关于后端:Spring-Framework-Aop原理

43次阅读

共计 15376 个字符,预计需要花费 39 分钟才能阅读完成。

Spring Framework Aop 原理

原因

Spring Framework 提供了除 IOC 之外的很多有意思的性能,深入研究其技术原理,可在我的项目技术选型上提供更多的思路和技术把控。Spring Framewrok 代码由大佬精心打磨,能够从性能实现上学习和模拟。另外 Spring Framework 是 Java 我的项目开发的根底,其余技术框架都会基于或者与 Spring 兼容,钻研其中的技术原理,可疾速把握其余技术框架的技术原理,比方 Spring boot \ Spring cloud…

简述

Spring Framework 呈现的背景是,Java 对象之间调用关系简单,为简化对象调用,Spring Framework 基于 Dependency Injection,将对象的控制权转移到 BeanFactory,由框架负责对象的生命周期,将对象与 Bean 进行映射,Bean 的生命周期由欠缺的管理机制。
Aop 切面编程是区别于面向对象编程的,Spring Framework 也提供了实现,成为 Spring’s Aop,仅反对办法级别的切面编程,属于运行期织入,赫赫有名的 Aspectj,属于更高级的一种框架,可能反对到结构器、办法、属性级别。

前提

Spring Framework 推出的 Aop 性能是基于 Ioc 实现的。须要对 IOC 的技术原理有肯定的理解,另外对切面编程的根底有个根本的理解。

注释

利用

maven pom dependency
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.3.20</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.20</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.3.20</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.7</version>
        </dependency>
Application 我的项目 EntryPoint
@ComponentScan
@Configuration
// 开启 Aspectj 注解反对
@EnableAspectJAutoProxy
public class Application {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
        ServiceB serviceB = context.getBean("serviceB", ServiceB.class);
        serviceB.say();}
}
切面逻辑
@Aspect
@Component
public class AopTest {@Pointcut("execution(* org.example.circularReference.*.*(..))")
    public void pointCut() {}

    @Around("pointCut()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {System.out.println("AopTest ...");
        return pjp.proceed();}
}
代码逻辑
@Service
public class ServiceB {public void say() {System.out.println("Application say ...");
    }
}

@EnableAspectJAutoProxy

  1. 可能反对解决 @Aspect 标注的 Component。
  2. 搭配 @Configuration 注解一起应用。
  3. 设置属性 proxyTargetClass=true,仅用 Cglib 生成代理,接口或者对象代理,接口的默认代理实现是 JDK proxy.
  4. 须要引入 aspectjweaver。
  5. 通过 @Import 注解引入 AspectJAutoProxyRegistrar。

AspectJAutoProxyRegistrar

注册 AnnotationAwareAspectJAutoProxyCreator 到 BeanDefinitionRegistry 当中。

具体代码在:AopConfigUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry)

        RootBeanDefinition beanDefinition = new RootBeanDefinition(AnnotationAwareAspectJAutoProxyCreator.class);
        beanDefinition.setSource(source);
        beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
        beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
        return beanDefinition;

AnnotationAwareAspectJAutoProxyCreator

解决利用上下文所有 AspectJ 注解的 aspects \ Spring Advisors,解决逻辑在 org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.
任何设置 AspectJ 注解的类都将被自动识别,Spring AOP 的基于代理的 model、办法连接点能够依照规定匹配。

通过 UML 图,creator 实现了 SmartInstantiationAwareBeanPostProcessor 接口,在 AbstractAutoProxyCreator 抽象类中实现了 postProcessBeforeInstantiation postProcessAfterInitialization 办法,将 Spring Aop 性能实现参加到 Bean 创立的过程中,将 Bean 的信息进行反射,取得 Class 信息与 Advisor 进行匹配,生成对应的代理类。

postProcessBeforeInstantiation 解决 customeTargetSource。
postProcessAfterInitialization 解决实例化后的 Bean,匹配 Pointcut。

    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {if (bean != null) {Object cacheKey = getCacheKey(bean.getClass(), beanName);
            if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                // 通过晚期代理的查看后,开始执行真正的 aop 逻辑
                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. getAdvicesAndAdvisorsForBean 会是一个精彩的逻辑。// 查找能够匹配的所有 Advisor
        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;
    }

上述局部是由 Aop 实现一个大抵逻辑。上面将会介绍 Aop 的具体工作原理。


getAdvicesAndAdvisorsForBean

查找能够匹配的所有 Advisor。具体实现在 org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator

    protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
        // 要害逻辑会在 findEligibleAdvisors 中连续。List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
        if (advisors.isEmpty()) {return DO_NOT_PROXY;}
        return advisors.toArray();}

    protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {List<Advisor> candidateAdvisors = findCandidateAdvisors();
        List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
        extendAdvisors(eligibleAdvisors);
        if (!eligibleAdvisors.isEmpty()) {eligibleAdvisors = sortAdvisors(eligibleAdvisors);
        }
        return eligibleAdvisors;
    }

org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors

    @Override
    protected List<Advisor> findCandidateAdvisors() {
        // Add all the Spring advisors found according to superclass rules.
        List<Advisor> advisors = super.findCandidateAdvisors();
        // Build Advisors for all AspectJ aspects in the bean factory.
        if (this.aspectJAdvisorsBuilder != null) {// 要害逻辑将在 buildAspectJAdvisors() 中连续。advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
        }
        return advisors;
    }

org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors

将 Spring Beanfactory 中 @Aspect 注解润饰的类转换为 Spring Advisors.

  1. 获取所有的 BeanDefinition 汇合
  2. 获取 Class 对象
  3. 判断类上是否有 Aspect 注解
  4. 获取类上的所有 Advisor.
public List<Advisor> buildAspectJAdvisors() {
        List<String> aspectNames = this.aspectBeanNames;

        if (aspectNames == null) {synchronized (this) {
                aspectNames = this.aspectBeanNames;
                if (aspectNames == null) {List<Advisor> advisors = new ArrayList<>();
                    aspectNames = new ArrayList<>();
                    String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
                    // 1. 获取所有的 BeanDefinition 汇合
                    for (String beanName : beanNames) {if (!isEligibleBean(beanName)) {continue;}
                        // We must be careful not to instantiate beans eagerly as in this case they
                        // would be cached by the Spring container but would not have been weaved.
                        // 2. 获取 Class 对象
                        Class<?> beanType = this.beanFactory.getType(beanName, false);
                        if (beanType == null) {continue;}
                        // 3. 判断是否有 Aspect 注解
                        if (this.advisorFactory.isAspect(beanType)) {aspectNames.add(beanName);
                            AspectMetadata amd = new AspectMetadata(beanType, beanName);
                            if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                                // 4. 获取类上的所有 Advisor.
                                MetadataAwareAspectInstanceFactory factory =
                                        new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                                List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                                if (this.beanFactory.isSingleton(beanName)) {this.advisorsCache.put(beanName, classAdvisors);
                                }
                                else {this.aspectFactoryCache.put(beanName, factory);
                                }
                                advisors.addAll(classAdvisors);
                            }
                            else {
                                // Per target or per this.
                                if (this.beanFactory.isSingleton(beanName)) {
                                    throw new IllegalArgumentException("Bean with name'" + beanName +
                                            "'is a singleton, but aspect instantiation model is not singleton");
                                }
                                MetadataAwareAspectInstanceFactory factory =
                                        new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
                                this.aspectFactoryCache.put(beanName, factory);
                                advisors.addAll(this.advisorFactory.getAdvisors(factory));
                            }
                        }
                    }
                    this.aspectBeanNames = aspectNames;
                    return advisors;
                }
            }
        }

        if (aspectNames.isEmpty()) {return Collections.emptyList();
        }
        List<Advisor> advisors = new ArrayList<>();
        for (String aspectName : aspectNames) {List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
            if (cachedAdvisors != null) {advisors.addAll(cachedAdvisors);
            }
            else {MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
                advisors.addAll(this.advisorFactory.getAdvisors(factory));
            }
        }
        return advisors;
    }

解析 Aspect 注解获取 Advisor 的要害代码:

  MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
  List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);

advisorFactory:AspectJAdvisorFactory -> AbstractAspectJAdvisorFactory -> ReflectiveAspectJAdvisorFactory

org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory
应用反射技术解析 @Aspect 润饰的类。

    @Override
    public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
        String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
        validate(aspectClass);

        // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
        // so that it will only instantiate once.
        MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
                new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

        List<Advisor> advisors = new ArrayList<>();
        // 重点关注 getAdvisorMethods
        for (Method method : getAdvisorMethods(aspectClass)) {// Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
            // to getAdvisor(...) to represent the "current position" in the declared methods list.
            // However, since Java 7 the "current position" is not valid since the JDK no longer
            // returns declared methods in the order in which they are declared in the source code.
            // Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
            // discovered via reflection in order to support reliable advice ordering across JVM launches.
            // Specifically, a value of 0 aligns with the default value used in
            // AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).
            // 重点关注 如何将解析后 method 转换为 advisor
            Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
            if (advisor != null) {advisors.add(advisor);
            }
        }

        // If it's a per target aspect, emit the dummy instantiating aspect.
        if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
            advisors.add(0, instantiationAdvisor);
        }

        // Find introduction fields.
        for (Field field : aspectClass.getDeclaredFields()) {Advisor advisor = getDeclareParentsAdvisor(field);
            if (advisor != null) {advisors.add(advisor);
            }
        }

        return advisors;
    }


    private List<Method> getAdvisorMethods(Class<?> aspectClass) {List<Method> methods = new ArrayList<>();
        // 解析 @Aspect 润饰的类,获取其中 Advisor 相干的办法。ReflectionUtils.doWithMethods(aspectClass, methods::add, adviceMethodFilter);
        if (methods.size() > 1) {methods.sort(adviceMethodComparator);
        }
        return methods;
    }

    public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
            int declarationOrderInAspect, String aspectName) {validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());

        AspectJExpressionPointcut expressionPointcut = getPointcut(candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
        if (expressionPointcut == null) {return null;}

        return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
                this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
    }

    private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
        AspectJAnnotation<?> aspectJAnnotation =
                AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
        if (aspectJAnnotation == null) {return null;}

        AspectJExpressionPointcut ajexp =
                new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
        ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
        if (this.beanFactory != null) {ajexp.setBeanFactory(this.beanFactory);
        }
        return ajexp;
    }
    // AspectJExpressionPointcut

BeanFactoryAspectInstanceFactory

org.springframework.aop.aspectj.AspectInstanceFactory 接口的实现。
若应用原型模式,会被实例化屡次,可能失去不正确的语义,能够应用 LazySingletonAspectInstanceFactoryDecorator 来装璜类,达到只实例化一次的成果。

InstantiationModelAwarePointcutAdvisorImpl

AspectJPointcutAdvisor 的外部实现,@Aspect 批改的类中的每个办法都是一个 advisor,也会只有一个实例就是此类。

AspectJExpressionPointcut

org.springframework.aop.Pointcut 接口的外部实现。应用 Aspectj 技术计算 pointcut 表达式(aspect 表达式),表达式最初还是由 Spring aop model 解决,只能反对到 method 级别。


以上是 Spring Advisor 造成的过程。上面开始执行 advisor 匹配的过程。


    // AbstractAdvisorAutoProxyCreator
    protected List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {ProxyCreationContext.setCurrentProxiedBeanName(beanName);
        try {
               // 转移到 AopUtils 中
            return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
        }
        finally {ProxyCreationContext.setCurrentProxiedBeanName(null);
        }
    }
    // AopUtils
    public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {if (candidateAdvisors.isEmpty()) {return candidateAdvisors;}
        List<Advisor> eligibleAdvisors = new ArrayList<>();
        for (Advisor candidate : candidateAdvisors) {if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {eligibleAdvisors.add(candidate);
            }
        }
        boolean hasIntroductions = !eligibleAdvisors.isEmpty();
        for (Advisor candidate : candidateAdvisors) {if (candidate instanceof IntroductionAdvisor) {
                // already processed
                continue;
            }
            // 转移办法
            if (canApply(candidate, clazz, hasIntroductions)) {eligibleAdvisors.add(candidate);
            }
        }
        return eligibleAdvisors;
    }
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {if (advisor instanceof IntroductionAdvisor) {return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
        }
        else if (advisor instanceof PointcutAdvisor) {PointcutAdvisor pca = (PointcutAdvisor) advisor;
            // 执行重载办法的逻辑
            return canApply(pca.getPointcut(), targetClass, hasIntroductions);
        }
        else {
            // It doesn't have a pointcut so we assume it applies.
            return true;
        }
    }
    public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {Assert.notNull(pc, "Pointcut must not be null");
        if (!pc.getClassFilter().matches(targetClass)) {return false;}

        MethodMatcher methodMatcher = pc.getMethodMatcher();
        if (methodMatcher == MethodMatcher.TRUE) {
            // No need to iterate the methods if we're matching any method anyway...
            return true;
        }

        IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
        if (methodMatcher instanceof IntroductionAwareMethodMatcher) {introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
        }

        Set<Class<?>> classes = new LinkedHashSet<>();
        if (!Proxy.isProxyClass(targetClass)) {classes.add(ClassUtils.getUserClass(targetClass));
        }
        classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

        for (Class<?> clazz : classes) {Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
            for (Method method : methods) {
                if (introductionAwareMethodMatcher != null ?
                        // 真正执行匹配的逻辑
                        introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
                        methodMatcher.matches(method, targetClass)) {return true;}
            }
        }

        return false;
    }
    // AspectJExpressionPointcut 
    // 具体匹配逻辑在 aspectj 中,有趣味的能够深入研究下。@Override
    public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {obtainPointcutExpression();
        ShadowMatch shadowMatch = getTargetShadowMatch(method, targetClass);

        // Special handling for this, target, @this, @target, @annotation
        // in Spring - we can optimize since we know we have exactly this class,
        // and there will never be matching subclass at runtime.
        if (shadowMatch.alwaysMatches()) {return true;}
        else if (shadowMatch.neverMatches()) {return false;}
        else {
            // the maybe case
            if (hasIntroductions) {return true;}
            // A match test returned maybe - if there are any subtype sensitive variables
            // involved in the test (this, target, at_this, at_target, at_annotation) then
            // we say this is not a match as in Spring there will never be a different
            // runtime subtype.
            RuntimeTestWalker walker = getRuntimeTestWalker(shadowMatch);
            return (!walker.testsSubtypeSensitiveVars() || walker.testTargetInstanceOfResidue(targetClass));
        }
    }

以上是 Spring Advisor 匹配的过程。


创立代理的局部就不做解释了。


以上就是 Spring Aop 技术的原理。通读后可对 Aop 实现有个大抵的了解,Spring 借助 AspectJ 的注解和表达式匹配,实现 Spring Aop 的根底性能,同时又和 Spring Ioc 进行交融。

正文完
 0