开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第17天,点击查看活动详情
前言
在Spring的使用当中,为了创建Bean对象,我们可以通过xml、@Bean、@Service等方式,但是有一种可以动态创建Bean对象的方式你知道嘛?那就是通过BeanDefinitionRegistryPostProcessor来动态创建BeanDefinition,通过BeanDefinition的注入从而达到Bean创建的动态化;
示例
下面我们通过一个简单的示例来看一下如何使用BeanDefinitionRegistryPostProcessor来动态创建Bean对象;
我们先创建出一个User类,这就是我们需要创建的Bean对象:
@Data
public class User {
private String name;
private int age;
}
下面我们来自定义一个BeanDefinitionRegistryPostProcessor子类:
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.stereotype.Component;
/**
* @author zouwei
* @className CustomBeanDefinitionRegistryPostProcessor
* @date: 2022/12/14 11:54
* @description:
*/
@Component
public class CustomBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// 给User类创建一个BeanDefinition
BeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClassName(User.class.getName());
// 设置属性值
beanDefinition.getPropertyValues().addPropertyValue("name", "zouwei");
beanDefinition.getPropertyValues().addPropertyValue("age", 30);
// 注册BeanDefinition
registry.registerBeanDefinition("user", beanDefinition);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
}
}
我们通过实现BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry()方法,可以自己构建BeanDefinition让spring把User以Bean的形式管理起来;下面来测试看一下:
@Autowired
private User user;
@GetMapping("/getUser")
public User getUser() {
return user;
}
通过在Controller写一个测试接口,我们在前端拿到的数据如下:
{
code: 200,
data: {
name: "zouwei",
age: 30
},
message: "",
error: "",
metaInfo: null
}
我们可以看到,即使没有通过注解的方式,我们也可以通过自定义BeanDefinitionRegistryPostProcessor把User注入进来;
应用
另外,在mybatis中就很好地运用了BeanDefinitionRegistryPostProcessor的特性实现了动态扫描Mapper地功能,比如MapperScannerConfigurer它就通过实现BeanDefinitionRegistryPostProcessor接口来完成了MapperScan的功能:
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
if (this.processPropertyPlaceHolders) {
this.processPropertyPlaceHolders();
}
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
scanner.setAddToConfig(this.addToConfig);
scanner.setAnnotationClass(this.annotationClass);
scanner.setMarkerInterface(this.markerInterface);
scanner.setSqlSessionFactory(this.sqlSessionFactory);
scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
scanner.setResourceLoader(this.applicationContext);
scanner.setBeanNameGenerator(this.nameGenerator);
scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
if (StringUtils.hasText(this.lazyInitialization)) {
scanner.setLazyInitialization(Boolean.valueOf(this.lazyInitialization));
}
if (StringUtils.hasText(this.defaultScope)) {
scanner.setDefaultScope(this.defaultScope);
}
scanner.registerFilters();
scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ",; \t\n"));
}
}
最终是通过scan()方法把basePackage里面的Mapper类全部注册到BeanDefinitionRegistry中,并最终实现了Mapper的代理和实例化。