问题
Spring创建的Bean 和 我们提供的Class对象 有什么关系吗? 一定是我们提供的这个对象实例吗?
加载流程
BeanFactoryPostProcessor的执行时机
结合上图的流程,我们可以得出如下结论
- 在bean被转换成BeanDefinition之后
- 在实例化bean之前
中间这个部分,如果用户实现了BeanFactoryPostProcessor接口,则可以对BeanDefinition进行修改
Code
演示下这个功能
两个类 一个可以被Spring扫描到的bean Artisan1 , 另外一个是普通的对象 Artisan2
package com.artisan.bd; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; @Component public class Artisan1 { @PostConstruct public void init(){ System.out.println("Artisan1 Created"); } }
标注了 @Component
package com.artisan.bd; import javax.annotation.PostConstruct; public class Artisan2 { }
普通对象
配置类
package com.artisan.bd; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan("com.artisan.bd") public class AppConfig { }
测试类
package com.artisan.bd; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Test { public static void main(String[] args) { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class); System.out.println(ac.getBean(Artisan1.class)); System.out.println(ac.getBean(Artisan2.class)); } }
同时我们也看到了 Artisan1这个对象,对应的 BeanDefinition中的beanClass也是 Artisan1 .
那能改么? 能改成Artisan2吗?
看了刚才的流程图,我们知道如果实现了BeanFactoryPostProcessor接口,就可以修改BeanDefinition。
试试吧
package com.artisan.bd; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.stereotype.Component; @Component public class ArtisanBeanFactoryPostProcessor implements BeanFactoryPostProcessor { /** * beanFactory 就是流程图中的 bdmap BeanDefinition的map集合 * @param beanFactory the bean factory used by the application context * @throws BeansException */ @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { // 取出A对应的 beanDefinition -----> 这时候bd中存放的类是A.class GenericBeanDefinition beanDefinition = (GenericBeanDefinition) beanFactory.getBeanDefinition("artisan1"); //ScannedGenericBeanDefinition beanDefinition1 = (ScannedGenericBeanDefinition) beanFactory.getBeanDefinition("artisan1"); // 将bd中的beanclass修改为B beanDefinition.setBeanClass(Artisan2.class); } }
使用实现类来接收 beanFactory.getBeanDefinition(“artisan1”) 的返回值,可用方法更多,接口中的方法太少,并且也木有我们要用的setBeanClassName 方法。
别忘了加@Component,不然spring无法扫描到,这个就不会生效 。
再此执行刚才的代码
同时,通过name artisan1 获取到的bean 其实是被修改后了的, 因为Sping根据用户提供的Artisan2, 实例化了Artisan2
再比如说修改scope
都明白了哈, 后面从源码的角度分析 ~