BeanFactoryPostProcessor
BeanDefinitionRegistryPostProcessor
ImportBeanDefinitionRegistrar
有的时候,我们需要在spring运行的时候,根据需要 动态添加之前没有定义的spring的bean,比如mybatis扫描某个包下的接口,转化为Mapper Bean。
Bean的定义在Spring中的组件名叫:BeanDefinition。
当我们创建了一个BeanDefinion后可以通过BeanDefinitionRegistry接口(ApplicationContext会实现此接口)将新的BeanDefinition注册到spring上下文中。
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
BeanFactoryPostProcessor(Bean工厂的后置处理器)
这个接口的作用是在Spring上下文的注册Bean定义的逻辑都跑完后,但是所有的Bean都还没真正实例化之前调用。
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
这个方法的主要用途就是通过注入进来的BeanFactory,在真正初始化Bean之前,再对spring上下文做一些动态修改。增加或者修改某些Bean定义的值,甚至再动态创建一些BeanDefinition都可以。
Demo:
@Override
public void postProcessBeanFactory(final ConfigurableListableBeanFactory beanFactory) throws BeansException {
GenericBeanDefinition beanDefinition = getGenericBeanDefinition();
((DefaultListableBeanFactory) beanFactory)
.registerBeanDefinition("dynamicUser", beanDefinition);
}
private GenericBeanDefinition getGenericBeanDefinition() {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(User.class);
beanDefinition.getPropertyValues().add(“name”, “张三”);
return beanDefinition;
}
BeanDefinitionRegistryPostProcessor(Bean注册器的后置处理器)
如上我们可以定义一个有关User这个Bean的定义,并且预先设置此Bean的Name属性值是
“张三”,最后注册到beanFactory中。
有鉴于此,Spring特意提供了一个更具体的子接口BeanDefinitionRegistryPostProcessor
这个子接口的方法postProcessBeanDefinitionRegistry会被Spring先于postProcessBeanFactory这个方法执行。不过呢,其实这2个方法都是注入的spring的上下文,只不过声明类型不同罢了。所以可以做的事一模一样。
private GenericBeanDefinition getGenericBeanDefinition() {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(User.class);
beanDefinition.getPropertyValues().add(“name”, “张三”);
return beanDefinition;
}
@Override
public void postProcessBeanDefinitionRegistry(final BeanDefinitionRegistry registry) throws BeansException {
GenericBeanDefinition beanDefinition = getGenericBeanDefinition();
registry.registerBeanDefinition(“dynamicUser2”,beanDefinition);
}
最后调用此spring上下文得到这个2个Bean:
public static void main(String[] args)
{
ConfigurableApplicationContext ctx = SpringApplication.run(DemoApplication.class, args);
User dynamicUser = ctx.getBean(“dynamicUser”, User.class);
System.out.println(dynamicUser);
User dynamicUser2 = ctx.getBean(“dynamicUser2”, User.class);
System.out.println(dynamicUser2);
}
BeanDefinitionBuilder
建造者模式去创建一个BeanDefinition。从2.5之后GenericBeanDefinition代替了原本的RootBeanDefinition和ChildBeanDefinition。我们通常使用GenericBeanDefinition就足够了。
我们通过Builder模式去设置BeanDefinition一些常用方法:
//设置Bean的构造函数传入的参数值
public BeanDefinitionBuilder addConstructorArgValue(Object value)
//设置构造函数引用其他的bean
public BeanDefinitionBuilder addConstructorArgReference(String beanName)
//设置这个bean的 init方法和destory方法
public BeanDefinitionBuilder setInitMethodName(String methodName)
public BeanDefinitionBuilder setDestroyMethodName(String methodName)
//设置单例/多例
public BeanDefinitionBuilder setScope(String scope)
//设置是否是个抽象的BeanDefinition,如果为true,表明这个BeanDefinition只是用来给子BeanDefinition去继承的,Spring不会去尝试初始化这个Bean。
public BeanDefinitionBuilder setAbstract(boolean flag)
//是否懒加载,默认是false
public BeanDefinitionBuilder setLazyInit(boolean lazy)
//自动注入依赖的模式,默认不注入
public BeanDefinitionBuilder setAutowireMode(int autowireMode)
//检测依赖。
public BeanDefinitionBuilder setDependencyCheck(int dependencyCheck)
以上,参考资料:http://www.logicbig.com/tutorials/spring-framework/spring-core/bean-definition/
ImportBeanDefinitionRegistrar
这个接口的实现类的作用是当这个接口的实现类被@Import接口引入某个被标记了@Configuration的注册类时,可以得到这个类的所有注解,然后做一些动态注册Bean的事儿。
比如在使用spring cloud feign组件的时候,我们这些写的
@SpringBootApplication
@EnableFeignClients(basePackages = “newbie.yyf.service.api.api”)
public class Application {
观察EnableFeignClients这个注解里面是不是就使用了
“@Import(FeignClientsRegistrar.class)”
而FeignClientsRegistrar就实现了ImportBeanDefinitionRegistrar接口,所以这个接口的实现:
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
registerDefaultConfiguration(metadata, registry);
registerFeignClients(metadata, registry);
}
这里面的AnnotationMetadata到底会包含什么呢?其实就是被Import标记的Application这个注册文件的所有注解。
我们可以通过拿到注解上的一些配置信息去动态生成BeanDefinition,如果你熟悉Feign的作用的话,你可以想到主要是Feign的客户端接口的Mock Bean,就像mybatis一样。
image.png
【Spring动态生成Bean的定义-BeanDefinition源码解析(转)】作者:lazyguy
链接:https://www.jianshu.com/p/899bd8089352
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
推荐阅读
- =======j2ee|spring用注解实现注入的@resource,@autowired,@inject区别
- jar|springboot项目打成jar包和war包,并部署(快速打包部署)
- 数据库|效率最高的Excel数据导入---(c#调用SSIS Package将数据库数据导入到Excel文件中【附源代码下载】)...
- java人生|35K 入职华为Java开发那天,我哭了(这 5 个月做的一切都值了)
- Java毕业设计项目实战篇|Java项目:在线嘿嘿网盘系统设计和实现(java+Springboot+ssm+mysql+maven)
- 微服务|微服务系列:服务发现与注册-----Eureka(面试突击!你想了解的Eureka都在这里.持续更新中......)
- java|ApplicationListener和SpringApplicationRunListener的联系
- Spring|SpringSecurity--自定义登录页面、注销登录配置
- 性能|性能工具之 Jmeter 通过 SpringBoot 工程启动
- 代码狂魔|Spring源码分析之IOC容器初始化流程