spring 程序执行时动态注册 bean 到 context

定义一个没有被 Spring 管理的 Controller

 
  1. public class UserController implements InitializingBean{
  2.  
  3. private UserService userService;
  4.  
  5. public UserService getUserService() {
  6. return userService;
  7. }
  8.  
  9. public void setUserService(UserService userService) {
  10. this.userService = userService;
  11. }
  12.  
  13. @Override
  14. public void afterPropertiesSet() throws Exception {
  15. System.out.println("我是动态注册的你,不是容器启动的时候注册的你");
  16. }
  17.  
  18. public String toAction(String content){
  19. return "-->" + userService.doService(content);
  20. }
  21.  
  22. }
 

需要注意的是,如果要注入 UserService, 需要提供它的 getter 和 setter 方法

现在启动 springboot 工程,显而易见这个类是不会被 Spring 管理的,接下来我们定义一个获取 Spring 上下文的工具类,如下

工具类

 
  1. public class SpringContextUtil {
  2. private static ApplicationContext applicationContext;
  3. //获取上下文
  4. public static ApplicationContext getApplicationContext() {
  5. return applicationContext;
  6. }
  7. //设置上下文
  8. public static void setApplicationContext(ApplicationContext applicationContext) {
  9. SpringContextUtil.applicationContext = applicationContext;
  10. }
  11. //通过名字获取上下文中的bean
  12. public static Object getBean(String name){
  13. return applicationContext.getBean(name);
  14. }
  15. //通过类型获取上下文中的bean
  16. public static Object getBean(Class<?> requiredType){
  17. return applicationContext.getBean(requiredType);
  18. }
  19. }
 

我们在 Springboot 的启动类中,保存当前 Spring 上下文,代码如下:

 
  1. @SpringBootApplication
  2. public class HelloApplication {
  3.  
  4. public static void main(String[] args) {
  5. ApplicationContext app = SpringApplication.run(HelloApplication.class, args);
  6. SpringContextUtil.setApplicationContext(app);
  7. }
  8.  
  9. }
 

然后我们在另一个被 Spring 管理的容器中,写如下方法,进行 bean 的动态注册

 
  1. @GetMapping("/bean")
  2. public String registerBean() {
  3. //将applicationContext转换为ConfigurableApplicationContext
  4. ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) SpringContextUtil.getApplicationContext();
  5.  
  6. // 获取bean工厂并转换为DefaultListableBeanFactory
  7. DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableApplicationContext.getBeanFactory();
  8.  
  9. // 通过BeanDefinitionBuilder创建bean定义
  10. BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserController.class);
  11.  
  12. // 设置属性userService,此属性引用已经定义的bean:userService,这里userService已经被spring容器管理了.
  13. beanDefinitionBuilder.addPropertyReference("userService", "userService");
  14.  
  15. // 注册bean
  16. defaultListableBeanFactory.registerBeanDefinition("userController", beanDefinitionBuilder.getRawBeanDefinition());
  17.  
  18.  
  19. UserController userController = (UserController) SpringContextUtil.getBean("userController");
  20.  
  21. return userController.toAction("动态注册生成调用");
  22.  
  23. //删除bean.
  24. //defaultListableBeanFactory.removeBeanDefinition("testService");
  25.  
  26. }
 

如上,就能动态的注册 bean。

注意:

  假如动态 bean 中属性不是引用 context 中的,需要通过参数传入。

例如:

 
  1. public class UserService{
  2.  
  3. private InterfaceGroup group;
  4.  
  5. public InterfaceGroup getGroup() {
  6. return group;
  7. }
  8.  
  9. public void setGroup(InterfaceGroup group) {
  10. this.group = group;
  11. }
  12.  
  13. }
 
 
  1. InterfaceGroup group =new InterfaceGroup();
  2. //设置属性....
  3. group.setXXX()
  4. //传入参数给动态bean引用
  5. registerBean(group)
 
 
  1. /**
  2. * 动态注册bean
  3. *
  4. * @param group 自定义类型
  5. * @return
  6. */
  7. public void registerBean(InterfaceGroup group) {
  8. //将applicationContext转换为ConfigurableApplicationContext
  9. ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) SpringContextUtil.getApplicationContext();
  10.  
  11. // 获取bean工厂并转换为DefaultListableBeanFactory
  12. DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableApplicationContext.getBeanFactory();
  13.  
  14. // 通过BeanDefinitionBuilder创建bean定义
  15. BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserService.class);
  16.  
  17. // 设置属性
  18. beanDefinitionBuilder.addPropertyValue("group", group);
  19.  
  20. // 注册bean
  21. defaultListableBeanFactory.registerBeanDefinition("userService", beanDefinitionBuilder.getRawBeanDefinition());
  22. //通过工具类获取动态注册的bean
  23. LOG.info((SpringContextUtil.getBean("userService")).toString());
 

在 spring 运行时,动态的添加 bean,dapeng 框架在解析 xml 的 soa:service 字段时,使用到了动态注册,注册了一个实现了 FactoryBean 类!


定义一个没有被 Spring 管理的 Controller
public class UserController implements InitializingBean{

    private UserService userService;

    public UserService getUserService() {
        return userService;
    }

    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("我是动态注册的你,不是容器启动的时候注册的你");
    }

    public String toAction(String content){
        return "-->" +  userService.doService(content);
    }

}
需要注意的是,如果要注入 UserService, 需要提供它的 getter 和 setter 方法
现在启动 springboot 工程,显而易见这个类是不会被 Spring 管理的,接下来我们定义一个获取 Spring 上下文的工具类,如下
工具类
public class SpringContextUtil {
    private static ApplicationContext applicationContext;
    //获取上下文
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }
    //设置上下文
    public static void setApplicationContext(ApplicationContext applicationContext) {
        SpringContextUtil.applicationContext = applicationContext;
    }
    //通过名字获取上下文中的bean
    public static Object getBean(String name){
        return applicationContext.getBean(name);
    }
    //通过类型获取上下文中的bean
    public static Object getBean(Class<?> requiredType){
        return applicationContext.getBean(requiredType);
    }
}
我们在 Springboot 的启动类中,保存当前 Spring 上下文,代码如下:
@SpringBootApplication
public class HelloApplication {

	public static void main(String[] args) {
		ApplicationContext app = SpringApplication.run(HelloApplication.class, args);
		SpringContextUtil.setApplicationContext(app);
	}
	
}
然后我们在另一个被 Spring 管理的容器中,写如下方法,进行 bean 的动态注册
@GetMapping("/bean")
public String registerBean() {
    //将applicationContext转换为ConfigurableApplicationContext
    ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) SpringContextUtil.getApplicationContext();

    // 获取bean工厂并转换为DefaultListableBeanFactory
    DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableApplicationContext.getBeanFactory();

    // 通过BeanDefinitionBuilder创建bean定义
    BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserController.class);
        
    // 设置属性userService,此属性引用已经定义的bean:userService,这里userService已经被spring容器管理了.
    beanDefinitionBuilder.addPropertyReference("userService", "userService");

    // 注册bean
    defaultListableBeanFactory.registerBeanDefinition("userController", beanDefinitionBuilder.getRawBeanDefinition());


    UserController userController = (UserController) SpringContextUtil.getBean("userController");

    return userController.toAction("动态注册生成调用");

     //删除bean.
    //defaultListableBeanFactory.removeBeanDefinition("testService");

}
    
如上,就能动态的注册 bean

 

posted @ 2024-06-26 14:48  CharyGao  阅读(8)  评论(0编辑  收藏  举报