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注解反对@EnableAspectJAutoProxypublic class Application {    public static void main(String[] args) {        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Application.class);        ServiceB serviceB = context.getBean("serviceB", ServiceB.class);        serviceB.say();    }}
切面逻辑
@Aspect@Componentpublic 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();    }}
代码逻辑
@Servicepublic 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 进行交融。