本篇主要是讲解IOC容器初始化过程中大体进行了哪一些工作,以及Bean后置处理器的工作原理和BeanPostProcessor在底层的使用。
version:4.3.12.RELEASE
version:4.11
实现BeanPostProcessor接口的组件,并且在两个方法体内打上断点:
public class BeanPostProcessorDefinition implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object o, String s) throws BeansException { System.out.println("postProcessBeforeInitialization -->"+s+" = "+o); return o; } @Override public Object postProcessAfterInitialization(Object o, String s) throws BeansException { System.out.println("postProcessorAfterInitialization -->"+s+"="+o); return o; } }
调试后查看方法调用栈如下(如图1):
在方法调用栈中的initializeBean(初始化Bean)方法中,有下面一段类似的伪代码:
initializeBean(param){ wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); ... invokeInitMethods(beanName, wrappedBean, mbd); ... wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); }
这段伪代码的大致意思就是先执行bean初始化之前的方法,然后执行bean初始化方法,最后执行初始化后的方法。
applyBeanPostProcessorsBeforeInitialization也是属于方法调用栈的一环,进去有类似一段伪代码:
applyBeanPostProcessorsBeforeInitialization(param) throws BeansException { for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) { result = beanProcessor.postProcessBeforeInitialization(result, beanName); if (result == null) { return result; } } return result; }
这段代码通过遍历得到所有的BeanPostProcessor,然后挨个执行重写的postProcessBeforeInitialization方法,倘若有一个方法返回的bean为null,那么循环就会跳出,意味着下面的postProcessBeforeInitialization方法不会被执行。在初始化方法后执行的applyBeanPostProcessorsAfterInitialization同理也是一样的。
大致总结后置处理器处理Bean初始化的过程(如图2):
谈到spring的IOC容器都离不开两个接口BeanFactory和ApplicationContext,其中ApplicationContext是BeanFactory的子接口,他们都可以代表spring容器。
图1打断点所示的方法调用栈可以用来分析容器初始化所进行的工作(以AnnotationConfigApplicationContext获取容器为例):
refresh过程:
registerBeanPostProcessors(Param)注册Bean后置处理器用来拦截Bean的创建
注册BeanPostProcessor,实际上spring就会创建对象保存在容器中;
以下是创建Bean的流程:
1、doCreateBean(Param)方法内创建Bean实例
2、populateBean(Param)给bean实例属性赋值
3、initializeBean(Param):初始化Bean
4、invokeAwareMethods():处理Bean实现Aware接口的方法回调
5、后置处理器处理的流程:图2的流程
==========上面流程则完成对BeanPostProcessor的注册和创建
refresh过程接上:
在spring中,Aware接口的Bean在被初始之后,可以取得一些相对应的资源,也就是说,自定义组件想要使用Spring容器底层的一些组件(ApplicationContext,BeanFactory,xxx)的话,自定义组件就需要实现xxxxAware接口;在创建对象的时候,会调用接口规定的方法注入相关组件,把Spring底层一些组件注入到自定义的Bean中;
ApplicationContextAware
可以在Spring初始化实例 Bean的时候,可以通过这个接口将当前的Spring上下文传入,即获得spring 容器,实际开发中,常常封装成一个工具类(方便获取容器获取bean):
//将组件注册添加到容器中后可以直接当作工具类 public class SpringContextTool implements ApplicationContextAware { private static ApplicationContext context = null; public static Object getBean(String beanName) { return context.getBean(beanName); } public static <T> T getBean(Class<T> clazz){ return context.getBean(clazz); } public static ApplicationContext getContext() { return context; } public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { context = applicationContext;//打个断点 } }
原理:在重写方法打个断点,查看方法调用栈
容器看出,在bean初始化方法执行之前,先执行后置处理器的postProcessBeforeInitialization方法,程序跳进ApplicationContextAwareProcessor这个类中(此类实现了BeanPostProcessor接口),执行重写的postProcessBeforeInitialization方法,在跳到invokeAwareInterfaces方法中,判断了当前初始化bean时候继承了对应的Aware,如果是则调用对应的set方法,传入对应的资源。
同理还有**EnvironmentAware
EmbeddedValueResolverAware
ResourceLoaderAware
ApplicationEventPublisherAware
MessageSourceAware**也是注入spring底层组件
再举个EmbeddedValueResolverAware的例子,可以实现这个aware接口来完成Spring获取properties文件属性值:
public class PropertiesUtil implements EmbeddedValueResolverAware { private static StringValueResolver resolver; @Override public void setEmbeddedValueResolver(StringValueResolver resolver) { this.resolver = resolver; } public static String getPropertiesValue(String key) { StringBuilder name = new StringBuilder("${").append(key).append("}"); return resolver.resolveStringValue(name.toString()); } }
需要获取properties文件的属性值时可以采用:propertiesUtil.getPropertiesValue("xxxxxxx")或者@value("xxxx")来达到获取属性值。
打个断点后发现它的原理和ApplicationContextAware是一样的。都是判断了当前初始化bean时候继承了对应的Aware,如果是则调用对应的set方法,传入对应的资源。源码如下:
private void invokeAwareInterfaces(Object bean) { if (bean instanceof Aware) { if (bean instanceof EnvironmentAware) { ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment()); } if (bean instanceof EmbeddedValueResolverAware) { ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver); } if (bean instanceof ResourceLoaderAware) { ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext); } if (bean instanceof ApplicationEventPublisherAware) { ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext); } if (bean instanceof MessageSourceAware) { ((MessageSourceAware) bean).setMessageSource(this.applicationContext); } if (bean instanceof ApplicationContextAware) { ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); } } }
ServletContextAware、ServletConfigAware等几个原理也是差不多类似的。
同理还有BeanValidationPostProcessor也实现了BeanPostProcessor接口,可用于数据校验,还有InitDestroyAnnotationBeanPostProcessor也实现了此接口,主要是用于处理JSR250那几个注解的,AutowiredAnnotationBeanPostProcessor也实现了该接口,用于处理@autowired注解装载bean。总之,Bean的赋值、注入其他组件,@autowired,@Async,生命周期等都是使用BeanPostProcessor来完成的。这一些使用和原理在下一章再分析并补上流程图。