BeanPostProcessor在spring bean初始化中的作用
前言
小编最近学习dubbo的内容,大家可以看下小编的dubbo一系列文章分布式架构之Dubbo篇。很长时间忘记更新spring的源码了。spring还差一些内容,即spring的扩展篇,之前讲到了BeanFactoryPostProcessor,BeanPostProcessor, Listener这三个接口是主要扩展接口且市面上大多数的框架也是对这几个接口进行扩展,原理大致相同。当然了ImportBeanDefinitionRegistrar这个接口的registerBeanDefinitions方法也很重要,提前可以将想要导入的类放进beanDefintion中,然后使用导入类,在spring与mybatis整合以及aop原理中同样用到了。今天小编给大家带来BeanPostProcessor的扩展。
贯穿spring bean生命周期的BeanPostProcessor
在j讲源码前,咱们看beanPostProcesor的继承或者实现类,为什么讲这个呢,首先他执行的时机不同,执行的方法不同。这边小编简单举例
稍微介绍一下,接口有两个分支一个是接口继承类,另一个是抽象的实现类,分别是上面的左右分支。大家应该一目了然。
这边小编从初始化spring bean开始:org.springframework.context.support.AbstractApplicationContext#refresh方法中的finishBeanFactoryInitialization,实例化所有不是懒加载的单例对象。最终会调到org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean方法开始用到BeanPostProcessor。依次往下看
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
1、InstantiationAwareBeanPostProcessor =====> postProcessBeforeInstantiation
2、BeanPostProcessor =====> postProcessAfterInitialization (可忽略,里面的判断是不会进去的)
// Candidate constructors for autowiring?
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
3、SmartInstantiationAwareBeanPostProcessor =====> determineCandidateConstructors (推断构造方法)
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
4、MergedBeanDefinitionPostProcessor =====> postProcessMergedBeanDefinition (beanDefintion的合并)
//循环依赖,三级缓存的扩展
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
5、SmartInstantiationAwareBeanPostProcessor =====> getEarlyBeanReference (对三级缓存的类做扩展放入工厂bean中)
//填充属性
populateBean(beanName, mbd, instanceWrapper);
6、InstantiationAwareBeanPostProcessor =====> postProcessAfterInstantiation (判断属性是否需要注入)记得小编演示过代码
7、InstantiationAwareBeanPostProcessor =====> postProcessProperties (真正填充属性)
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
8、BeanPostProcessor =====> postProcessBeforeInitialization (执行部分aware接口且执行注解版的初始化回调方法)
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
9、BeanPostProcessor =====> postProcessAfterInitialization(事件发布 Aop处理)
到这儿就基本讲完了spring调用beanPostProcessor的地方,所以你只要足够大牛可以对以上任意一步对初始化的类做修改。并且每次都能调用到。其中前面都是BeanPostProcessor 的继承接口实现,到最后才是BeanPostProcessor 的直接实现。这样说其实并不准确,因为无论是哪个分支最后其实都实现了BeanPostProcessor 中的两个方法,只是执行方法的顺序放到了最后。
小编讲了那么多不知道各位明白没有,那接下来小编用实际代码来说明一下。
代码模仿Aop
这边模仿aop使用接口到接口也就是没有用的cglib,而是用jdk默认的动态代理,小编在后续会单独带来cglib,因为cglib比较复杂这边暂时不演示代码。
做一个接口并实现他的方法,然后对这个接口做一个切面
//接口类
public interface IAopService {
/**
* 模拟方法
*/
void forkAopMethod();
}
//接口实现类
@Component
public class AopServiceImpl implements IAopService{
@Override
public void forkAopMethod() {
System.out.println("fork aop method impl......");
}
}
代理类
@Component
public class AopBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
Class<?>[] interfaces = bean.getClass().getInterfaces();
Object beanProxy = bean;
//spring aop判断是否要切面的方法,这边我只是随便模拟
//一般会有注解啊,切面等等判断
if (interfaces.length > 0) {
beanProxy = Proxy.newProxyInstance(this.getClass().getClassLoader(),interfaces,new AopHandler(bean));
}
return beanProxy;
}
class AopHandler implements InvocationHandler{
private Object target;
public AopHandler(Object target){
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before method invoke");
Object invoke = method.invoke(target, args);
System.out.println("after method invoke");
return invoke;
}
}
}
测试类
@ComponentScan("com.xxx.xxx.forkaop")
public class AopTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(AopTest.class);
IAopService bean = applicationContext.getBean(IAopService.class);
bean.forkAopMethod();
}
}
测试结果
before method invoke
fork aop method impl......
after method invoke
到这来就模拟完毕了,然后大家应该明白了aop的原理为什么是动态代理了,其默认使用jdk的没有接口的情况下才使用cglib,这边小编暂时不考虑cglib。
思考
这边测试类中小编使用的是 IAopService bean = applicationContext.getBean(IAopService.class);这个代码却没有使用子类的class,为什么会这样呢,大家如果试过就知道如果使用子类实现就会报错,spring容器认为自己没有这个类型的bean,这是为什么呢。
这里因为对AopServiceImpl 进行了代理,所以放入容器里面是一个$Proxy…这样一个spring bean,但是这个代理bean是实现IAopService ,所以根据父类接口拿到的时候实际是拿到了子类实现的代理类,这样就可以进行aop了。
AOP源码阅读
阅读之前将代码示例写好,修改上面测试类以及加入spring的aop类
//测试类
@ComponentScan("com.xxx.xxx.forkaop")
@EnableAspectJAutoProxy
public class AopTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(AopTest.class);
IAopService bean = applicationContext.getBean(IAopService.class);
bean.forkAopMethod();
}
}
//spring aop
@Aspect
@Component
public class SpringAop {
@Pointcut("within(com.dtyunxi.yundt.forkaop.AopServiceImpl)")
public void needPointCut(){
}
@Before("needPointCut()")
public void beforeAopMethod(){
System.out.println("aop before method");
}
@After("needPointCut()")
public void afterAopMethod(){
System.out.println("aop after method");
}
}
测试结果
aop before method
fork aop method impl......
aop after method
通过以上代码知道我们得开启aop 使用@EnableAspectJAutoProxy以及加入@Aspect注解,这边是否想到了spring与mybatis整合。
小编一步一步带大家看下源代码
@EnableAspectJAutoProxy 注解源码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
//注解引入了AspectJAutoProxyRegistrar类,很明显这里会实现ImportBeanDefinitionRegistrar
//加入一些类到beanDefintion中去
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
/**
基于接口cglib而非java接口动态代理实现
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
* to standard Java interface-based proxies. The default is {@code false}.
*/
boolean proxyTargetClass() default false;
/**
指示代理应该由AOP框架作为ThreadLocal公开,
以便通过org.springframework.aop.framework.AopContext类
进行检索。默认关闭,即不能保证AopContext访问将工作。
* Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
* for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
* Off by default, i.e. no guarantees that {@code AopContext} access will work.
* @since 4.3.1
*/
boolean exposeProxy() default false;
}
AspectJAutoProxyRegistrar类源码
//根据给定的@EnableAspectJAutoProxy注释,根据当前适当的BeanDefinitionRegistry
//注册一个AnnotationAwareAspectJAutoProxyCreator。(重点,到最后是BeanPostProcessor的子类)
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
/**
* Register, escalate, and configure the AspectJ auto proxy creator based on the value
* of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
* {@code @Configuration} class.
*/
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//注册AnnotationAwareAspectJAutoProxyCreator的beanDefintion
//当然有一些判断,就判断是否存在内置的,判断与上面的权限谁大,等等。
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
//拿到注解上的属性值,判断,是否需要做一些处理
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
AnnotationAwareAspectJAutoProxyCreator类最终实现的postProcessAfterInitialization方法
在org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.(我们是否需要通知)
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
//这边创建代理对象,使用jdk的动态代理或cglib创建对象
return proxyFactory.getProxy(getProxyClassLoader());
}
这边小编只限贴出jdk的源码,cglib下一次再讲。
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
//这就和小编模拟的有点像了
return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
}
相关源码
org.springframework.aop.framework.JdkDynamicAopProxy#getProxy
org.springframework.aop.framework.CglibAopProxy#getProxy
放入三级缓存的时候则是以下代码
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getEarlyBeanReference
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
return this.wrapIfNecessary(bean, beanName, cacheKey);
}
是不是很眼熟,这里再一次解释了spring 循环依赖使用了三级缓存
总结
小编拖更spring源码有点长了,这次带来的beanPostProcessor希望大家可以喜欢。这边小编自觉得还算讲清楚了,有什么疑问可以评论。小编再接再厉,下次给大家带来cglib动态代理的简码(源码的一部分)。cglib可不是只做aop的哦。