3 动态注册 Bean

Wu Jun 2018-12-18 21:53:15
06 Spring > 02 IoC

1 注册接口

有两种接口可动态注册 bean

  1. BeanDefinitionRegistry
    注册 Bean 定义,使用BeanDefinitionRegistry 接口 registerBeanDefinition() 方法,根据BeanDefinition实例化 bean 实例
  2. SingletonBeanRegistry
    注册 bean 实例,使用SingletonBeanRegistry 接口registerSingleton() 方法,注册单例 bean。

DefaultListableBeanFactory 接口同时实现了这两个接口

2 普通注册

如果是在普通 Bean 中注册,那么该 bean 则无法被BeanPostProcessor处理,没有 AOP 的支持。

public class PersonManagerRegisterController {

    @Autowired
    GenericApplicationContext applicationContext;

    @Autowired
    ConfigurableBeanFactory beanFactory;

    public void registerPersonManager() {
        PersonDao personDao = applicationContext.getBean(PersonDao.class);
        PersonManager personManager = new PersonManager();
        personManager.setPersonDao(personDao);
        beanFactory.registerSingleton("personManager", personManager);
    }
}

3 BeanFactoryPostProcessor 注册

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

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

        //注册 Bean 定义
        BeanDefinitionBuilder beanDefinitionBuilder =
                BeanDefinitionBuilder.genericBeanDefinition(PersonManager.class);
        beanDefinitionBuilder.addPropertyReference("personDao", "personDao");
        BeanDefinition personManagerBeanDefinition = beanDefinitionBuilder.getRawBeanDefinition();
        defaultListableBeanFactory.registerBeanDefinition("personManager1", personManagerBeanDefinition);

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

4 Spring 官方实现

4.1 ImportBeanDefinitionRegistrar

Spring 官方在动态注册 bean 时,大多使用 ImportBeanDefinitionRegistrar 接口。

所有实现了该接口的类的都会被 ConfigurationClassPostProcessor 处理,ConfigurationClassPostProcessor 实现了 BeanFactoryPostProcessor 接口,所以 ImportBeanDefinitionRegistrar 中动态注册的 bean 是优先与依赖其的 bean 初始化的,也能被 aop、validator 等机制处理。

4.2 BeanDefinitionRegistryPostProcessor

Spring 官方另一个大量使用的动态注册接口是 BeanDefinitionRegistryPostProcessor,这个接口扩展自 BeanFactoryPostProcessor,专门用于动态注册 Bean。

@Component
public class PersonBeanDefinitionRegistryPostProcessor
		implements BeanDefinitionRegistryPostProcessor {

    // 注册 Bean 定义
	@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
			throws BeansException {
		// 构造 bean 定义
		BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
				.genericBeanDefinition(PersonManager.class);
		//设置依赖
		beanDefinitionBuilder.addPropertyReference("personDao", "personDao");
		BeanDefinition personManagerBeanDefinition = beanDefinitionBuilder
				.getRawBeanDefinition();
		//注册bean定义
		registry.registerBeanDefinition("personManager1", personManagerBeanDefinition);
	}
	
	// 注册 Bean 实例
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
			throws BeansException {
			
		BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
				.genericBeanDefinition(PersonManager.class, () -> {
					PersonDao personDao = beanFactory.getBean(PersonDao.class);
					PersonManager personManager = new PersonManager();
					personManager.setPersonDao(personDao);
					return personManager;
				});
		BeanDefinition personManagerBeanDefinition = beanDefinitionBuilder
				.getRawBeanDefinition();
		((DefaultListableBeanFactory) beanFactory)
				.registerBeanDefinition("personManager2", personManagerBeanDefinition);
	}
}