栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

重写第三方jar中SPRING BEAN的方式

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

重写第三方jar中SPRING BEAN的方式

1、直接在自己工程中建同包同类名的类进行替换

方式简单粗暴,可以直接覆盖掉jar包中的类,spring项目会优先加载自定义的类。

1.1 替换实现

下面是覆盖 third-bean.jar中的一个类 MyConfig,主要是想修改它里面的getProjectName方法的业务逻辑。

package com.ybw.config;

import org.springframework.context.annotation.Configuration;


@Configuration
public class MyConfig {
    
    public String getProjectName() {
        return "third-bean";
    }
}

包路径为 com.ybw.config, 直接工程里面新建一样路径一样类名MyConfig即可。

package com.ybw.config;


public class MyConfig {
    
    public String getProjectName() {
        return "current-bean";
    }
}
1.2 接口访问

package com.ybw.controller;

import com.ybw.config.MyConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;


@RestController
@Slf4j
public class TestController {
    @Resource
    private MyConfig myConfig;

    @GetMapping("/getProjectName")
    public String getProjectName() {
        return myConfig.getProjectName();
    }
}

访问地址:http://localhost:8080/getProjectName

访问结果如下,替换成功。

2、 排除需要替换的JAR包中的类

使用 @ComponentScan 里面的 excludeFilters 功能排除调用要替换的类,然后自己写个类继承替换的类即可。
下面的例子是替换掉 jar包中的MyServiceImpl类

package com.ybw;

import com.ybw.service.impl.MyServiceImpl;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;

@SpringBootApplication
@ComponentScan(excludeFilters = {@ComponentScan.Filter(type =
        FilterType.ASSIGNABLE_TYPE, classes = {MyServiceImpl.class})})
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}
package com.ybw.service.impl;

import com.ybw.service.MyService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class MyTestServiceImpl implements MyService {

    @Override
    public String getProjectName() {
        return "current-bean";
    }
}
3、@BEAN 覆盖

该场景针对,框架jar包中有@ConditionalOnMissingBean注解,这种注解是说明如果你也创建了一个一样的Bean则框架就不自己再次创建这个bean了,这样你可以覆写自己的bean。

package com.ybw.config;

import com.ybw.dto.UserDTO;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyBeanConfig {

    @Bean
    @ConditionalOnMissingBean
    public UserDTO userDTO(){
        return new UserDTO(1L,"张三");
    }
}

直接继承要覆盖的类,自己重写里面方法,使用@Component注入到spring中去

package com.ybw.dto;

import com.alibaba.fastjson2.JSON;
import lombok.Data;
import org.springframework.stereotype.Component;


@Component
@Data
public class MyUserDTO extends UserDTO {

    private Long no;

    @Override
    public String toJson() {
        super.id = 2L;
        super.name = "李四";
        this.no = 50L;
        return JSON.toJSONString(this);
    }
}
spring注解扩展
  • @ConditionalOnBean // 当给定的在bean存在时,则实例化当前Bean
  • @ConditionalOnMissingBean // 当给定的在bean不存在时,则实例化当前Bean
  • @ConditionalOnClass // 当给定的类名在类路径上存在,则实例化当前Bean
  • @ConditionalOnMissingClass // 当给定的类名在类路径上不存在,则实例化当前Bean
4、使用BEANDEFINITIONREGISTRYPOSTPROCESSOR

BeanDefinitionRegistryPostProcessor 说白了就是可以在初始化Bean之前修改Bean的属性,甚至替换原先准备要实例化的bean。

4.1 示例

假设jar包中有一个类 AppleProductServiceImpl,正常情况下它会被spring自动扫描到注入IOC容器中去。

package com.ybw.service.impl;

import com.ybw.service.ProductService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;


@Service("productService")
@Slf4j
public class AppleProductServiceImpl implements ProductService {
    @Override
    public void addProduct() {
        log.info("添加苹果");
    }
}

自己工程中实现ProductService,并且覆写里面的addProduct中的方法,注意不需要@Service

package com.ybw.service.impl;

import com.ybw.service.ProductService;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.PostConstruct;

@Slf4j
public class BananaProductServiceImpl implements ProductService {

    @PostConstruct
    public void init() {
        log.info("我替换了默认实现");
    }

    @Override
    public void addProduct() {
        log.info("添加香蕉");
    }
}

然后 实现 BeanDefinitionRegistryPostProcessor 接口,修改原来bean定义,主要查看postProcessBeanDefinitionRegistry方法的实现,先清空原bean定义,注册我们自己的bean定义来达到替换的目的。

package com.ybw.config;

import com.alibaba.fastjson2.JSON;
import com.ybw.service.impl.BananaProductServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.stereotype.Component;


@Component
@Slf4j
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        // 注册Bean定义,容器根据定义返回bean
        log.info("所有bean:{}", JSON.toJSONString(beanDefinitionRegistry.getBeanDefinitionNames()));
        //要被替换的bean
        String beanName = "productService";
        if (beanDefinitionRegistry.containsBeanDefinition(beanName)) {
            // 先移除原来的bean定义
            beanDefinitionRegistry.removeBeanDefinition(beanName);

            // 注册我们自己的bean定义
            BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(BananaProductServiceImpl.class);
//        // 如果有构造函数参数, 有几个构造函数的参数就设置几个  没有就不用设置
//        beanDefinitionBuilder.addConstructorArgValue("构造参数1");
//        beanDefinitionBuilder.addConstructorArgValue("构造参数2");
//        beanDefinitionBuilder.addConstructorArgValue("构造参数3");
//        // 设置 init方法 没有就不用设置
//        beanDefinitionBuilder.setInitMethodName("init");
//        // 设置 destory方法 没有就不用设置
//        beanDefinitionBuilder.setDestroyMethodName("destory");
            // 将Bean 的定义注册到Spring环境
            beanDefinitionRegistry.registerBeanDefinition("myTestRegistryConfig", beanDefinitionBuilder.getBeanDefinition());
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        // bean的名字为key, bean的实例为value
//        Map beanMap = configurableListableBeanFactory.getBeansWithAnnotation(RestController.class);
//        log.info("所有 RestController 的bean {}", beanMap);
    }
}

测试接口

@Resource
private ProductService productService;


@GetMapping("/addProduct")
public String addProduct() {
    productService.addProduct();
    return "OK";
}

访问接口返回值

[INFO ] 2022-06-17 15:20:46.280 [http-nio-8080-exec-4] c.y.s.impl.BananaProductServiceImpl - 添加香蕉
5、示例代码

https://gitee.com/xixingzhe2/share/tree/master/spring/spring-replace-bean/spring-replace-bean

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/978671.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号