24.AOP的第一个时机之resolveBeforeInstantiation

587 阅读11分钟

在spring aop中,如果我们的类属符合如下条件:被切面的pointcut匹配到、或者属于自定义的Advisor接口实现类,那么spring在bean完成实例化之后,会为类生成代理对象。这是众所周知的aop流程。

此外,spring还为我们提供了TargetSourceCreator接口,该接口的功能是:在bean实例化之前,就为类生成代理。 现在我们通过查看源码的方式,来了解该接口的功能。

创建代理

doGetBean

在循环依赖中我们讲了spring实例化bean的入口,refresh->finishBeanFactoryInitialization->preInstantiateSingletons->getBean->doGetBean,看doGetBean中的如下代码

if (mbd.isSingleton()) {
    // 实例化bean
    sharedInstance = getSingleton(beanName, () -> {
        try {
            // 真正的完成bean的创建
            return createBean(beanName, mbd, args);
        }
        catch (BeansException ex) {
            destroySingleton(beanName);
            throw ex;
        }
    });
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

createBean

createBean(beanName, mbd, args);方法真正的完成了bean的实例化,包括循环依赖、AOP、生命周期等。

所谓的AOP无非就是将bean加强,在bean的方法前后加上其他的方法而已,bean的class在虚拟机启动的时候就加载到JVM里了,我们不会通过修改class来动态扩展bean的功能,但是可以新生成一个类(动态代理类),这个类呢,包含了bean的所有功能,同时又进行了加强,然后将这个动态代理类实例化,替换掉原有的bean,最后放到spring单例池中。

如果你的类没有被其他类依赖,那么可以在doCreateBean之前就创建好代理对象。

//给Bean后置处理器一个机会,返回一个替代目标对象的代理对象。
//就在这里
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
    //注意如果有 InstantiationAwareBeanPostProcessor类型的接口
    //并返回了自定义对象 这里会直接返回
    return bean;
}
//如果上面直接返回了bean 下面的doCreateBean就不会执行
Object beanInstance = doCreateBean(beanName, mbdToUse, args);

注意此时还没后面的bean初始化代码,这里AOP的准备工作,AOP实现是靠BeanPostProcessor后置处理器完成的。

BeanFactoryPostProcessor和BeanPostProcessors两者有啥区别?

BeanFactoryPostProcessor干预BeanDefinition的生成,而BeanPostProcessors干预bean的实例化。

// 给Bean后置处理器一个机会,返回一个替代目标对象的代理对象。
@Nullable
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    //如果尚未被解析
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        // Make sure bean class is actually resolved at this point.
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            Class<?> targetType = determineTargetType(beanName, mbd);
            if (targetType != null) {
                //调用InstantiationAwareBeanPostProcessor的 
                //postProcessBeforeInstantiation
                //参数是Class
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                //这里返回的是null
                if (bean != null) {
                    //调用BeanPostProcessor的 postProcessAfterInitialization
                    //注意是BeanPostProcessor
                    bean = applyBeanPostProcessorsAfterInitialization (bean, beanName);
                }
            }
        }
        mbd.beforeInstantiationResolved = (bean != null);
    }
    return bean;
}

这个resolveBeforeInstantiation()方法的意义到底是什么?

其实很简单,它的意思就是说,如果我们指定了targetSource,那么可以在这里创建一个代理直接返回,就不需要走下边的实例化和初始化阶段了,因为指定了targetSource后,这个bean就由开发人员自己负责完成创建了。而如果没有指定targetSource,那么就按照正常流程往下执行bean的实例化和初始化,说白了就是人家注释上说的:“给你一个返回代理的机会”。

protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
    //for循环,拿到所有的BeanPostProcessors。
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
            //判断是InstantiationAwareBeanPostProcessor
            //强转为InstantiationAwareBeanPostProcessor
            InstantiationAwareBeanPostProcessor ibp = 
                                    (InstantiationAwareBeanPostProcessor) bp;
            //调用InstantiationAwareBeanPostProcessor的
            //postProcessBeforeInstantiation方法
            Object result = ibp.postProcessBeforeInstantiation
                                                                            (beanClass, beanName);
            if (result != null) {
                return result;
            }
        }
    }
    //如果没有实现自定义的InstantiationAwareBeanPostProcessor
    //这里返回的是null
    return null;
}

注意这里收集到的是InstantiationAwareBeanPostProcessor InstantiationAwareBeanPostProcessor是BeanPostProcessor的子接口。如果applyBeanPostProcessorsBeforeInstantiation方法返回bean不为空,则实例化结束直接返回resolveBeforeInstantiation方法的返回值。不会执行下面的doCreateBean方法。

spring会遍历所有BeanPostProcessor,这么多后置处理器具体生成代理用到的是哪个?

答:AnnotationAwareAspectJAutoProxyCreator。

AnnotationAwareAspectJAutoProxyCreator继承自AbstractAutoProxyCreator。AbstractAutoProxyCreator是InstantiationAwareBeanPostProcessor类型,并且重写了postProcessBeforeInstantiation方法,所以此时进入AbstractAutoProxyCreator的方法,postProcessBeforeInstantiation方法如下:

postProcessBeforeInstantiation

此时生成代理的第一个时机都出现了,在postProcessBeforeInstantiation方法中生成代理

   @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
        Object cacheKey = getCacheKey(beanClass, beanName);
​
        if (!StringUtils.hasLength(beanName) ||         
                        !this.targetSourcedBeans.contains(beanName)) {
            
            //advisedBeans是一个集合,用来保存不需要代理的类。比如我们上面定义的切面
            //本身是不需要被代理的,还有加了@Configuration注解的Config配置类,
            //是不需要代理的,Config其实已经被代理了,之前讲过。
            if (this.advisedBeans.containsKey(cacheKey)) {
                return null;
            }
            //isInfrastructureClass(beanClass)
            //判断我们这个业务类是否需要被代理,进入isInfrastructureClass代码
            //判断Advice、Pointcut、Advisor是否是beanClass的超类或者超接口
            //shouldSkip(beanClass, beanName)
            //主要是判断beanName不为空且不是original instance
            //2个条件都是false 说明需要代理
            if (isInfrastructureClass(beanClass) 
                            || shouldSkip(beanClass, beanName)) {
                //不需要代理
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return null;
            }
        }
        //这里会做判断 如果 targetSource
        //如果有自定义TargetSource 
        //将当前beanName放入targetSourcedBeans缓存中,直接走创建代理的分支
        //不会走createBean去创建Bean,这里就是给一个机会。
        //关于自定义TargetSource这个分支暂时不讲。
        TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
        
        //一般情况下targetSource为null不会走这个分支 直接返回null
        //一般情况下targetSource为null不会走这个分支 直接返回null
        //一般情况下targetSource为null不会走这个分支 直接返回null
        if (targetSource != null) {
            if (StringUtils.hasLength(beanName)) {
                this.targetSourcedBeans.add(beanName);
            }
            //获取切面
            Object[] specificInterceptors = 
                getAdvicesAndAdvisorsForBean(beanClass, 
                                             beanName, 
                                            targetSource);
            //创建代理对象
            Object proxy = 
                createProxy(beanClass,
                            beanName, 
                            specificInterceptors, 
                            targetSource);
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        }
        return null;
    }

if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) 这行代码就是判断我们这个业务类是否需要被代理,进入isInfrastructureClass代码:

//判断Advice、Pointcut、Advisor、AopInfrastructureBean
//是否是我们的beanClass的超类或者超接口
protected boolean isInfrastructureClass(Class<?> beanClass) {
        return (super.isInfrastructureClass(beanClass) ||
                     (this.aspectJAdvisorFactory != null && 
                      this.aspectJAdvisorFactory.isAspect(beanClass)));
    }

调用父类的方法

protected boolean isInfrastructureClass(Class<?> beanClass) {
        //判断Advice、Pointcut、Advisor、AopInfrastructureBean
        //是否是beanClass的超类或者超接口
        boolean retVal = Advice.class.isAssignableFrom(beanClass) ||
                Pointcut.class.isAssignableFrom(beanClass) ||
                Advisor.class.isAssignableFrom(beanClass) ||
                AopInfrastructureBean.class.isAssignableFrom(beanClass);
        
        return retVal;
    }

首先会调用父类的方法 class1.isAssignableFrom(class2) 判定此 Class1 对象所表示的类或接口与指定的 Class2 参数所表示的类或接口是否相同,或是否是其超类或超接口。

如果是则返回 true;否则返回 false。

Advice、Pointcut、Advisor等是跟切面相关的,不需要代理。 如果父类方法返回false,继续判断该类是不是一个切面,是切面的话也是不需要被代理的。

shouldSkip(beanClass, beanName)是判断beanName不为空且不是original instance。

如果2个条件都是false才会被代理 符合条件的放入advisedBeans 集合中,后面会根据这个集合判断业务类是否需要被代理。

上面只是判断是否需要代理。如果是不需要代理的class加入不需要代理的Map集合中。

TargetSource targetSource = getCustomTargetSource(beanClass, beanName);

getCustomTargetSource(beanClass, beanName);一般情况下targetSource为null

targetSource为null直接返回null的话就不会提前创建代理了。也就是说getCustomTargetSource方法如果返回TargetSource类型,那么if逻辑里会将当前bean加入this.targetSourcedBeans.add(beanName);并且为当前类生成代理,那么getCustomTargetSource方法逻辑是什么呢?我们进去看看

@Nullable
protected TargetSource getCustomTargetSource(Class<?> beanClass, String beanName) {

   if (this.customTargetSourceCreators != null &&
         this.beanFactory != null && this.beanFactory.containsBean(beanName)) {
      for (TargetSourceCreator tsc : this.customTargetSourceCreators) {
         TargetSource ts = tsc.getTargetSource(beanClass, beanName);
         if (ts != null) {
            // Found a matching TargetSource.
            if (logger.isTraceEnabled()) {
               logger.trace("TargetSourceCreator [" + tsc +
                     "] found custom TargetSource for bean with name '" + beanName + "'");
            }
            return ts;
         }
      }
   }

   // No custom TargetSource found.
   return null;
}

先看第一个判断this.customTargetSourceCreators != null,首先要知道this是谁?

this是AbstractAutoProxyCreator,customTargetSourceCreators是他的属性

AbstractAutoProxyCreator暴露了一个方法

setCustomTargetSourceCreators(TargetSourceCreator... targetSourceCreators)

总结一下:那也就是说如果我们想要在bean实例化之前,就为类生成代理。我们需要调用 AbstractAutoProxyCreator#setCustomTargetSourceCreators来设置TargetSourceCreator。

继续往下看

如果customTargetSourceCreators成员有值,于是遍历该成员。

调用TargetSourceCreator#getTargetSource方法,方法逻辑如下

@Override
@Nullable
public final TargetSource getTargetSource(Class<?> beanClass, String beanName) {
    //此处是模板模式会调用到AbstractBeanFactoryBasedTargetSourceCreator的具体子类方法中,
    //具体子类方法会返回TargetSource
   AbstractBeanFactoryBasedTargetSource targetSource =
         createBeanFactoryBasedTargetSource(beanClass, beanName);
   if (targetSource == null) {
      return null;
   }

   if (logger.isDebugEnabled()) {
      logger.debug("Configuring AbstractBeanFactoryBasedTargetSource: " + targetSource);
   }
    
   //拷贝1个新的internalBeanFactory
   DefaultListableBeanFactory internalBeanFactory = getInternalBeanFactoryForBean(beanName);

   // We need to override just this bean definition, as it may reference other beans
   // and we're happy to take the parent's definition for those.
   // Always use prototype scope if demanded.
   BeanDefinition bd = this.beanFactory.getMergedBeanDefinition(beanName);
   GenericBeanDefinition bdCopy = new GenericBeanDefinition(bd);
   if (isPrototypeBased()) {
      bdCopy.setScope(BeanDefinition.SCOPE_PROTOTYPE);
   }
   internalBeanFactory.registerBeanDefinition(beanName, bdCopy);

   // Complete configuring the PrototypeTargetSource.
   targetSource.setTargetBeanName(beanName);
   //设置拷贝的internalBeanFactory到targetSource
   targetSource.setBeanFactory(internalBeanFactory);

   return targetSource;
}

AbstractBeanFactoryBasedTargetSourceCreator类是TargetSourceCreator接口的一个抽象实现类。 createBeanFactoryBasedTargetSource(beanClass, beanName);是标准的模板模式。

createBeanFactoryBasedTargetSource(beanClass, beanName);会调用到AbstractBeanFactoryBasedTargetSourceCreator的具体子类方法中,返回TargetSource。

接着往下看getInternalBeanFactoryForBean(beanName);创建一个新的BeanFactory,新的BeanFactory会拥有老的BeanFactory的属性。但需要注意的是,新BeanFactory的BeanPostProcessor集合里,去除了AbstractAutoProxyCreator类型,如下

protected DefaultListableBeanFactory getInternalBeanFactoryForBean(String beanName) {
   synchronized (this.internalBeanFactories) {
      DefaultListableBeanFactory internalBeanFactory=this.internalBeanFactories.get(beanName);
      if (internalBeanFactory == null) {
         internalBeanFactory = buildInternalBeanFactory(this.beanFactory);
         this.internalBeanFactories.put(beanName, internalBeanFactory);
      }
      return internalBeanFactory;
   }
}
protected DefaultListableBeanFactory buildInternalBeanFactory(ConfigurableBeanFactory containingFactory) {
   // Set parent so that references (up container hierarchies) are correctly resolved.
   DefaultListableBeanFactory internalBeanFactory
              = new DefaultListableBeanFactory(containingFactory);

   // 拷贝所有的BeanPostProcessor
   internalBeanFactory.copyConfigurationFrom(containingFactory);

   //排除了AOP核心组件对应的BeanPostProcessor
   internalBeanFactory.getBeanPostProcessors().removeIf(beanPostProcessor ->
         beanPostProcessor instanceof AopInfrastructureBean);

   return internalBeanFactory;
}

我们可以看到是克隆一个原来的BeanFactory出来,然后将里面所有的AopInfrastructureBean组件都进行移除,而这个组件是什么?其实就是我们的AOP的核心组件,相当于就是将克隆出来的BeanFactory当中的所有AOP的组件全部remove掉。

参考链接:ac.nowcoder.com/discuss/826…

到此,类的代理对象就生成了,克隆出来的BeanFactory当中的所有AOP的组件被全部remove掉。所以之后的spring的实例化逻辑也不会生成代理了。

总结一下:如果我们想要在bean实例化之前,就为类生成代理,需要提供AbstractBeanFactoryBasedTargetSourceCreator的实现类。

调用代理对象方法

假设生成的是jdk代理。当调用对象方法时,会进入invoke方法。方法首先获取TargetSource对象

    @Override
    @Nullable
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       Object oldProxy = null;
       boolean setProxyContext = false;
       
       TargetSource targetSource = this.advised.targetSource;
       Object target = null;
       //调用getTarget获取原来的对象
       target = targetSource.getTarget();
           
    }

调用targetSource.getTarget();获取原来的对象.

在前言里提到的aop流程中,最终生成的TargetSource是SingletonTargetSource类型,于是获取到的target就是原来的对象。

而在上述流程中,我们是提前生成代理的,生成的TargetSource类型是我们钩子方法里自定义的,所以获取到的target取决于我们如何实现。

总结一下:如果我们想要在bean实例化之前,就为类生成代理,还需要提供TargetSource接口的实现。

下面我们自己来实现TargetSource相关接口。

使用TargetSource提前创建代理

日志接口

package target.source;

import org.springframework.stereotype.Component;

@Component
public interface LogService {

     void print();
}

日志接口实现类

package target.source;

import org.springframework.stereotype.Component;

@Component
public class AopLog implements LogService {

   public String log() {
      System.out.println("----log----");
      return "log";
   }

   @Override
   public void print() {
      System.out.println("----print----");
   }
}

配置类

package target.source;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@EnableAspectJAutoProxy(proxyTargetClass = false)
@ComponentScan()
public class BeanConfig {

}

切面和切面表达式

package target.source;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.PriorityOrdered;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class Aop implements PriorityOrdered {

    //指定切入点表达式,拦截那些方法,即为那些类生成代理对象
    //@Pointcut("execution(* com.bie.aop.UserDao.save(..))")  ..代表所有参数
    //@Pointcut("execution(* com.bie.aop.UserDao.*())")  指定所有的方法
    //@Pointcut("execution(* com.bie.aop.UserDao.save())") 指定save方法

    @Pointcut("execution(* aop.*.*(..))")
    public void pointCut(){

    }

    @Before("pointCut()")
    public void Before(){
        System.out.println("Before");
    }

    @After("pointCut()")
    public void After(){
        System.out.println("After");
    }

    @AfterThrowing("pointCut()")
   public void AfterThrowing(){
      System.out.println("AfterThrowing");
   }

   @AfterReturning("pointCut()")
   public void AfterReturning(){
      System.out.println("AfterReturning");
   }

   @Around("pointCut()")
   public void Around(ProceedingJoinPoint joinPoint) throws Throwable {
      System.out.println("Around Before");
      joinPoint.proceed();
      System.out.println("Around After");
   }

   @Override
   public int getOrder() {
      return 1;
   }
}

根据上面的总结:如果我们想要在bean实例化之前,就为类生成代理:

1.需要提供AbstractBeanFactoryBasedTargetSourceCreator的实现类

2.需要提供TargetSource接口的实现。

3.需要调用 AbstractAutoProxyCreator#setCustomTargetSourceCreators来设置TargetSourceCreator。

下面就是开始做这些事情。

CustomTargetSourceCreator

1.需要提供AbstractBeanFactoryBasedTargetSourceCreator的实现类

package target.source;

import org.springframework.aop.framework.autoproxy.target.AbstractBeanFactoryBasedTargetSourceCreator;
import org.springframework.aop.target.AbstractBeanFactoryBasedTargetSource;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

public class CustomTargetSourceCreator extends AbstractBeanFactoryBasedTargetSourceCreator {

    @Override
    protected AbstractBeanFactoryBasedTargetSource createBeanFactoryBasedTargetSource(Class<?> beanClass, String beanName) {
        if (getBeanFactory() instanceof ConfigurableListableBeanFactory) {
            if(beanClass.isAssignableFrom(AopLog.class)) {
                return new CustomTargetSource();
            }
        }
        return null;
    }
}

CustomTargetSource

2.需要提供TargetSource接口的实现。

package target.source;

import org.springframework.aop.target.AbstractBeanFactoryBasedTargetSource;

import java.io.Serializable;

public class CustomTargetSource extends AbstractBeanFactoryBasedTargetSource implements Serializable {
   private static final long serialVersionUID = 5177019431887513952L;

    @Override
    public Object getTarget() throws Exception {
        //此处获取的BeanFactory是上面拷贝出来的BeanFactory
        return getBeanFactory().getBean(getTargetBeanName());
    }
}

其中getBeanFactory()的值,是上述流程提到的新的BeanFactory。

由于该BeanFactory的BeanPostProcessor没有了AbstractAutoProxyCreator。

所以getBeanFactory().getBean(getTargetBeanName())获取的bean,一定是原生的bean,而不是代理对象。

CustomTargetSourceCreatorBeanPostProcessor

3.需要调用 AbstractAutoProxyCreator#setCustomTargetSourceCreators来设置TargetSourceCreator。

package target.source;

import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.PriorityOrdered;
import org.springframework.stereotype.Component;

@Component
public class CustomTargetSourceCreatorBeanPostProcessor implements BeanPostProcessor, PriorityOrdered, BeanFactoryAware {

    private BeanFactory beanFactory;

    @Override
    public int getOrder() {
        return 45;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if(bean instanceof AnnotationAwareAspectJAutoProxyCreator) {
            AnnotationAwareAspectJAutoProxyCreator creator 
                            = (AnnotationAwareAspectJAutoProxyCreator)bean;
            CustomTargetSourceCreator targetSourceCreator
                            = new CustomTargetSourceCreator();
             targetSourceCreator.setBeanFactory(beanFactory);
             creator.setCustomTargetSourceCreators(targetSourceCreator);
        }
        return bean;
    }
    
    //这里的BeanFactory是原生的BeanFactory
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }
}

光写了CustomTargetSourceCreator 还不行,因为它必须作为AbstractAutoProxyCreator类的成员,所以我们需要给AbstractAutoProxyCreator的成员赋值。

此处我们自定义了CustomTargetSourceCreatorBeanPostProcessor。

到此,我们就完成了对StudentServiceImpl类型提前生成代理功能的整合。

参考链接:blog.csdn.net/qq_39002724…