Spring动态注册bean
为什么需要动态注册bean
大部分时候,静态的配置信息即可满足系统需求。但是某些场景下,我们需要根据静态配置中的信息动态生成bean,此时就需要动态注册bean的功能。
如: 用户定义一个如下的接口,而接口的实现则由框架生成,不需要用户自行编写,此时实现类就需要动态注册到容器中。
@Rest("http://localhost:8081/test")
public interface IRequestDemo {
@GET
ResultBean get1();
@GET("/get2")
ResultBean getWithKey(@Param("key") String key);
@GET("/get3")
ResultBean getWithMultKey(@Param("key1") String key,
@Param("key2") String key2);
}
@componet
public class test {
@Autowired
IRequestDemo demo;
public String test() {
String msg = "<h1>invoke remote rest result</h1>";
ResultBean get1 = demo.get1();
msg += "<br/>get1 result=" + get1;
ResultBean get2 = demo.getWithKey("key-------");
msg += "<br/>get2 result=" + get2;
ResultBean get3 = demo.getWithMultKey("key11111", "key22222");
msg += "<br/>get3 result=" + get3;
return msg;
}
}
动态注册bean的api
Spring中的bean定义都保存在 BeanDefinitionRegistry 接口中,单例的bean的实例都保存在 SingletonBeanRegistry 接口中。
因此动态注册bean也分为了两种方式:
- 使用BeanDefinitionRegistry接口的void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException 方法
- 使用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);
}
}
在普通bean中注册
@RestController
@Slf4j
public class PersonManagerRegisterController {
/**
* The Application context.
*/
@Autowired
GenericApplicationContext applicationContext;
/**
* The Bean factory.
*/
@Autowired
ConfigurableBeanFactory beanFactory;
/**
* 动态注册bean,此处注册的bean没有AOP的支持
* curl http://localhost:8080/registerPersonManager
*/
@GetMapping("/registerPersonManager")
public void registerPersonManager() {
PersonDao personDao = applicationContext.getBean(PersonDao.class);
PersonManager personManager = new PersonManager();
personManager.setPersonDao(personDao);
beanFactory.registerSingleton("personManager3", personManager);
}
}
完整代码:pkpk1234/dynamic-register-bean-demo
本文由 创作,采用 知识共享署名4.0 国际许可协议进行许可。本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名。最后编辑时间为: 2020/11/28 02:11