• Spring AOP使用与原理


    AOP介绍

    SpringAOP核心概念
    上述中已经出现的关键词有Advice(顶级的通知类/拦截器)、MethodInvocation(方法连接点)、MethodInterceptor(方法拦截器)
    SpringAOP在此基础上又增加了几个类,丰富了AOP定义及使用概念,包括
    Advisor:包含通知(拦截器),Spring内部使用的AOP顶级接口,还需要包含一个aop适用判断的过滤器,考虑到通用性,过滤规则由其子接口定义,例如IntroductionAdvisor和PointcutAdvisor,过滤器用于判断bean是否需要被代理
    Pointcut: 切点,属于过滤器的一种实现,匹配过滤哪些类哪些方法需要被切面处理,包含一个ClassFilter和一个MethodMatcher,使用PointcutAdvisor定义时需要
    ClassFilter:限制切入点或引入点与给定目标类集的匹配的筛选器,属于过滤器的一种实现。过滤筛选合适的类,有些类不需要被处理
    MethodMatcher:方法匹配器,定义方法匹配规则,属于过滤器的一种实现,哪些方法需要使用AOP

    AOP使用方法

    配置Advisor

    这一步对SpringAOP使用者很关键,决定了我们如何定义配置Advisor,即SpringAOP和Aspectj,实际使用配置AOP方式有多种,还区分xml和注解,最终转化处理时我认为只分为这两种。其中Aspectj方式配置AOP应该是最常见应用最广泛的用法了。

    前面提到Aspectj是一种静态代理,而SpringAOP是动态代理。但Aspectj的一套定义AOP的API非常好,直观易用。所以Spring引入了Aspectj,但只使用部分注解用来定义配置AOP,在获取Advisor阶段用来生成Advisor,与后面的代理生成和代理增强执行无关!
    最少需要定义三个类,一个Advisor的实现类,一个Advice实现类(拦截器),一个aop适配过滤器(这里使用的Advisor为派生的PointcutAdvisor ,需要定义PointCut切点)。可以增加一个注解用于AOP埋点,需要给bean哪个方法进行切面,则方法上加上该注解。
    Advisor:MyAdvisor,返回一个Advice,
    Advice:MyInterceptAdvice,拦截器,invoke方法中可以添加切面逻辑代码
    PointCut: MyPointCut,切点,匹配过滤出需要切面的类及方法,查找方法头注解了MyAnnotation的方法。
    埋点注解:MyAnnotation
    MyAdvisor.java

    @Component
    public class MyAdvisor implements PointcutAdvisor {
    
        @Override
        public Advice getAdvice() {
            return new MyInterceptAdvice();
        }
    
        @Override
        public boolean isPerInstance() {
            return false;
        }
    
        @Override
        public Pointcut getPointcut() {
            return new MyPointCut();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    MyInterceptAdvice.java

    public class MyInterceptAdvice implements MethodInterceptor {
    
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            System.out.println("go go go MyAdvisor process!!!");
            return invocation.proceed();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    MyPointCut.java

    public class MyPointCut implements Pointcut {
    
        @Override
        public ClassFilter getClassFilter() {
            return new MyClassFilter();
        }
    
        @Override
        public MethodMatcher getMethodMatcher() {
            return new MyMethodMatcher();
        }
    
        private class MyMethodMatcher implements MethodMatcher {
            @Override
            public boolean matches(Method method, Class<?> targetClass) {
                Annotation[] annoArray = method.getDeclaredAnnotations();
                if (annoArray == null || annoArray.length == 0) {
                    return false;
                }
    
                for (Annotation annotation : annoArray) {
                    if (annotation.annotationType() == MyAnnotation.class) {
                        return true;
                    }
                }
                return false;
            }
    
            @Override
            public boolean isRuntime() {
                return false;
            }
    
            @Override
            public boolean matches(Method method, Class<?> targetClass, Object... args) {
                return false;
            }
        }
    
        private class MyClassFilter implements ClassFilter {
    
            @Override
            public boolean matches(Class<?> clazz) {
                return AnnotationUtils.isCandidateClass(clazz, MyAnnotation.class);
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    再定义一个测试类

    @Component
    public class TestService {
    
        @MyAnnotation
        public void test() {
            System.out.println("test!");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    运行方法测试发现aop生效

    使用Aspectj间接配置Advisor

    一个类就可以了,定义切点和增强方法

    @Aspect
    @Component
    public class AopConfig {
    
        @Pointcut("execution(* cn.nec.aop.cnnecaop.service.*.*(..))")
        public void pointCut() {}
      
        @Around("pointCut()")
        public Object around(ProceedingJoinPoint joinPoin) {
            System.out.println("go go go MyAspectJ process!!!");
            Object obj = null;
            try {
                obj = joinPoin.proceed();
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
    
            return obj;
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    注解的形式,实际上最终还是被封装成Advice接口

    注解AOP的几个执行时机

    • @Before
      • 前置通知:目标方法之前执行
    • MethodBeforeAdviceInterceptor
    @Override
    	public Object invoke(MethodInvocation mi) throws Throwable {
    		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
    		return mi.proceed();
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • @After
      • 后置通知:目标方法之后执行(始终执行)
    • AspectJAfterAdvice
    @Override
    	public Object invoke(MethodInvocation mi) throws Throwable {
    		try {
    			return mi.proceed();
    		}
    		finally {
    			invokeAdviceMethod(getJoinPointMatch(), null, null);
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • @AfterReturning
      • 返回通知:执行方法结束前执行(异常不执行)
      • AfterReturningAdviceInterceptor
    	@Override
    	public Object invoke(MethodInvocation mi) throws Throwable {
    		Object retVal = mi.proceed();
    		this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
    		return retVal;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • @AfterThrowing
      • 异常通知:出现异常的时候执行
      • AspectJAfterThrowingAdvice
    @Override
    	public Object invoke(MethodInvocation mi) throws Throwable {
    		try {
    			return mi.proceed();
    		}
    		catch (Throwable ex) {
    			if (shouldInvokeOnThrowing(ex)) {
    				invokeAdviceMethod(getJoinPointMatch(), null, ex);
    			}
    			throw ex;
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • @Around
      • 环绕通知:环绕目标方法执行(执行前后都在一个方法中自定义)
      • AspectJAroundAdvice
    	@Override
    	public Object invoke(MethodInvocation mi) throws Throwable {
    		if (!(mi instanceof ProxyMethodInvocation)) {
    			throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
    		}
    		ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
    		ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
    		JoinPointMatch jpm = getJoinPointMatch(pmi);
    		return invokeAdviceMethod(pjp, jpm, null, null);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    around方法中,不会有自动执行process的逻辑。因此,需要在自己定义的方法中自行执行

    AOP原理分析

    AOP入口

    SpringAOP是对bean的一种扩展,是后处理器的一种处理。Spring bean在 执行初始化方法前后,会使用所有BeanPostProcessor对bean进行特殊处理。Aop代理即是一种对bean特殊处理。

    protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
       if (System.getSecurityManager() != null) {
          AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
             invokeAwareMethods(beanName, bean);
             return null;
          }, getAccessControlContext());
       }
       else {
          invokeAwareMethods(beanName, bean);
       }
    
       Object wrappedBean = bean;
       if (mbd == null || !mbd.isSynthetic()) {
          wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
       }
    
       try {
          invokeInitMethods(beanName, wrappedBean, mbd);
       }
       catch (Throwable ex) {
          throw new BeanCreationException(
                (mbd != null ? mbd.getResourceDescription() : null),
                beanName, "Invocation of init method failed", ex);
       }
       if (mbd == null || !mbd.isSynthetic()) {
          wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
       }
    
       return wrappedBean;
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    此时用于代理的BeanPostProcessor登场,对需要代理的bean进行代理
    对应的BeanPostProcessor为AbstractAutoProxyCreator的子类,执行AbstractAutoProxyCreator.postProcessAfterInitialization()。

    @Override
    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    	if (bean != null) {
    		Object cacheKey = getCacheKey(bean.getClass(), beanName);
    		if (this.earlyProxyReferences.remove(cacheKey) != bean) {
    			return wrapIfNecessary(bean, beanName, cacheKey);
    		}
    	}
    	return bean;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    earlyProxyReferences中存放的是循环依赖提前暴露bean生成的代理
    注意!如果earlyProxyReferences已经存在了这个bean,代表该bean已经被提前暴露生成过了代理,那么不再进行重复代理!
    紧接着进入wrapIfNecessary

    
    /**
     * Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
     * @param bean the raw bean instance
     * @param beanName the name of the bean
     * @param cacheKey the cache key for metadata access
     * @return a proxy wrapping the bean, or the raw bean instance as-is
     */
    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    	if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
    		return bean;
    	}
        //advisedBeans的对应value为fasle,则代表不需要代理
    	if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
    		return bean;
    	}
           //对于本身就是advisorBean和需要跳过的bean不进行代理
    	if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
    		this.advisedBeans.put(cacheKey, Boolean.FALSE);
    		return bean;
    	}
    
    	// Create proxy if we have advice.
    	// 获取拦截器,及Advisor,看样子也可以获取Advice!
    	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;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    可以看到代理生成分了两步,获取AdvicesAndAdvisors,然后生成代理对象
    在这里插入图片描述
    getAdvicesAndAdvisorsForBean方法

    @Override
    	@Nullable
    	protected Object[] getAdvicesAndAdvisorsForBean(
    			Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
    
    		List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
    		if (advisors.isEmpty()) {
    			return DO_NOT_PROXY;
    		}
    		return advisors.toArray();
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    	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;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    获取所有的Advisor

    findCandidateAdvisors用于获取所有的Advisor,默认获取直接配置的Advisor。即实现了Advisor的所有bean。

    advisors.add(this.beanFactory.getBean(name, Advisor.class));
    
    • 1

    AnnotationAwareAspectJAutoProxyCreator重写了findCandidateAdvisors,不仅可以获取直接配置得Advisor,还可以获取用AspectJ间接定义的Advisor,即把AspectJ定义的bean转化为Advisor。
    所以使用AnnotationAwareAspectJAutoProxyCreator可以同时支持两种配置AOP方式!

    获取AspectJ注解间接定义的Advisor

    if (this.advisorFactory.isAspect(beanType)) {
          aspectNames.add(beanName);
          AspectMetadata amd = new AspectMetadata(beanType, beanName);
          if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
             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));
          }
       }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    查找过滤合适的Advisor

    findAdvisorsThatCanApply用于查找可用的Advisor,遍历所有的Advisor,使用Advisor的PointCut执行匹配方法,对bean Class的方法挨个进行匹配,能匹配到说明该Advisor合格,加入到返回结果中,这里只展示了其中一种切点的处理逻辑–PointcutAdvisor。

    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;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    分别根据每个advisor pointCut的classFilter和MyMethodMatcher进行匹配。

    过滤规则扩展

    直接实现Advisor,和实现Advisor的扩展接口有什么区别?
    Advisor是顶级接口,其实器残缺的,没有给出过滤匹配的方式
    扩展接口IntroductionAdvisor和PointcutAdvisor。

    Advisor没有过滤匹配规则,会匹配所有bean(不包含特殊bean)
    IntroductionAdvisor给出了class类型过滤方式,会匹配限定类型的bean
    PointcutAdvisor给出了class类型+方法匹配过滤方式,会匹配限定类型限定方法的bean。

    显然PointcutAdvisor功能最强大,适用性和实用性最强

    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;
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    对于Aspect扩展

    	extendAdvisors(eligibleAdvisors);
    
    • 1
    @Override
    	protected void extendAdvisors(List<Advisor> candidateAdvisors) {
    		AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
    	}
    
    • 1
    • 2
    • 3
    • 4
    public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
    		// Don't add advisors to an empty list; may indicate that proxying is just not required
    		if (!advisors.isEmpty()) {
    			boolean foundAspectJAdvice = false;
    			for (Advisor advisor : advisors) {
    				// Be careful not to get the Advice without a guard, as this might eagerly
    				// instantiate a non-singleton AspectJ aspect...
    				if (isAspectJAdvice(advisor)) {
    					foundAspectJAdvice = true;
    					break;
    				}
    			}
    			if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
    				advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
    				return true;
    			}
    		}
    		return false;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    如果是sAspectJAdvice,那么添加一个advisor,ExposeInvocationInterceptor这个的用处后面看

    生成代理对象及代理执行

    使用可用的Advisor和当前bean对象生成动态代理对象

    	if (specificInterceptors != DO_NOT_PROXY) {
            //代码当前bean被代理
    			this.advisedBeans.put(cacheKey, Boolean.TRUE);
    			Object proxy = createProxy(
    					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
    			this.proxyTypes.put(cacheKey, proxy.getClass());
    			return proxy;
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    ProxyFactory proxyFactory = new ProxyFactory();
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    proxyFactory.getProxy(getProxyClassLoader());createAopProxy().getProxy(classLoader);
    
    
    • 1
    • 2
    • 3
    • 4

    createAopProxy用于创建代理类,进入源码可以看到支持两种代理方式,其中JDK动态代理需要bean实现接口。

    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
       if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
          Class<?> targetClass = config.getTargetClass();
          if (targetClass == null) {
             throw new AopConfigException("TargetSource cannot determine target class: " +
                   "Either an interface or a target is required for proxy creation.");
          }
          if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
             return new JdkDynamicAopProxy(config);
          }
          return new ObjenesisCglibAopProxy(config);
       }
       else {
          return new JdkDynamicAopProxy(config);
       }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    注意这里有有个坑,不能仅仅看类是否有继承接口,还要看一个配置
    proxyTargetClass
    true
    目标对象实现了接口 – 使用CGLIB代理机制
    目标对象没有接口(只有实现类) – 使用CGLIB代理机制
    false
    目标对象实现了接口 – 使用JDK动态代理机制(代理所有实现了的接口)
    目标对象没有接口(只有实现类) – 使用CGLIB代理机制
    在这里插入图片描述

    可见如果proxyTargetClass是true,那么不管什么类都会使用cglib代理,只有目标类本身就接口/代理类才会使用jdk代理
    在这里插入图片描述

    JDK动态代理

    public Object getProxy(@Nullable ClassLoader classLoader) {
       if (logger.isTraceEnabled()) {
          logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
       }
       Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
       findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
       return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    是不是熟悉了,和手动定义JDK动态代理一样,对于jdk动态代理的拦截器InvocationHandler就是其本身
    核心就是
    Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, invocationHandler)。
    再来看看核心方法invoke

    // 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...
       MethodInvocation invocation =
             new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
       // Proceed to the joinpoint through the interceptor chain.
       retVal = invocation.proceed();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    从Advisor中获取拦截器,然后生成一个连接点(ReflectiveMethodInvocation),包含链接器和代理信息,执行连接点的proceed方法,会链式调用拦截器,执行所有的切面代码。

    public Object proceed() throws Throwable {
       // We start with an index of -1 and increment early.
       if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
          return invokeJoinpoint();
       }
    
       Object interceptorOrInterceptionAdvice =
             this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
       if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
          // Evaluate dynamic method matcher here: static part will already have
          // been evaluated and found to match.
          InterceptorAndDynamicMethodMatcher dm =
                (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
          Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
          if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
             return dm.interceptor.invoke(this);
          }
          else {
             // Dynamic matching failed.
             // Skip this interceptor and invoke the next in the chain.
             return proceed();
          }
       }
       else {
          // It's an interceptor, so we just invoke it: The pointcut will have
          // been evaluated statically before this object was constructed.
          return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
       }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
     @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            System.out.println("go go go MyAdvisor process!!!");
            return invocation.proceed();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    切面执行完毕后会继续调用ReflectiveMethodInvocation的invoke方法,currentInterceptorIndex自增,执行匹配到的Advice,执行完毕执行invokeJoinpoint方法

    注意点

    jdk代理是对接口做的代理,匹配advice时,时根据接口
    例如根据注解匹配,注解值放在子类上时无效的,需要放到接口上
    例如

    public interface ITestService {
         @MyAnnotation
         void test();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    ExposeInvocationInterceptor的作用是什么

    我们前面知道了,如果有注解间接定义的advisor,那么会添加一个ExposeInvocationInterceptor到首位
    第一个执行的拦截器就会是ExposeInvocationInterceptor
    从英文名字,顾名思义,暴露调用器的拦截器。
    其就是起了暴露一个调用器作用的拦截器。
    1、那么其暴露了什么调用器?
    2、是如何暴露的,通过什么方法实现?
    3、暴露给谁?
    4、在什么时候起到拦截作用?
    调用链首先调用此ExposeInvocationInterceptor拦截器的invoke方法,将MethodInvocation mi 设置到
    ThreadLocal invocation 里面

    @Override
    	public Object invoke(MethodInvocation mi) throws Throwable {
    		MethodInvocation oldInvocation = invocation.get();
    		invocation.set(mi);
    		try {
    			return mi.proceed();
    		}
    		finally {
    			invocation.set(oldInvocation);
    		}
    	}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    至于为什么要把MethodInvocation塞到threadLocal中 invocation中
    是因为通过注解@Aspectj定义的advise执行时,其对应的接口没有MethodInvocation这个参数
    例如前置执行器

    @Override
    	public Object invoke(MethodInvocation mi) throws Throwable {
    		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
    		return mi.proceed();
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    	void before(Method method, Object[] args, @Nullable Object target) throws Throwable;
    
    • 1

    但是又需要使用,因此需要使用threadLocal进行传递

    @Override
    	public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
    		invokeAdviceMethod(getJoinPointMatch(), null, null);
    	}
    
    • 1
    • 2
    • 3
    • 4
    @Nullable
    	protected JoinPointMatch getJoinPointMatch() {
    		MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
    		if (!(mi instanceof ProxyMethodInvocation)) {
    			throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
    		}
    		return getJoinPointMatch((ProxyMethodInvocation) mi);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    那么获取joinpoint是为了干什么
    例如有一个前置执行方法

      @Before(value = "execution(public * test(int)) && args(a)")
        public void before(JoinPoint joinPoint,int a){
            System.out.println("------------------hello 方法执行前-------------------");
        }
    
    • 1
    • 2
    • 3
    • 4

    需要传参,joinPoint就是从MethodInvocation中获取

    CGLIB动态代理类

    	Enhancer enhancer = createEnhancer();
    			if (classLoader != null) {
    				enhancer.setClassLoader(classLoader);
    				if (classLoader instanceof SmartClassLoader &&
    						((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
    					enhancer.setUseCache(false);
    				}
    			}
    			enhancer.setSuperclass(proxySuperClass);
    			enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
    			enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
    			enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
    
    			Callback[] callbacks = getCallbacks(rootClass);
    			Class<?>[] types = new Class<?>[callbacks.length];
    			for (int x = 0; x < types.length; x++) {
    				types[x] = callbacks[x].getClass();
    			}
    			// fixedInterceptorMap only populated at this point, after getCallbacks call above
    			enhancer.setCallbackFilter(new ProxyCallbackFilter(
    					this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
    			enhancer.setCallbackTypes(types);
    
    			// Generate the proxy class and create a proxy instance.
    			return createProxyClassAndInstance(enhancer, callbacks);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    与jdk自然不同,用的是cglib创建代理的方式
    生效的callback可能有多个,这里看 DynamicUnadvisedInterceptor

    	@Override
    		@Nullable
    		public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    			Object oldProxy = null;
    			boolean setProxyContext = false;
    			Object target = null;
    			TargetSource targetSource = this.advised.getTargetSource();
    			try {
    				if (this.advised.exposeProxy) {
    					// Make invocation available if necessary.
    					oldProxy = AopContext.setCurrentProxy(proxy);
    					setProxyContext = true;
    				}
    				// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
    				target = targetSource.getTarget();
    				Class<?> targetClass = (target != null ? target.getClass() : null);
    				List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    				Object retVal;
    				// Check whether we only have one InvokerInterceptor: that is,
    				// no real advice, but just reflective invocation of the target.
    				if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
    					// 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 = methodProxy.invoke(target, argsToUse);
    				}
    				else {
    					// We need to create a method invocation...
    					retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
    				}
    				retVal = processReturnType(proxy, target, method, retVal);
    				return retVal;
    			}
    			finally {
    				if (target != null && !targetSource.isStatic()) {
    					targetSource.releaseTarget(target);
    				}
    				if (setProxyContext) {
    					// Restore old proxy.
    					AopContext.setCurrentProxy(oldProxy);
    				}
    			}
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    执行proceed的流程与jdk的流程基本相同。
    执行时生成的连接点为CglibMethodInvocation,是JDK动态代理连接点ReflectiveMethodInvocation的子类,执行的还是ReflectiveMethodInvocation的proceed方法

  • 相关阅读:
    【分享】如何自动同步企业微信外部客户信息到CRM系统?
    Web信息收集,互联网上的裸奔者
    神经网络滤镜使用技巧图,神经滤镜为什么不能用
    Netty入门案例 与 Netty异步模型
    Prometheus接入AlterManager配置邮件告警(基于K8S环境部署)
    史上最全的Java进阶书籍推荐
    安卓日志输出-logger
    漏刻有时数据可视化Echarts组件开发(26):全国地图三级热力图下钻和对接api自动调用数据开发实录
    数据在内存中的存储(原反补码、大小端、浮点数)
    HylicOS --- 环境搭建 与 环境测试(巨多坑)
  • 原文地址:https://blog.csdn.net/qq_37436172/article/details/127950656