Spring动态注册bean

https://zhuanlan.zhihu.com/p/30070328

为什么需要动态注册bean

大部分时候,静态的配置信息即可满足系统需求。但是某些场景下,我们需要根据静态配置中的信息动态生成bean,此时就需要动态注册bean的功能。

动态注册bean的api

Spring中的bean定义都保存在 **BeanDefinitionRegistry** 接口中,单例的bean的实例都保存在 **SingletonBeanRegistry** 接口中。

因此动态注册bean也分为了两种方式:

 

1. 使用BeanDefinitionRegistry接口的void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException 方法

2. 使用SingletonBeanRegistry接口的void registerSingleton(String beanName, Object singletonObject) 方法

 

两者区别在于使用前者时,Spring容器会根据BeanDefinition实例化bean实例,而使用后者时,bean实例就是传递给registerSingleton方法的对象。

 

DefaultListableBeanFactory接口同时实现了这两个接口,在实践中通常会使用这个接口。

 

在普通bean中进行动态注册

可以在任何获得了BeanDefinitionRegistry或者SingletonBeanRegistry实例的地方进行动态注册。

但是如果bean不是在BeanFactoryPostProcessor中被注册,那么该bean则无法被**BeanPostProcessor**处理,即无法对其应用aop、Bean Validation等功能。

 

在**BeanFactoryPostProcessor**中进行动态注册

在Spring容器的启动过程中,BeanFactory载入bean的定义后会立刻执行BeanFactoryPostProcessor,此时动态注册bean,则可以保证动态注册的bean被BeanPostProcessor处理,并且可以保证其的实例化和初始化总是先于依赖它的bean。

 

例子

在BeanFactoryPostProcessor注册

@Component
@Slf4j
public class PersonBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        DefaultListableBeanFactory defaultListableBeanFactory
                = (DefaultListableBeanFactory) beanFactory;

        //注册Bean定义,容器根据定义返回bean
        log.info("register personManager1>>>>>>>>>>>>>>>>");
        BeanDefinitionBuilder beanDefinitionBuilder =
                BeanDefinitionBuilder.genericBeanDefinition(PersonManager.class);
        beanDefinitionBuilder.addPropertyReference("personDao", "personDao");
        BeanDefinition personManagerBeanDefinition = beanDefinitionBuilder.getRawBeanDefinition();
        defaultListableBeanFactory.registerBeanDefinition("personManager1", personManagerBeanDefinition);

        //注册bean实例
        log.info("register personManager2>>>>>>>>>>>>>>>>");
        PersonDao personDao = beanFactory.getBean(PersonDao.class);
        PersonManager personManager = new PersonManager();
        personManager.setPersonDao(personDao);
        beanFactory.registerSingleton("personManager2", personManager);

    }
}

 

我的例子:

自定义注解ZcyType.class ,在util 类上添加此注解,系统启动自动加载注解此注解的类,注册到bean中。

在if else 中,使用此方法替换掉if else

注解类:
@Target(ElementType.TYPE)// 注解会在class字节码文件中存在,在运行时可以通过反射获取到
@Retention(RetentionPolicy.RUNTIME)//定义注解的作用目标**作用范围字段、枚举的常量/方法
@Documented//说明该注解将被包含在javadoc中
public @interface ZcyType {
    String value() ;
}


处理类:
@Data
@ZcyType("xUtil")
public class XUtil implements IUtil{

    private ITService itService;

    @Override
    public void test(){
        System.out.println("22222222222");
        itService.getT();
    }
}

处理类:
@Data
@ZcyType("zUtil")
public class ZUtil implements IUtil{

    private ITService itService;
    @Override
    public void test(){
        System.out.println("233333");
        itService.getT();
    }
}


启动加载类,把ZcyType注解的类 注册
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        DefaultListableBeanFactory defaultListableBeanFactory
                = (DefaultListableBeanFactory) configurableListableBeanFactory;
        System.out.println("1111111111111111");
        Reflections reflections = new Reflections("com.zte.daas.datamange");
        Set<Class<?>> classesList = reflections.getTypesAnnotatedWith(ZcyType.class);
        for(Class c : classesList){

                ZcyType zcyType = (ZcyType) c.getAnnotation(ZcyType.class);
                BeanDefinitionBuilder beanDefinitionBuilder =
                        BeanDefinitionBuilder.genericBeanDefinition(c);
                beanDefinitionBuilder.addPropertyReference("itService", "tService");
                BeanDefinition personManagerBeanDefinition = beanDefinitionBuilder.getRawBeanDefinition();
                defaultListableBeanFactory.registerBeanDefinition(zcyType.value(), personManagerBeanDefinition);

                //configurableListableBeanFactory.registerSingleton(zcyType.value(),c.newInstance());  
// 实例的可以使用方法,就是 private ITService itService; 去掉的情况

        }
    }
}


使用:
@ApiOperation("test")
    @GetMapping("get")
    public void getInfo() throws Exception {
        Reflections reflections = new Reflections("com.zte.daas.datamange");
        Set<Class<?>> classesList = reflections.getTypesAnnotatedWith(ZcyType.class);
        for (Class classes : classesList) {
            IUtil iUtil = (IUtil)SpringUtil.getBean(classes);
            iUtil.test();
        }

    }

https://juejin.im/post/5ce79feef265da1b725bdca1

2. 策略模式

2.1 策略模式实现的Service

@Service
public class CancelOrderStrategyService {

    @Autowired
    private StrategyContext context;

    public void process(OrderDTO orderDTO) {
        OrderTypeEnum orderTypeEnum = OrderTypeEnum.getByCode(orderDTO.getServiceType());
        AbstractStrategy strategy = context.getStrategy(orderTypeEnum);
        strategy.process(orderDTO);
    }
}
复制代码

简洁的有点过分了是不是!!!

2.2 各种类型策略实现及抽象策略类

下面选取了即时订单和预约订单的策略.

@Service
@OrderTypeAnnotation(orderType = OrderTypeEnum.INSTANT)
public class InstantOrderStrategy extends AbstractStrategy {
    @Override
    public void process(OrderDTO orderDTO) {
        System.out.println("取消即时订单");
    }
}
复制代码
@Service
@OrderTypeAnnotation(orderType = OrderTypeEnum.BOOKING)
public class BookingOrderStrategy extends AbstractStrategy {
    @Override
    public void process(OrderDTO orderDTO) {
        System.out.println("取消预约订单");
    }
}
复制代码
public abstract class AbstractStrategy {
    abstract public void process(OrderDTO orderDTO);
}
复制代码

2.3 策略类型注解

每个策略中增加了注解OrderTypeAnnotation,以标注适用于不同类型的策略内容.

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface OrderTypeAnnotation {
    OrderTypeEnum orderType();
}
复制代码

2.4 策略处理器类StrategyProcessor和策略上下文StrategyContext

其中最为核心的为StrategyProcessor 策略处理器类和StrategyContext 策略上下文,

@Component
public class StrategyProcessor implements BeanFactoryPostProcessor {

    private static final String STRATEGY_PACKAGE = "com.lujiahao.strategy";

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        Map<OrderTypeEnum, Class> handlerMap = Maps.newHashMapWithExpectedSize(3);
        ClassScanner.scan(STRATEGY_PACKAGE, OrderTypeAnnotation.class).forEach(clazz -> {
            OrderTypeEnum type = clazz.getAnnotation(OrderTypeAnnotation.class).orderType();
            handlerMap.put(type, clazz);
        });

        StrategyContext context = new StrategyContext(handlerMap);
        configurableListableBeanFactory.registerSingleton(StrategyContext.class.getName(), context);
    }
}
复制代码
public class StrategyContext {
    private Map<OrderTypeEnum, Class> strategyMap;

    public StrategyContext(Map<OrderTypeEnum, Class> strategyMap) {
        this.strategyMap = strategyMap;
    }

    public AbstractStrategy getStrategy(OrderTypeEnum orderTypeEnum) {
        if (orderTypeEnum == null) {
            throw new IllegalArgumentException("not fond enum");
        }

        if (CollectionUtils.isEmpty(strategyMap)) {
            throw new IllegalArgumentException("strategy map is empty,please check you strategy package path");
        }

        Class clazz = strategyMap.get(orderTypeEnum);
        if (clazz == null) {
            throw new IllegalArgumentException("not fond strategy for type:" + orderTypeEnum.getCode());
        }

        return (AbstractStrategy) SpringBeanUtils.getBean(clazz);
    }
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值