《Spring源码深度解析》七(1)

>>强大,10k+点赞的 SpringBoot 后台管理系统竟然出了详细教程!

第七章:AOP

7.1:切入点:

7.1.1:初始化:AopNamespaceHandler#init

注:如果声明了自定义的注解,那么就一定会在程序中的某个地方注册了对应的解析器,统一接口为BeanDefinitionParser,入口为parse函数

AopNamespaceHandler#init
public void init() 
{
    ...
    registerBeanDefinitionParser("aspectj-autoproxy"new AspectJAutoProxyBeanDefinitionParser());
    ...
}

7.1.2 解析:AspectJAutoProxyBeanDefinitionParser

parse:

public BeanDefinition parse(Element element, ParserContext parserContext) {
    //注册AnnotationAspectJAutoProxyCreator
  AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
    //对于注解中子类处理
    extendBeanDefinition(element, parserContext);
    return null;
}

public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
        ParserContext parserContext, Element sourceElement)
 
{
    //7.1.3
    //注册或升级AutoProxyCreator定义beanName为org.Springframework.aop.config.internalAutoProxyCreator的BeanDefinition
    //对于AOP的实现,基本上都是靠AnnotationAwareAspectJAutoProxyCreator去完成,它可以根据
//@Point注解定义的切点来自动代理相匹配的bean。但是为了配置简便,Spring使用了自定义配置来帮助我们自动注册AnnotationAwareAspectJAutoProxyCreator ,其注册过程就是在这里实现的。
    //这里涉及优先级的问题,即选择使用哪个自动代理创建器
    BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
            parserContext.getRegistry(), parserContext.extractSource(sourceElement));
    //对proxy-target-class以及expose-proxy属性的处理
    //若目标对象实现了至少一个接口,则会使用JDK动态代理,否则为cglib
    //也可以强制使用cglib(<aop:config>的proxy-target-class属性设为true),但是无法adviseFinal方法,因为final方法不能被覆盖
    useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
    //注册组件并通知,便于监听器做进一步处理
    registerComponentIfNecessary(beanDefinition, parserContext);
}

bug:

《Spring源码深度解析》七(1)

7.1.3创建AOP代理:AnnotationAspectJAutoProxyCreator

间接实现了BeanPostProcessor接口,所以当Spring加载这个Bean时会在实例化前调用器postProcessAfterInitialization方法,对于AOP的分析也从这里开始:

7.1.3.1:postProcessAfterInitialization

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        //根据据给定的bean的class和name构建出一个key,格式:beanClassName_beanName
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        //如果它适合被代理, 则需要封装指定bean
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    //如果已经处理过(无须put);或无须增强(无须put);或给定的bean类是否代表一个基础设施类,基础设施类不应代理(put);或配置了指定bean不需要自动代理(put),则返回bean
    ...
    //如果存在增强方法则创建代理
    //7.1.3.1.1 获取增强方法或者增强器。
    //7.1.3.1.2 根据获取的增强进行代理。
    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;
}
7.1.3.1.1:获取增强方法或者增强器。

1.获取所有的增强

2.寻找所有增强中适用于bean的增强并应用

protected Object[] getAdvicesAndAdvisorsForBean(
        Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
    List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
    ...
}

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    List<Advisor> candidateAdvisors = findCandidateAdvisors();//1.
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);//2.
    ...
}
7.1.3.1.1.1:获取所有的增强

解析流程分为四步,如下:

AnnotationAwareAspectJAutoProxyCreator#
protected List<Advisor> findCandidateAdvisors() {
    //当使用注解方式配置AOP的时候并不是丢弃了对XML配置的支持,
    //在这里调用父类方法加载配置文件中的AOP声明
    List<Advisor> advisors = super.findCandidateAdvisors();
    if (this.aspectJAdvisorsBuilder != null) {
    //1.获取所有beanName ,这一步骤中所有在beanFacotry中注册的bean都会被提取出来。
    //2.遍历所有beanName,并找出声明AspectJ注解的类,进行进一步的处理。
    //**3.对标记为AspectJ注解的类进行增强器的提取。所有的增强都由Advisor的实现类InstantiationModelAwarePointcutAdvisorImpl统一封装;不同的注解会生成不同的增强器,增强器会调用增强的方法
    //前置增强:大致的结构是在拦截器链中放置MethodBeforeAdviceInterceptor(中间类)。而在MethodBeforeAdviceinterceptor中又放置了AspectJMethodBeforeAdvice,并在调用invoke时首先串联调用(中间类目的:将mi.processd()抽取出来,以便在befor之后调用,解耦)
    //后置增强:没有提供中间的类,而是直接在拦截器链中使用了中间的AspectJAfterAdvice,try中调用mi.process(),finally中调用增强方法
    //4.将提取结果加入缓存。
        advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    }
    return advisors;
}

增强(advisor)使用了工厂模式,即advisorFactory

7.1.3.1.1.2:寻找所有适用于bean的增强并应用,即满足通配符的增强器
protected List<Advisor> findAdvisorsThatCanApply(
        List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName)
 
{
    ...
    //过滤已经得到的advisors
    //寻找适用于当前class的增强器,引介增强和普通增强分开处理
    return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
    ...
}
7.1.3.1.2:根据获取的增强进行代理,即创建代理,涉及ProxyFactory
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,@Nullable Object[] specificInterceptors, TargetSource targetSource){
    //流程:
    //1.获取当前类中的属性。
    proxyFactory.copyFrom(this);
    //2.添加代理接口。
    evaluateProxyInterfaces(beanClass, proxyFactory)#proxyFactory.addInterface(ifc);
    //3.封装Advisor并加入到ProxyFactory中。需要先将拦截器封装为增强器。
    //设计:由于Spring涉及过多的拦截器、增强器、增强方法等方式来对逻辑进行增强,所以非常有必要统一封装成Advisor来进行代理的创建
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    proxyFactory.addAdvisors(advisors);
    //4.设置要代理的类。
    proxyFactory.setTargetSource(targetSource);
    //5.Spring为子类提供了定制的函数customizeProxyFactory(factory),子类可以在此函数中对ProxyFactory做进一步封装。
    customizeProxyFactory(proxyFactory);
    //6.进行代理的创建与获取操作。
    proxyFactory.getProxy(getProxyClassLoader());
}

第六步中,关于代理的选择:

if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))

三个判断解释:

《Spring源码深度解析》七(1)

JDK与CGlib选择的总结:

《Spring源码深度解析》七(1)

如何强制使用CGlib实现AOP、JDK和CGlib的区别、为什么优先使用JDK(final不可被覆盖):

《Spring源码深度解析》七(1)

JDKDynamicAopProxy#getProxy#invoke:

getProxy创建了代理实例;
invoke封装(new ReflectiveMethodlnvocation(…))、执行(retVal=ReflectiveMethodlnvocation.proceed())了一个拦截器链;
而proceed中增强的逻辑委派给了各个增强器来完成(invoke),拦截器全部执行完后,调用原先的方法。

优化技巧:
后置可参考7.1.3.1.1.1中后置增强的执行,即直接调用了ReflectiveMethodlnvocation的proceed,用finally来实现后置,这样在所有的return结束后,即调用了原方法后才会调用后置方法
前置也可参考,即直接调用before,再返回proceed
这样就避免了原生的直接在调用原方法的前后增加逻辑,达到解耦的目的

CglibAopProxy#getProxy:

getProxy为创建Enhancer的全过程
getCallbacks(rootClass):设置拦截器链,加入Callback中。拦截器(advised属性)会被封装在DynamicAdvisedInterceptor(实现Methodlnterceptor)中

注:CGlib中对于方法的拦截是通过将自定义的拦截器((实现Methodlnterceptor接口)加入Callback中并在调用代理时直接激活拦截器中的intercept 方法来实现的

因此cglib代理的核心逻辑在DynamicAdvisedInterceptor的intercept中
流程与JDK中的invoke类似:都是首先构造链,然后封装此链进行串联调用;
稍有些区别就是在JDK中直接构造ReflectiveMethodlnvocation ,
而在cglib中使用CglibMethodlnvocation 。CglibMethodlnvocation继承自ReflectiveMethodlnvocation , 但是proceed 方法并没有重写,达到职责明确,又能代码复用的目的(技巧)。


原文始发于微信公众号(不止于Java):《Spring源码深度解析》七(1)