在之前的版本中,我们是用BeanFactoryPostProcessor来实现bean的动态创建的,但是spring 5 原生就支持了动态创建bean。
从spring 5.x 开始,官方在GenericApplicationContext提供了registerBean方法。这里我们可以看到,其原理还是用BeanDefinition来实现的。
public <T> void registerBean(@Nullable String beanName, Class<T> beanClass,
@Nullable Supplier<T> supplier, BeanDefinitionCustomizer... customizers) {
ClassDerivedBeanDefinition beanDefinition = new ClassDerivedBeanDefinition(beanClass);
if (supplier != null) {
beanDefinition.setInstanceSupplier(supplier);
}
for (BeanDefinitionCustomizer customizer : customizers) {
customizer.customize(beanDefinition);
}
String nameToUse = (beanName != null ? beanName : beanClass.getName());
registerBeanDefinition(nameToUse, beanDefinition);
}
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}
我们试试效果
写一个class
public class PersonService {
public void say(){
System.out.println("this is a person");
}
}
使用CommandLineRunner在容器启动后创建
@Component
public class BeanRegisterRunner implements CommandLineRunner {
@Autowired
private GenericApplicationContext genericApplicationContext;
@Override
public void run(String... args) throws Exception {
genericApplicationContext.registerBean(PersonService.class, PersonService::new);
}
}
调用
@RestController
@RequestMapping(value = "user")
public class UserController {
@Autowired
@Lazy //由于是在容器启动后创建,所以这里需要加个@Lazy
private PersonService personService;
@GetMapping(value = "person-say")
public void personSay(){
personService.say();
}
}
请求这个接口,控制台成功打印。所以,达到预期。
基于BeanFactoryPostProcessor动态创建Bean
https://www.ithere.net/article/1422088308742520834