spring源码分析五(bean的后置处理器)

上一节,我们分析了spring容器如何为我们生成我们需要的bean,并将生成的bean放入到beanFactory这个容器中,怎嘛放置的那,就是将bean的名称
作为key,beandefination作为value放入map集合中,这个时候,我们的bean已经准备就绪了,我们已经加载了所有bean到容器中,就相当于我们盖房子
已经封顶了,框架已经出来了,加下来该干嘛,进入我们今天的内容
预处理bean工厂

prepareBeanFactory(beanFactory);

AbstractApplicationContext

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // 设置beanFactory的类加载器,如果存在,就直接设置,如果不存在,创建一个默认的
        beanFactory.setBeanClassLoader(getClassLoader());
        //设置bean的表达式解析器,创建的目的是为了后面填充属性的时候使用
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
        //设置属性注解解析器
        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

        //将ApplicationContext对象交给ApplicationContextAwareProcessor类来处理,从而在Aware接口实现的类中注入applicationContext
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

        // 设置忽略自动装配的接口类
        beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
        beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
        beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
        beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

        //设置可以解析的自动装配
        beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
        beanFactory.registerResolvableDependency(ResourceLoader.class, this);
        beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
        beanFactory.registerResolvableDependency(ApplicationContext.class, this);

        // Register early post-processor for detecting inner beans as ApplicationListeners.
        beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

        //如果当前BeanFactory包含loadTimeWeaver这个Bean,说明存在类加载器织入AspectJ
        //则把当前BeanFactory交给类加载器BeanPostProcessor实现类LoadTimeWeaverAwareProcessor来处理,从而实现类加载器织入AspectJ的目的
        if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            // Set a temporary ClassLoader for type matching.
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }

        // 注册一些默认的环境属性配置
        if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
            beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
        }
        if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
            beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
        }
        if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
            beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
        }
    }

以上代码比较简单,主要步骤就是
1:设置类加载器
2:设置表达式解析器,为了填充属性使用
3:利用BeanPostProcessor给Aware接口的实现类注入ApplicationContext中对应的属性
4:设置每个Aware接口的实现类,忽略自动装配
5:设置自动装配的类(BeanFactory,ResourceLoader,ApplicationEventPublisher,ApplicationContext)
6:如果BeanFactory中存在loadTimeWeaver的bean,那么需要添加动态织入功能
7:注册各种可用组件(environment,systemProperties,systemEnvironment)

总结为一句话,就是准备bean容器,总之这个方法还是比较简单,我们接着往下看

postProcessBeanFactory(beanFactory);

我们会发现spring并没有实现这个方法,就是个空实现,也就是说提供给实现postProcessBeanFactory这个方法的第三方使用的,谁要使用
谁就去实现,他的主要作用就是在beanFactory准备工作完成后,做一些定制化处理,我们就不做深入的研究了.
今天的重点我们就来分析下下面这两个方法,乍一看,这两个方法有点相似啊,但是一定不要搞错了,他们两个不一样的,相同点是它们两个都是spring
在初始化的时候对外暴露的扩展点,我们一起看一下哈
1:#invokeBeanFactoryPostProcessors(beanFactory);
2:#registerBeanPostProcessors(beanFactory);

invokeBeanFactoryPostProcessors(beanFactory)

这个方法的字面意思,是说调用bean后置处理器,具体是干嘛的那,要使用它就要是实现BeanFactoryPostProcessor这个接口
我们看看这个接口官方的描述
允许自定义修改应用程序上下文的Bean定义,调整上下文的基础Bean工厂的Bean属性值。
应用程序上下文可以在它们的bean定义中自动检测BeanFactoryPostProcessor bean,并在创建任何其他bean之前应用它们。
对于面向系统管理员的自定义配置文件很有用,这些文件会覆盖在应用程序上下文中配置的Bean属性。
请参阅PropertyResourceConfigurer及其具体实现
以了解解决此类配置需求的现成解决方案。
BeanFactoryPostProcessor可以与bean定义进行交互并对其进行修改,但不能与bean实例进行交互。
这样做可能会导致bean *实例化过早,从而违反了容器并造成了意想不到的副作用。 *如果需要bean实例交互,请考虑实现BeanPostProcessor

官方注释已经解释的很清楚了,也就是说你可以修改bean的属性值,下面,我们修改下,看看是否可以
postProcessBeanFactory只有一个方法,让我们自定义一个类,实现这个接口,然后修改我们的属性值,

这里注意一下,我使用的xml配置,所以你要想成功,得把这个类注册到xml中,平常的话,我们都是使用注解的方式,添加service注解就可

demo

public class LocalFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("BeanFactoryPostProcessor被调用了....");
        String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();

        for (String beanDefinitionName : beanDefinitionNames) {
            if (beanDefinitionName.equals("helloSpring")){
                BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanDefinitionName);
                //获取属性值,并执行修改
                MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
                if (propertyValues.contains("name")){
                    propertyValues.addPropertyValue("name","王五");
                    System.out.println("属性值修改成功");
                }
            }
        }
    }
}

我们运行的结果不难发现,属性值已经被修改,会打印:你好,spring王五,这段代码比较简单,就不做具体分析了,毕竟不是重点哈

下一个,我们来分析下BeanPostProcessor.
大家想一个问题,如果我们在bean初始化之后,做一些自定义需求,我们需要怎嘛办,spring在bean的整个生命周期内,都会提供适当的钩子方法
为了我们方便去修改bean的属性或者加入我们自己的逻辑,处理这样的逻辑就需要用到BeanPostProcessor这个接口
这个接口提供了两个方法分别是

1:
@Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
2:
@Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

postProcessBeforeInitialization是在bean实例化、依赖注入及自定义初始化方法之后调用执行
postProcessAfterInitialization是在bean实例化、依赖注入及自定义初始化方法之后调用执行

看看官网的解释
ApplicationContext容器会自动检测Spring配置文件中那些bean所对应的Java类实现了BeanPostProcessor
接口,并自动把它们注册为后置处理器
BeanFactory容器注册bean后置处理器时必须通过代码显示的注册

下面通过一个简单的案例来学习下,或者大家也可以看spring的自己实现的用于校验bean的类BeanValidationPostProcessor
demo

public class LocalPosProcessor implements BeanPostProcessor {

    private static final Logger logger = LoggerFactory.getLogger(LocalPosProcessor.class);


    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        logger.info("后置处理器前置方法执行了....");
        if (bean instanceof HelloSpringImpl){
            HelloSpring bean1 = (HelloSpringImpl)bean;
            ((HelloSpringImpl) bean1).setName("哈哈");
            logger.info("获取到的bean是:"+bean1);
        }
        return bean;
    }


    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        logger.info("后置处理器后置方法执行了");
        if (bean instanceof HelloSpringImpl){
            HelloSpring bean1 = (HelloSpringImpl)bean;
            ((HelloSpringImpl) bean1).setName("嘿嘿");
            logger.info("获取到的bean是:"+bean1);
        }
        return bean;
    }
}

最后打印的结果是:
17:20:14.998 [main] INFO com.ryx.xiaoxin_distribute.spring.springIocAndAop.IOC.test1.LocalPosProcessor - 后置处理器前置方法执行了....
17:20:14.998 [main] INFO com.ryx.xiaoxin_distribute.spring.springIocAndAop.IOC.test1.LocalPosProcessor - 获取到的bean是:com.ryx.xiaoxin_distribute.spring.springIocAndAop.IOC.test1.HelloSpringImpl@4d6025c5
执行了这个方法才会执行后置处理器方法...
17:20:14.998 [main] INFO com.ryx.xiaoxin_distribute.spring.springIocAndAop.IOC.test1.LocalPosProcessor - 后置处理器后置方法执行了
17:20:14.998 [main] INFO com.ryx.xiaoxin_distribute.spring.springIocAndAop.IOC.test1.LocalPosProcessor - 获取到的bean是:com.ryx.xiaoxin_distribute.spring.springIocAndAop.IOC.test1.HelloSpringImpl@4d6025c5
17:20:15.006 [main] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver - Found key 'spring.liveBeansView.mbeanDomain' in PropertySource 'systemProperties' with value of type String
applicationContext启动了....
你好,spring嘿嘿

可以说比较简单,网上的案例都是用来处理多个实现类实现一个接口,spring不知道加载哪个,通过BeanPostProcessor和自定义注解处理的案例比较经典
我这边就不废话了.

这一期,我们设计的源码分析计较少,主要是说了spring的两种后置处理器的一些实际使用
这里总结一下
BeanFactoryPostProcessor是bean级别的处理器,功能比较强大,可以修改任意bean的属性,
BeanPostProcessor可以说是粒度更细的后置处理器,分别定义了两个方法,before和after,如果某个bean
实现了InitializingBean接口,那样的话,before方法会在afterProperties方法执行前执行,after会在afterProperties执行后执行,可以让我们
有更多的选择在spring的bean的生命周期内处理我们自己的逻辑

ok,本期内容比较轻松,掌握起来很容易!
Thanks

你可能感兴趣的:(spring源码分析五(bean的后置处理器))