美文网首页
第七章 AOP

第七章 AOP

作者: 口可口可_99d4 | 来源:发表于2019-04-21 23:55 被阅读0次

整体流程:
1、解析XML配置:编写一个自定义标签解析器

  • Spring容器,加载这个解析器,并parse配置
  • 解析器自动注册AspectJAwareAdvisorAutoProxyCreator.class,这个类继承了BPP(流式处理)

2、给所有被代理类添加后置处理(beanName, class):利用AspectJAwareAdvisorAutoProxyCreator的BPP特性,当每个类加载的时候,生成它的代理。

3、找到所有被代理类的拦截器:工具类方法,从beanFactory中找到所有继承了Advisor.class的方法,根据advisor上的规则,和class过滤List<Advisor>

4、创建代理(拦截器,beanName)JDK/Cglib(invoke):链表的方式来实现过滤器链


image.png

1、阅读顺序

  • 1、自定义的XML标签:AopNamespaceHandler
    -> 对应的AspectJAutoProxyBeanDefinitionParser的parse()方法
    • 1.1、自动注册这个类AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary
    • 1.2、对proxy-target-class和expose-proxy属性处理:[proxy-target-class:指定cglib还是jdk]、[expose-proxy:目标对象内部的调用将无法实施切面增强]
    • 1.3、注册组件监听器
  • 2、关注1.1中,注册的AnnotationAwareAspectJAutoProxyCreator类的实例化过程,就是初始化了切面代理。【下图有该类的UML图】
    • 2.1、关注它的postProcessAfterInitialization方法 -> wrapIfNecessary()
    • 2.2、wrapIfNecessary:
      • 2.2.1、是否需要增强、是否是基础设施类
      • 2.2.2、获取增强的方法[getAdvicesAndAdvisorsForBean()]
      • 2.2.3、根据增强方法创建代理类:AbstractAutoProxyCreator#createProxy()
  • 3、关注2.2.2中的获取增强的方法:查找候选增强,过滤可用增强
    • 3.1、查找Advisor.class的bean:[父抽象类实现的]
    • 3.2、过滤所有的bean,进行选择性增强。
      • 3.2.1、是否需要增强:是否有@aspectj注解,或者bean是ajc$开头的beanName
      • 3.2.2、查找advice,加入缓存:[查找advice:AspectJAdvisorFactory#getAdvisors(factory)]
  • 4、关注3.2.2中的查找advice:getAdvisors
    • 4.1、获取类下的所有@PointCut注解的方法
    • 4.2、getPointCut()
    • 4.3、初始化advice:new InstantiationModelAwarePointcutAdvisorImpl() ->instantiateAdvice(pointcut)
      • 4.2.1、根据方法上的注解构造pointCut:findAnnotation():[Before.class, Around, After, AfterReturning, AfterThrowing, Pointcut]
  • 5、关注4.2.1的findAnnotation()
    • 5.1 给注解类型和SynthesizedAnnotation.class添加代理【见下面的源码】
      代理的作用是,调用这个advisor实例获取对象时,返回porperty的值
  • 6、关注4.3的instantiateAdvice(pointcut)
    • 6.1、根据pointCut的内容,switch:before、after等,构建不同的advice类实例
  • 7、关注2.2.3根据增强方法创建代理类
    • 7.1、将增强方法封装成拦截器链List,
    • 7.2、如果list为空,直接执行切点方法
    • 7.3、在invocation.proceed中执行
      \color{red}{待续...ProxyFactory\#getProxy()}

\color{red}{around是怎么搞的,再仔细看看AspectJAroundAdvice\#invoke()}

public class AopNamespaceHandler extends NamespaceHandlerSupport {

    /**
     * Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the
     * '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}'
     * and '{@code scoped-proxy}' tags.
     */
    @Override
    public void init() {
        // In 2.0 XSD as well as in 2.1 XSD.
        registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
        registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
        registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());

        // Only in 2.0 XSD: moved to context namespace as of 2.1
        registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
    }

}
AnnotationAwareAspectJAutoProxyCreator类结构

给注解类型添加代理

static <A extends Annotation> A synthesizeAnnotation(A annotation, Object annotatedElement) {
        if (annotation == null) {
            return null;
        }
        if (annotation instanceof SynthesizedAnnotation) {
            return annotation;
        }

        Class<? extends Annotation> annotationType = annotation.annotationType();
        if (!isSynthesizable(annotationType)) {
            return annotation;
        }

        DefaultAnnotationAttributeExtractor attributeExtractor =
                new DefaultAnnotationAttributeExtractor(annotation, annotatedElement);
        InvocationHandler handler = new SynthesizedAnnotationInvocationHandler(attributeExtractor);

        // Can always expose Spring's SynthesizedAnnotation marker since we explicitly check for a
        // synthesizable annotation before (which needs to declare @AliasFor from the same package)
        Class<?>[] exposedInterfaces = new Class<?>[] {annotationType, SynthesizedAnnotation.class};
        return (A) Proxy.newProxyInstance(annotation.getClass().getClassLoader(), exposedInterfaces, handler);
    }

根据不同的pointcut,构建对象
ReflectiveAspectJAdvisorFactory

public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
            MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

        Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
        validate(candidateAspectClass);

        AspectJAnnotation<?> aspectJAnnotation =
                AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
        if (aspectJAnnotation == null) {
            return null;
        }

        // If we get here, we know we have an AspectJ method.
        // Check that it's an AspectJ-annotated class
        if (!isAspect(candidateAspectClass)) {
            throw new AopConfigException("Advice must be declared inside an aspect type: " +
                    "Offending method '" + candidateAdviceMethod + "' in class [" +
                    candidateAspectClass.getName() + "]");
        }

        if (logger.isDebugEnabled()) {
            logger.debug("Found AspectJ method: " + candidateAdviceMethod);
        }

        AbstractAspectJAdvice springAdvice;

        switch (aspectJAnnotation.getAnnotationType()) {
            case AtBefore:
                springAdvice = new AspectJMethodBeforeAdvice(
                        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                break;
            case AtAfter:
                springAdvice = new AspectJAfterAdvice(
                        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                break;
            case AtAfterReturning:
                springAdvice = new AspectJAfterReturningAdvice(
                        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
                if (StringUtils.hasText(afterReturningAnnotation.returning())) {
                    springAdvice.setReturningName(afterReturningAnnotation.returning());
                }
                break;
            case AtAfterThrowing:
                springAdvice = new AspectJAfterThrowingAdvice(
                        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
                if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
                    springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
                }
                break;
            case AtAround:
                springAdvice = new AspectJAroundAdvice(
                        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                break;
            case AtPointcut:
                if (logger.isDebugEnabled()) {
                    logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
                }
                return null;
            default:
                throw new UnsupportedOperationException(
                        "Unsupported advice type on method: " + candidateAdviceMethod);
        }

        // Now to configure the advice...
        springAdvice.setAspectName(aspectName);
        springAdvice.setDeclarationOrder(declarationOrder);
        String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
        if (argNames != null) {
            springAdvice.setArgumentNamesFromStringArray(argNames);
        }
        springAdvice.calculateArgumentBindings();
        return springAdvice;
    }

JDK动态代理AOP

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        MethodInvocation invocation;
        Object oldProxy = null;
        boolean setProxyContext = false;

        TargetSource targetSource = this.advised.targetSource;
        Class<?> targetClass = null;
        Object target = null;

        try {
            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                // The target does not implement the equals(Object) method itself.
                return equals(args[0]);
            }
            else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                // The target does not implement the hashCode() method itself.
                return hashCode();
            }
            else if (method.getDeclaringClass() == DecoratingProxy.class) {
                // There is only getDecoratedClass() declared -> dispatch to proxy config.
                return AopProxyUtils.ultimateTargetClass(this.advised);
            }
            else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                    method.getDeclaringClass().isAssignableFrom(Advised.class)) {
                // Service invocations on ProxyConfig with the proxy config...
                return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
            }

            Object retVal;

            if (this.advised.exposeProxy) {
                // Make invocation available if necessary.
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }

            // May be null. Get as late as possible to minimize the time we "own" the target,
            // in case it comes from a pool.
            target = targetSource.getTarget();
            if (target != null) {
                targetClass = target.getClass();
            }

            // Get the interception chain for this method.
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

            // Check whether we have any advice. If we don't, we can fallback on direct
            // reflective invocation of the target, and avoid creating a MethodInvocation.
            if (chain.isEmpty()) {
                // We can skip creating a MethodInvocation: just invoke the target directly
                // Note that the final invoker must be an InvokerInterceptor so we know it does
                // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
            }
            else {
                // We need to create a method invocation...
                invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                // Proceed to the joinpoint through the interceptor chain.
                retVal = invocation.proceed();
            }

            // Massage return value if necessary.
            Class<?> returnType = method.getReturnType();
            if (retVal != null && retVal == target &&
                    returnType != Object.class && returnType.isInstance(proxy) &&
                    !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                // Special case: it returned "this" and the return type of the method
                // is type-compatible. Note that we can't help if the target sets
                // a reference to itself in another returned object.
                retVal = proxy;
            }
            else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
                throw new AopInvocationException(
                        "Null return value from advice does not match primitive return type for: " + method);
            }
            return retVal;
        }
        finally {
            if (target != null && !targetSource.isStatic()) {
                // Must have come from TargetSource.
                targetSource.releaseTarget(target);
            }
            if (setProxyContext) {
                // Restore old proxy.
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }

相关文章

网友评论

      本文标题:第七章 AOP

      本文链接:https://www.haomeiwen.com/subject/bzssgqtx.html