专栏首页码猿技术专栏一文搞懂Spring-AOP原理

一文搞懂Spring-AOP原理

文章目录

1. 简介

2. 添加依赖

3. 通知

4. 连接点

5. 切点

6. 切面

7. 实现

8. 注解的实现

9. 切入点表达式

10. 切面执行顺序(Order)

10.1. 注意点

11. Aspect实例化模型

12. 获取参数(args)

13. PointCut

14. PointCuts

15. ClassFilter

16. ClassFilters

17. MethodMatcher

18. MethodMatchers

19. Advice

20. Advisor

20.1. PointcutAdvisor

21. proxyFactory

21.1. 示例

22. @EnableAspectJAutoProxy

23. AspectJAutoProxyRegistrar

24. AnnotationAutoProxyCreator

25. BeanFactoryAspectJAdvisorsBuilder

26. AspectJAdvisorFactory

27. JdkDynamicAopProxy

28. MethodInterceptor

28.1. AspectJAfterAdvice【示例】

29. MethodInvocation

29.1. ReflectiveMethodInvocation

30. JDK动态代理示例

31. AOP创建代理流程

32. AOP执行流程

简介

  • 面向切面编程,是面向对象编程的重要组成部分,在不改变业务逻辑功能的基础上,对横切逻辑进行扩展

添加依赖

<dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-aspects</artifactId>
     <version>5.1.5.RELEASE</version>
   </dependency>

通知

  • @Before(前置通知):在业务方法执行之前调用
  • @After(后置通知):在方法之后执行
  • @AfterReturning(正常返回通知):在方法之后执行,只有在业务方法没有出现异常的时候才会执行
  • @AfterThrowing(异常通知) : 在方法之后执行,只有在业务方法出现异常的时候才会执行
  • @Around (环绕通知):在业务方法执行之前和之后执行

连接点

  • 业务层的所有方法,叫做连接点
  • 业务类中可以被增强的方法都叫做连接点

切点

  • 能切入切面逻辑的方法,叫做切点
  • 实际被增强的方法叫做切入点 ,其他的那些没有被增强的方法(连接点)不是切点

切面

  • 定义了增强方法的类就叫做切面

实现

  • 在配置类上开启切面,使用@EnableAspectJAutoProxy
@Configuration
@ComponentScan(value = {"cn.tedu.demo"})
@EnableAsync
@EnableAspectJAutoProxy
public class FirstConfig {}
  • 使用五个不同的通知完成切入:
/**
 * 切面,使用@Aspect标注
 */
@Component
@Aspect
public class CustomAspect {

    /**
     * 使用@PointCut定义切入点
     */
    @Pointcut(value = "execution(* cn.tedu.demo.aspect.AspectInvok.invok(..))")
    public void pointCut(){}

    /**
     * 前置通知,在指定方法之前执行
     * @param point JoinPoint对象,可以获取切点的各种属性,比如入参的参数等
     */
    @Before(value = "pointCut()")
    public void before(JoinPoint point){
        //获取入参的参数的值
        Object[] args = point.getArgs();
        System.out.println(Arrays.asList(args));
        //获取MethodSignature,其中可以获取切点的各种属性,比如方法返回类型,参数等等
        MethodSignature signature = (MethodSignature) point.getSignature();
        String[] parameterNames = signature.getParameterNames();
        System.out.println(Arrays.asList(parameterNames));
        System.out.println("在方法之前执行");
    }

    /**
     * 在切点之后执行
     * @param point JoinPoint对象
     */
    @After(value = "pointCut()",argNames = "point")
    public void after(JoinPoint point){
        System.out.println("在方法之后执行");
    }

    /**
     * 在方法前后都会执行
     * @param point
     */
    @Around(value = "pointCut()")
    public void around(ProceedingJoinPoint point) throws Throwable {
        System.out.println("前置执行");
        //执行方法,可以获取返回值,否则方法将不会执行
        Object result = point.proceed(point.getArgs());
        System.out.println("后置执行,执行的结果=="+result);
    }

    /**
     * 正常返回通知,
     * @param point Joinpoint对象
     * @param result 方法执行返回的结果,需要和@AfterReturning注解中returning中的属性值相同,否则不能自动装配
     */
    @AfterReturning(value = "pointCut()",returning = "result")
    public void afterReturning(JoinPoint point,Object result){
        System.out.println("正常返回执行,执行的结果为:"+result);
    }

    /**
     * 异常返回执行,程序出现异常了才会执行
     * @param point
     * @param ex 切入点执行抛出的异常,需要和@AfterThrowing注解的throwing值相同,否则不能完成自动装配
     */
    @AfterThrowing(value = "pointCut()",throwing = "ex")
    public void afterThrowing(JoinPoint point,Exception ex){
        System.out.println("异常返回执行,执行的异常为:"+ex);
    }
}

注解的实现

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation {
    String name() default "陈加兵";
    int age() default 22;
}
  • 定义一个切面,使用注解如下:
@Component
@Aspect
public class CustomAspect {
    /**
     * 使用@PointCut定义切入点
     */
    @Pointcut(value = "@annotation(cn.tedu.demo.aspect.MyAnnotation)")
    public void pointCut(){}
    /**
     * 前置通知,在指定方法之前执行
     * @param point JoinPoint对象,可以获取切点的各种属性,比如入参的参数等
     */
    @Before(value = "pointCut()")
    public void before(JoinPoint point){
        //获取MethodSignature,其中可以获取切点的各种属性,比如方法返回类型,参数等等
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        //获取方法上指定的注解
        MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
        System.out.println("name="+myAnnotation.name());
        System.out.println("在方法之前执行");
    }
}

切入点表达式

  • 两个或者三个切入点,可以使用切入点表达式,比如||&&!
  • 如下我们定义两个切入点:
@Pointcut("execution(* cn.tedu.demo.service.UserService.addUser(..))")
   public void pointCut1(){}

   @Pointcut("execution(* cn.tedu.demo.service.UserService.deleteUserById(..))")
   public void pointCut2(){}
  • 我们使用表达式来定义第三个切入点
    • @Pointcut("pointCut1()||pointCut2()"):两个切入点只要满足其中一个就能匹配
    • @Pointcut("pointCut1()&&pointCut2()"):两个切入点必须全部满足才能匹配
    • @Pointcut("!pointCut1()&&pointCut2()"):不满足PointCut1并且满足pointCut2才能匹配

切面执行顺序(Order)

  • 如果有多个切面匹配了同一个目标方法,那么切面如何执行,我们可以使用@Order指定的切入点的执行顺序,注意:@Order中的值越小优先级越高
@Aspect
@Component
@Order(Ordered.LOWEST_PRECEDENCE-1)
public class LogAspect {
    
 @Aspect
@Component
@Order(Ordered.HIGHEST_PRECEDENCE-2)
public class LogAspect2 {

注意点

  • 事务也是的一个切面,那么事务的优先级和自定义的切面优先级有什么关系呢?
    • 如果自定义事务的优先级比事务的优先级高,那么在动态代理的时候,获取的拦截器链就在事务的拦截器(TransactionInterceptor)之前,此时切面执行的逻辑和目标方法就不在同一个事务中
    • 默认的事务的优先级是最低的,因此切面使用默认的是能够保证在同一个事务中执行的。
    • 事务的优先级可以在@EnableTransactionManagement这个注解中设置
    • 如果切面指定了优先级,但是还要保证和目标方法在同一个事务中,那么必须调整事务的优先级比自定义切面的优先级高。
  • 如何知道事务的优先级?
    • ProxyTransactionManagementConfiguration配置类中注入BeanFactoryTransactionAttributeSourceAdvisor会获取EnableTransactionManagement注解中的order值作为优先级
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		advisor.setTransactionAttributeSource(transactionAttributeSource());
		advisor.setAdvice(transactionInterceptor());
        //如果注解中的属性不为空
		if (this.enableTx != null) {
            //直接设置order的值
			advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
		}
		return advisor;
	}
  • 拦截器如果根据优先级排序?
    • 在创建代理对象的时候,会获取适用于当前Bean的所有Advisor,之后会根据优先级进行排序
    • 在JDK获取拦截器链的时候实际就是循环便利ProxyFactory中存储的Advisor,将其中的Advice转换为MethodInterceptor,因此这个拦截器也是按照Advisor的顺序。
//org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisors
//获取适用于当前bean的所有Advisor
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    	//获取候选Advisor
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
    	//获取能够适用于的当前Bean的advisor
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
            //对advisor排序
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}


//org.springframework.aop.framework.DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice
//直接获取ProxyFactory中的Advisor,循环遍历将其中的advice转换为MethodInterceptor
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
			Advised config, Method method, @Nullable Class<?> targetClass) {

		// This is somewhat tricky... We have to process introductions first,
		// but we need to preserve order in the ultimate list.
		AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
		Advisor[] advisors = config.getAdvisors();
		List<Object> interceptorList = new ArrayList<>(advisors.length);
		Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
		Boolean hasIntroductions = null;

		for (Advisor advisor : advisors) {
			if (advisor instanceof PointcutAdvisor) {
				// Add it conditionally.
				PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
				if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
					MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
					boolean match;
					if (mm instanceof IntroductionAwareMethodMatcher) {
						if (hasIntroductions == null) {
							hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
						}
						match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
					}
					else {
						match = mm.matches(method, actualClass);
					}
					if (match) {
						MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
						if (mm.isRuntime()) {
							// Creating a new object instance in the getInterceptors() method
							// isn't a problem as we normally cache created chains.
							for (MethodInterceptor interceptor : interceptors) {
								interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
							}
						}
						else {
							interceptorList.addAll(Arrays.asList(interceptors));
						}
					}
				}
			}
			else if (advisor instanceof IntroductionAdvisor) {
				IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
				if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
					Interceptor[] interceptors = registry.getInterceptors(advisor);
					interceptorList.addAll(Arrays.asList(interceptors));
				}
			}
			else {
				Interceptor[] interceptors = registry.getInterceptors(advisor);
				interceptorList.addAll(Arrays.asList(interceptors));
			}
		}

		return interceptorList;
	}

Aspect实例化模型

获取参数(args)

  • 在这之前如果我们想要获取目标方法的参数,我们常用的手段就是通过JoinPoint的API直接获取的,如下:
MethodSignature signature = (MethodSignature) point.getSignature();
String[] parameters = signature.getParameterNames();
  • 但是我们也是可以通过args将入参绑定,如下:
    • 此时的args中的user就和通知方法中的user绑定了,spring会自动获取目标方法中的参数user为其绑定值
    • 注意:args中此时只指定了一个参数User,也就是意味着目标方法只能是带有User对象这一个参数的方法才能匹配,如果有其他的参数,那么这个通知将不起作用
@Before(value = "pointCut1()&&args(user)")
    public void before(JoinPoint point,User user){
  • 我们可以使用的args指定一个或者多个参数,如:args(user,..),此时匹配的目标方法中至少包含一个参数User对象才能匹配。

PointCut

  • PointCut这个接口有两部分组成,分别是ClassFilterMethodMatcher,其实可以很好的理解,如何定义一个切入点?我们在定义切入点的时候,就是想对某一个类的全部方法,或者对某一个类的部方法进行切入,因此在判断能否作用到方法上的时候,先判断是否类能够匹配(ClassFilter的活),之后再判断方法是否匹配(MethodMatcher的活)。
  • PointCut的实现类有很多,其中比较重要的是AOP使用的AspectJExpressionPointcut【这个类主要是解析execution表达式的,这个类同时实现了ClassFilter和MethodMatcher,具备了两者的功能,因此可以直接使用该类进行切入点的匹配】、AnnotationMatchingPointcut【注解的PointCut,主要用来匹配注解,底层使用就是AnnotationMethodMatcherAnnotationMethodClassFilter,后续会讲到】
  • 源码如下:
public interface Pointcut {
	//返回一个ClassFilter
	ClassFilter getClassFilter();
	//返回一个MethodMatcher
	MethodMatcher getMethodMatcher();
	//TruePointCut,对应任何的方法都是匹配(总是匹配)
	Pointcut TRUE = TruePointcut.INSTANCE;
}
  • AspectJExpressionPointcut演示如下:
@Test
 public void testAspectJExpressionPointCut() throws NoSuchMethodException {
     AspectJExpressionPointcut expressionPointcut = new AspectJExpressionPointcut();
     //设置aspectj表达式,这个比较常用的表达式
     expressionPointcut.setExpression("execution(* cn.tedu.demo.service.UserService.addUser(..))");
     //匹配类
     boolean b = expressionPointcut.matches(UserService.class);
     //直接调用matches匹配方法
     boolean a = expressionPointcut.matches(UserService.class.getDeclaredMethod("addUser", User.class), UserService.class);
     System.out.println(a+"--->"+b);
 }
  • AnnotationMatchingPointcut的演示如下:
@Test
public void testAnnotationMatchingPointcut() throws NoSuchMethodException {
    //第一个参数是注解,第二参数表示是否在接口和父类的查找该注解
    AnnotationMatchingPointcut pointcut = new AnnotationMatchingPointcut(Transactional.class, false);
    //匹配方法上是否有@Transactional注解
    boolean a = pointcut.getMethodMatcher().matches(UserService.class.getDeclaredMethod("addUser", User.class), UserService.class);
    //匹配类上是否有@Transactional注解
    boolean b = pointcut.getClassFilter().matches(UserService.class);
    System.out.println(a+"--->"+b);
}

PointCuts

  • 类似于MethodMatchers和ClassFilters,其中同样有union等,作用就是提供了一个matches方法,不需要自己写步骤先比较Class,再比较Method等操作,当然还有一些便捷的功能。
@Test
public void testPointcuts() throws NoSuchMethodException {
    AnnotationMatchingPointcut annotationMatchingPointcut = new AnnotationMatchingPointcut(Transactional.class, false);
    Class cls=UserService.class;
    Method method = cls.getDeclaredMethod("addUser", User.class);
    //调用matches方法,判断UserService的addUser方法是否有@Transactional注解
    boolean matches = Pointcuts.matches(annotationMatchingPointcut, method, cls);
    System.out.println(matches);
}
  • 类过滤器,就是判断类是否匹配
@FunctionalInterface
public interface ClassFilter {

	//判断方法
	boolean matches(Class<?> clazz);
	
    //定义一个总是匹配的TrueClassFilter,其实就是matches方法总是返回true
	ClassFilter TRUE = TrueClassFilter.INSTANCE;

}
  • ClassFilter在spring底层有许多实现的类,比如AnnotationClassFilter(匹配指定注解)、TrueClassFilter(全部匹配)、AspectJExpressionPointcut(Aspect表达式匹配,APO重要的组件)
  • 实例:使用AnnotationClassFilter测试该类是否有@Transactional注解
    • 该类有一个属性checkInherited,如果为false,那么只检查当前类是否有对应的注解,为true,那么会检查父类或者实现的接口存在,默认为false
@Test
public void testAnnotationClassFilter(){
    //指定checkInherited为true,会同时检查该类和父类及其实现的接口是否存在Transactional注解
    AnnotationClassFilter annotationClassFilter = new AnnotationClassFilter(Transactional.class, true);
    boolean matches = annotationClassFilter.matches(UserServiceImpl.class);
    System.out.println(matches);
   
}
  • 我们也可以自定义自己的ClassFilter, 只需要实现其中的接口方法即可,如下:
@Test
public void testCustomClassFilter(){
    //自定义一个classFilter,判断指定的类是否是UserServiceImpl的接口或者父类或者同类
    ClassFilter customFilter =cls-> cls.isAssignableFrom(UserServiceImpl.class);
    boolean matches = customFilter.matches(UserService.class);
    System.out.println(matches);
}

ClassFilters

  • 该抽象类中有两个ClassFilter,分别是UnionClassFilter【满足其中一个即返回true】、IntersectionClassFilter【必须满足所有的ClassFilter才返回true】
  • 同样的对应有两个静态方法上面的两个Filter,如下:
    • public static ClassFilter union(ClassFilter cf1, ClassFilter cf2)
    • public static ClassFilter intersection(ClassFilter cf1, ClassFilter cf2)
  • 实例
@Test
    public void testClassFilters(){
        //类或者接口上必须有Transactional注解
        AnnotationClassFilter annotationClassFilter = new AnnotationClassFilter(Transactional.class,false);
        //类或者接口必须是UserServiceImpl的父类或者接口或者同类
        ClassFilter customFilter =cls-> cls.isAssignableFrom(UserServiceImpl.class);
        //返回unionFilter,只要满足上面的一个ClassFilter即返回true
        ClassFilter unionFilter = ClassFilters.union(annotationClassFilter, customFilter);
        //返回intersectionFilter,必须满足上面两个ClassFilter才会返回true
        ClassFilter intersectionFilter = ClassFilters.intersection(annotationClassFilter, customFilter);
        boolean u = unionFilter.matches(UserService.class);
        boolean i = intersectionFilter.matches(UserService.class);
        System.out.println(u);
        System.out.println(i);
    }

MethodMatcher

  • ClassFilter是匹配类,MethodMatcher是用来匹配方法
  • MethodMatcher有两个matches方法,分别是两个参数和三个参数的,两个参数用于静态匹配,只有两个参数的匹配返回true,isRuntime方法true,才应该调用三个参数的方法。如果isRuntime返回false,那么不应该调用三个参数的matches
  • 接口的实现类有很多,如StaticMethodMatcher【只支持静态匹配,两个参数的matchs】、AspectJExpressionPointcut【AOP重要组件】、TrueMethodMatcher【总是匹配】、AnnotationMethodMatcher【注解匹配】
  • 实例如下:
@Test
public void testAnnotationMethodMatcher() throws NoSuchMethodException {
    //检测方法上是否标注了Transactional注解,false指定了不检查当前类父类和接口
    AnnotationMethodMatcher methodMatcher=new AnnotationMethodMatcher(Transactional.class,false);
    Class cls=UserService.class;
    Method method = cls.getDeclaredMethod("addUser", User.class);
    //两个参数的mathces,三个参数的不支持【继承了StaticMethodMatcher】
    boolean matches = methodMatcher.matches(method, cls);
    System.out.println(matches);
}
  • 当然也是可以自定义实现类,这里和上面的ClassFilter的差不多,就不再写了,自己发挥想象力

MethodMatchers

  • 同ClassFilters功能一样,其中提供了UnionMethodMatcher类【只要匹配一个即返回true】,IntersectionMethodMatcher【】
  • 此处不再演示

Advice

  • 通知的接口,在aop中的每一个通知注解都有对应的接口,比如BeforeAdviceAfterAdvice
  • Advice的默认实现抽象类是AbstractAspectJAdvice,各种AspectJ的通知都会继承并拓展该类,其中封装了有关通知的全部信息,比如方法名称、方法Method对象、PointCut、Jpoint、pointCut表达式等等信息,其中最重要的一个方法就是protected Object invokeAdviceMethodWithGivenArgs(Object[] args),该方法用于调用通知方法。
  • 其中关于AspectJ的五种通知方法,类的命名方式是AspectJXxxAdvice,继承抽象类AbstractAspectJAdvice
  • 比如AspectAfterAdvice这个实现类,其中重要的方法就是invok,源码如下:
    • 通过源码就可以看出在方法之后执行是怎样的过程,先调用被增强的方法【原方法】、再调用被@After标注的通知方法。
public Object invoke(MethodInvocation mi) throws Throwable {
		try {
            //先执行被增强的方法
			return mi.proceed();
		}
		finally {
            //再执行通知方法
			invokeAdviceMethod(getJoinPointMatch(), null, null);
		}
	}

Advisor

  • 顾问的意思,其中封装了Advice(通知)。

PointcutAdvisor

  • 继承了Advisor,是对Advice和PointCut的封装
  • AspectJExpressionPointcutAdvisor:Aop中的一种Advisor,用于封装AspectJExpressionPointCut和Advice

proxyFactory

  • 代理工厂:其中保存了代理对象的一切属性,包括advisor,类的信息,接口的信息等。
  • 创建代理对象,实际调用的是org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy
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.");
			}
            //如果是接口,创建JDK的动态代理
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
            //创建Cglib动态代理
			return new JdkDynamicAopProxy(config);
		}
	}

示例

public class ProxyFactoryTest {

    /**
     * 自定义一个BeforeAdvice
     */
    public static class CustomBeforAdvice implements MethodBeforeAdvice{
        @Override
        public void before(Method method, Object[] args, Object target) throws Throwable {
            String name = method.getName();
            if (StringUtils.equals(name,"addUser")){
                System.out.println("在addUser之前执行");
            }else{
                System.out.println("other");
            }
        }
    }
    public static class Log{
        public void before(){
            System.out.println("在之前执行");
        }
    }

    @Test
    public void test1(){
        UserService userService=new UserServiceImpl();
        //创建proxyFactory
        ProxyFactory factory = new ProxyFactory(userService);
        //创建自定义的BeforeAdvice
        MethodBeforeAdvice advice=new CustomBeforAdvice();
        //将Advice添加到proxyFactory中
        factory.addAdvice(advice);
        //获取代理对象
        UserService proxy = (UserService) factory.getProxy();
        proxy.addUser(new User(""));
    }



    @Test
    public void test2() throws NoSuchMethodException {
        UserService userService=new UserServiceImpl();
        //创建proxyFactory
        ProxyFactory factory = new ProxyFactory(userService);
        Class aspectCls=Log.class;
        Method aspectMethod = aspectCls.getMethod("before");
        //构建aspectJ表达式切入点
        AspectJExpressionPointcut aspectJExpressionPointcut = new AspectJExpressionPointcut();
        aspectJExpressionPointcut.setExpression("execution(* cn.tedu.demo.service.UserService.addUser(..))");
        //创建AspectInstanceFactory(切面实例工厂)
        AspectInstanceFactory aspectInstanceFactory=new SimpleAspectInstanceFactory(aspectCls);
        AspectJMethodBeforeAdvice advice=new AspectJMethodBeforeAdvice(aspectMethod,aspectJExpressionPointcut,aspectInstanceFactory);
        //创建Advisor,其中封装了Advice和Advisor
        Advisor advisor = new AspectJPointcutAdvisor(advice);
        ArrayList<Advisor> advisors = Lists.newArrayList(advisor);
        //添加ExposeInvocationInterceptor到advisor中,这个不是必须的,但是使用AspectJ expression pointcut是必须的
        AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(advisors);
        //将advisor添加到ProxyFactory中
        factory.addAdvisors(advisors);
        UserService proxy= (UserService) factory.getProxy();
        proxy.addUser(new User("chen"));


    }
}

@EnableAspectJAutoProxy

  • @EnableAspectJAutoProxy该注解中可以看出使用了@Import(AspectJAutoProxyRegistrar.class),因此实际作用的类就是AspectJAutoProxyRegistrar
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

AspectJAutoProxyRegistrar

  • 该类实现ImportBeanDefinitionRegistrar【向容器中注入Bean】。
  • 该类的主要作用就是向ioc容器中注入AnnotationAutoProxyCreator
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

	/**
	* 向容器中注入AnnotationAutoProxyCreator
	*/
	@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		//调用方法注册AnnotationAutoProxyCreator
		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

        //获取@EnableAspectJAutoProxy注解中两个属性的值
		AnnotationAttributes enableAspectJAutoProxy =
				AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
        //判断注解属性的值
		if (enableAspectJAutoProxy != null) {
			if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
			if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
				AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
			}
		}
	}

}

AnnotationAutoProxyCreator

  • 注解版代理创建器,主要的作用就是利用SmartInstantiationAwareBeanPostProcessor后置处理器,在Bean实例化前后创建代理对象。有了后置处理器和BeanFactoryAware,可想而知,主要的实现都是从他们实现的方法进入的。
  • 继承关系如下:
  • 创建代理对象的代码如下:
    • 真正的实现在org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
      • advisedBeans:存放所有的Bean,value是Boolean类型的值,如果为false表示不需要代理,反之则需要代理

BeanFactoryAspectJAdvisorsBuilder

  • Advisor的构建器,主要的功能就是扫描的带有@Aspect注解的类,构造Advisor。
  • AbstractAdvisorAutoProxyCreator的setFactory的方法中被创建。
  • 其中最重要的方法就是buildAspectJAdvisors,用来构造Advisor

AspectJAdvisorFactory

  • Advisor工厂,主要是用来构造Advisor的,在BeanFactoryAspectJAdvisorsBuilder中被应用。
  • ReflectiveAspectJAdvisorFactory是其实现类,AOP中就是使用该类构造Advisor
  • 其中最重要的两个方法如下:
    • private List<Method> getAdvisorMethods(Class<?> aspectClass):在切面类获取没有标注@PointCut的方法
    • public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory):获取所有的Advisor

JdkDynamicAopProxy

  • JDK的动态调用的主要类,实现了AopProxy、InvocationHandler
  • 重要的属性:
    • private final AdvisedSupport advised:其中封装了代理类的属性,其实就是一个ProxyFactory,包括目标类,目标方法、advisor等信息。
  • 重要方法:
    • public Object invoke(Object proxy, Method method, Object[] args):方法调用的类,实现了InvocationHandler的方法

MethodInterceptor

  • 方法拦截器接口,继承了Advice,Interceptor。AspectJxxxAdvice等通知的类中都实现了这个方法,其中有一个invoke方法,是执行方法调用的逻辑,在Spring的代理执行的过程中和ReflectiveMethodInvocation结合使用,完美的诠释了责任链的模式。
  • Object invoke(MethodInvocation invocation) throws Throwable:执行方法的逻辑

AspectJAfterAdvice【示例】

  • 该类实现了MethodInterceptor,其中的Invoke实现如下:
    • 其中的mi.proceed()这个方法,是责任链模式的重要方法。
@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
            //调用其他的拦截器【因为这个拦截器是在方法之后执行的】
			return mi.proceed();
		}
		finally {
            //最终调用通知方法
			invokeAdviceMethod(getJoinPointMatch(), null, null);
		}
	}

MethodInvocation

  • 方法调用器,其中一个实现类是AOp中非常重要的组件(ReflectiveMethodInvocation)。

ReflectiveMethodInvocation

  • 该类在spring中的大致描述就是通过反射调用目标方法,是spring中内部使用的类。
  • 该类其中的重要的方法就是proceed,通过责任链的模式执行拦截器中的方法,和MethodInterceptor完美的诠释了责任链设计模式。源码如下:
    • 其实最重要的就是在内部调用了拦截器的invoke方法,但是在拦截器的invoke方法中还会递归的执行的proceed方法,这样的配置就完成了责任链的模式。
public Object proceed() throws Throwable {
		// 标记拦截器链执行的位置,初始值是-1,递归的结束条件
		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 {

				return proceed();
			}
		}
		else {
			//调用拦截器的invoke方法
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}
  • 实例如下:
@Test
    public void test1() throws Throwable {
        //目标对象
        UserService userService=new UserServiceImpl();
        //新建一个ProxyFactory,创建代理
        ProxyFactory factory = new ProxyFactory();
        factory.setTarget(userService);
        //设置接口,否则使用的是cglib代理
        factory.setInterfaces(UserService.class);
        //获取代理对象
        Object proxy = factory.getProxy();
        //切面
        Class aspectCls=LogAspect.class;
        //通知方法
        Method aspectMethod=aspectCls.getDeclaredMethod("afterAdvice");
        //切面对象
        final Object aspectObj=new LogAspect();
        //新建一个拦截器
        MethodInterceptor afterInterceptor=new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                CustomeInvocation ref=(CustomeInvocation)invocation;
                try{
                    //执行其他的拦截器
                    return invocation.proceed();
                }finally {
                    //最后执行切面的方法
                    ref.getAspectMethod().invoke(ref.getAspectObj(), ref.getAspectArgs());
//                    System.out.println("方法之后执行");
                }
            }
        };
        //创建拦截器链
        List<Object> interceptors=new ArrayList<>();
        interceptors.add(afterInterceptor);
        Method targetMethod=UserService.class.getMethod("addUser", User.class);
        Object[] args=new Object[]{new User("陈加兵")};
        CustomeInvocation invocation = new CustomeInvocation(proxy, userService, targetMethod, args, UserService.class,interceptors,aspectCls,aspectMethod,aspectObj,new Object[]{});
        invocation.proceed();
    }

    /**
     * 自定义一个Invocation,因为ReflectiveMethodInvocation是spring内部使用的,构造方法protected
     */
    public static class CustomeInvocation extends  ReflectiveMethodInvocation{
        private Method aspectMethod;
        private Class aspcetCls;
        private Object aspectObj;
        private Object[] aspectArgs;
        /**
         * @param proxy 代理
         * @param target 目标对象
         * @param method 目标方法
         * @param arguments 参数
         * @param targetClass 目标类
         * @param aspectMethod 通知方法
         * @param  aspctCls 切面类
         * @param  aspectObj 切面对象
         * @param interceptorsAndDynamicMethodMatchers 拦截器
         */
        public CustomeInvocation(Object proxy, Object target, Method method, Object[] arguments, Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers,Class aspctCls,Method aspectMethod,Object aspectObj,Object[] aspectArgs) {
            super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
            this.aspectMethod=aspectMethod;
            this.aspcetCls=aspctCls;
            this.aspectObj=aspectObj;
            this.aspectArgs=aspectArgs;
        }
    }

JDK动态代理示例

public class JDKDynamicProxy {
    public static interface Subject{
        int add(int a,int b);
    }

    public static class  CustomSubject implements Subject{
        @Override
        public int add(int a, int b) {
            System.out.println("执行加法计算");
            return a+b;
        }
    }

    /**
     * 自定义的InvocationHandler
     */
    public static class CustomInvocationHandler implements InvocationHandler{

        /**
         * 目标对象
         */
        private Object targetObject;

        public CustomInvocationHandler(Object targetObject) {
            this.targetObject = targetObject;
        }

        /**
         * @param proxy 代理对象
         * @param method 真正执行的方法
         * @param args 方法参数
         * @return
         * @throws Throwable
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            String methodName = method.getName();
            if (methodName.equals("add")){
                System.out.println("invok调用");
                Object invoke = method.invoke(targetObject, args);
                return invoke;
            }
            return null;
        }
    }

    @Test
    public void test(){
        Subject subject=new CustomSubject();
        CustomInvocationHandler customInvocationHandler = new CustomInvocationHandler(subject);
        Subject proxy= (Subject) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Subject.class}, customInvocationHandler);
        int count = proxy.add(1, 2);
        System.out.println(count);
    }
}

AOP创建代理流程

AOP执行流程

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • SpringBoot整合多数据源的巨坑

    爱撒谎的男孩
  • Springmvc注解版开发

    爱撒谎的男孩
  • Java IO学习笔记三

    爱撒谎的男孩
  • 设计模式 | 外观模式及典型应用

    外观模式是一种使用频率非常高的结构型设计模式,它通过引入一个外观角色来简化客户端与子系统之间的交互,为复杂的子系统调用提供一个统一的入口,降低子系统与客户端的耦...

    小旋锋
  • java 画图片

    DencyCheng
  • android实现菜单三级树效果

    本文实例为大家分享了android实现菜单三级树展示的具体代码,供大家参考,具体内容如下

    砸漏
  • 从 Spring 集成 MyBatis 到浅析 Java 动态代理

    因为 MyBatis 的易上手性和可控性,使得它成为了 ORM框架中的首选。近日新起了一个项目,所以重新搭建了一下 Spring-mybatis, 下面是搭建笔...

    Java技术江湖
  • 从 Spring 集成 MyBatis 到浅析 Java 动态代理

    因为 MyBatis 的易上手性和可控性,使得它成为了 ORM框架中的首选。近日新起了一个项目,所以重新搭建了一下 Spring-mybatis, 下面是搭建笔...

    黄泽杰
  • Spring实战——XML和JavaConfig的混合配置

    前言 看了园龄已经两年多了,再不能写完内容直接点击发布,留下一片密密麻麻的文字让别人看的头昏脑涨。所以现在每次写完主要内容后,还需要对于格式稍稍调整下。那么有没...

    JackieZheng
  • SpringFramework之@Conditional

        Conditional注解很重要,是Springboot自动化配置的基础,它会根据指向的condition实现类,在SpringIOC的时候调用其mat...

    克虏伯

扫码关注云+社区

领取腾讯云代金券