Spring之AOP底层源码解析

Spring之AOP底层源码解析

1、动态代理

代理模式的解释:为其他对象提供一种代理以控制对这个对象的访问,增强一个类中的某个方法,对程序进行扩展。

举个例子

public class UserService {

    public void test() {
        System.out.println("test...");
    }
}

此时,我们 new 一个 UserService 对象,然后执行 test() 方法,结果是显而易见的。

Untitled

那如果我们现在想在不修改 UserService 类的源码前提下,给 test() 方法增加额外的逻辑,那么就可以使用动态代理机制来创建 UserService 对象了,比如:

		public static void main(String[] args) {
				// 被代理对象
        UserService target = new UserService();
        // 通过cglib技术
        Enhancer enhancer = new Enhancer();
				// 设置要代理的类
        enhancer.setSuperclass(UserService.class);
        // 定义额外的逻辑,也就是代理逻辑
        enhancer.setCallbacks(new Callback[]{new MethodInterceptor() {
            /**
             *
             * @param o 代理对象
             * @param method 当前正在执行的方法
             * @param objects 方法所需要的参数
             * @param methodProxy
             * @return
             * @throws Throwable
             */
						@Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("before...");
								// 执行被代理对象的原始方法
                Object result = methodProxy.invoke(target, objects);
								// Object result = methodProxy.invokeSuper(o, objects); 这种方式也可以
                System.out.println("after...");
                return result;
            }
        }});

        // 动态代理所创建出来的UserService代理对象
        UserService userService = (UserService) enhancer.create();
        // 执行这个userService的test方法时,就会额外执行一些其他逻辑
        userService.test();
    }

Untitled

得到的都是 UserService 对象,但是执行 test() 方法时的效果却不一样了,这就是代理所带来的效果。

上面是通过 cglib 来实现的动态代理对象的创建,是基于子父类的,被代理类(UserService)是父类,代理类是子类,代理对象就是代理类的实例对象,代理类是由 cglib 创建的,对于程序员来说不用关心。

除了 cglib 技术,JDK 本身也提供了一种创建代理对象的动态代理机制,但是它只能代理接口,也就是 UserService 得先有一个接口才能利用 JDK 动态代理机制来生成一个代理对象,比如:

public interface UserInterface {

    public void test();

}

public class UserService implements UserInterface {

    public void test() {
        System.out.println("test...");
    }
}

利用 JDK 动态代理来生成一个代理对象:

		public static void main(String[] args) {
				// 被代理对象
        UserService target = new UserService();
        /**
         * UserInterface接口的代理对象
         * 注意第一个参数可以是任意类的类加载器,而第二个参数必须是代理对象的类型
         */
        Object proxy = Proxy.newProxyInstance(UserService.class.getClassLoader(), new Class[]{UserInterface.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("before...");
								// 通过反射机制调用被代理对象的原始方法
                Object result = method.invoke(target, args);
                System.out.println("after...");
                return result;
            }
        });
        UserInterface userService = (UserInterface) proxy;
        userService.test();
    }

Untitled

如果你把 new Class[]{UserInterface.class},替换成 new Class[]{UserService.class},那么代码会直接报错:

Untitled

Untitled

表示一定要是个接口。

由于这个限制,所以产生的代理对象的类型是 UserInterface,而不是 UserService,这是需要注意的。

2、ProxyFactory

上面我们介绍了两种动态代理技术,那么在 Spring 中进行了封装,封装出来的类叫做 ProxyFactory,表示是创建代理对象的一个工厂,使用起来会比上面的更加方便,比如:

		public static void main(String[] args) {
				// 被代理对象
        UserService target = new UserService();
				// 创建代理对象工厂
        ProxyFactory proxyFactory = new ProxyFactory();
				// 设置要代理的目标类
        proxyFactory.setTarget(target);
				/**
         * 注意:如果没有加上下面这行代码,那么默认走的是cglib动态代理;
         * 而如果我们设置了接口,那么走的就是jdk动态代理
         */
        proxyFactory.setInterfaces(UserInterface);
				// 设置代理逻辑,MethodInterceptor表示方法拦截器
        proxyFactory.addAdvice(new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }
        });
				// 通过代理对象工厂,获取代理对象
        UserInterface userService = (UserInterface) proxyFactory.getProxy();
        userService.test();
    }

通过 ProxyFactory,我们可以不再关心到底是用 cglib 还是 JDK 动态代理了,ProxyFactory 会帮助我们去判断,如果 UserService 实现了接口,那么ProxyFactory 底层就会采用 JDK 动态代理,如果没有实现接口,就会采用 cglib 动态代理。上面的代码,就是由于 UserService 实现了 UserInterface 接口,所以最后产生的代理对象是 UserInterface 类型。

3、Advice的分类

1、Before Advice:方法调用前执行

public class XiexuBeforeAdvice implements MethodBeforeAdvice {

    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("方法调用前执行");
    }
}

2、After Returning Advice:方法 Return 后执行

		public class XiexuAfterReturningAdvice implements AfterReturningAdvice {
        /**
         * @param returnValue 执行完被代理方法之后的返回值
         * @param method      被代理方法
         * @param args        方法所需要的参数
         * @param target      被代理对象
         * @throws Throwable
         */
        @Override
        public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
            System.out.println("方法return后执行");
        }
    }

3、After Throwing Advice:方法抛异常后执行

Untitled

public class XiexuThrowsAdvice implements ThrowsAdvice {
		
		/**
     * NullPointerException ex:当方法抛出的异常类型为NullPointerException类型时,才会调用该方法
     */
    public void afterThrowing(Method method, Object[] args, Object target, NullPointerException ex) {
        System.out.println("方法抛出异常后执行");
    }

}

4、After Advice:方法执行完之后执行,不管当前方法有没有抛出异常,这个 Advice 方法都会执行

5、Around Advice:这是功能最强大的 Advice,可以自定义执行顺序

public class XiexuAroundAdvice implements MethodInterceptor {

    @Nullable
    @Override
    public Object invoke(@NotNull MethodInvocation invocation) throws Throwable {
        System.out.println("方法执行Around前");
				// 执行被代理方法
        Object proceed = invocation.proceed();
        System.out.println("方法执行Around后");
        return proceed;
    }
}

3.1、MethodInterceptor链

除了Around advice,其他 advice 在执行完各自的逻辑代码后,都会自动调用 proceed() 去执行被代理方法,而每次调用 proceed() 就会去看还有没有设置其他的 advice,如果有就会继续执行其他 advice 的代理逻辑。

这里就是用到了「责任链」设计模式。

	public static void main(String[] args) {
				// 被代理对象
        UserService target = new UserService();
				// 代理对象工厂
        ProxyFactory proxyFactory = new ProxyFactory();
				// 设置目标对象
        proxyFactory.setTarget(target);
        proxyFactory.addAdvice(new XiexuBeforeAdvice());
        proxyFactory.addAdvice(new XiexuAroundAdvice());
        proxyFactory.addAdvice(new XiexuAroundAdvice());
				// 获取代理对象
        UserService proxy = (UserService) proxyFactory.getProxy();
        proxy.test(); // 执行这行代码的时候,底层就会去执行invocation.proceed()
    }

Untitled

proceed() 方法源码:

	@Override
	@Nullable
	public Object proceed() throws Throwable {

		/**
		 * currentInterceptorIndex初始值为-1,每调用一个Interceptor就会加1
		 * 当调用完了最后一个Interceptor后就会执行被代理的方法
		 */
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			// 执行被代理的方法,点进invokeJoinpoint()看看
			return invokeJoinpoint();
		}

		// currentInterceptorIndex初始值为-1
		Object interceptorOrInterceptionAdvice =
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);

		/**
		 * 如果当前interceptor是InterceptorAndDynamicMethodMatcher,则先进行匹配,匹配成功后再调用该interceptor
		 * 如果没有匹配则递归调用proceed()方法,调用下一个interceptor
		 */
		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			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 {
				// 不匹配则执行下一个MethodInterceptor
				return proceed();
			}
		} else {
			/**
			 * 直接调用MethodInterceptor,传入this,在内部会再次调用proceed()方法进行递归
			 * 比如MethodBeforeAdviceInterceptor
			 */
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}

4、Advisor的理解

跟 Advice 类似的还有一个 Advisor 的概念,一个 Advisor 是由一个 Pointcut 和一个 Advice 组成的,通过 Pointcut 可以指定需要被代理的逻辑,比如一个 UserService 类中有两个方法,按上面 ProxyFactory 的例子,这两个方法都会被代理、被增强,那么我们现在可以通过 Advisor,来控制具体代理哪一个方法,比如:

public class Test {

    public static void main(String[] args) {
				// 被代理对象
        UserService target = new UserService();
				// 代理对象工厂
        ProxyFactory proxyFactory = new ProxyFactory();
				// 设置目标对象
        proxyFactory.setTarget(target);
        proxyFactory.addAdvisor(new PointcutAdvisor() {
            /**
             * Pointcut可以去定义我们的代理逻辑要应用到哪个方法或哪个类上面
             * @return
             */
            @Override
            public Pointcut getPointcut() {
                return new StaticMethodMatcherPointcut() {
                    @Override
                    public boolean matches(Method method, Class<?> targetClass) {
												// 表示只有test()方法才需要走代理逻辑
                        return method.getName().equals("test");
                    }
                };
            }

            /**
             * Advice只是表示一段代理逻辑
             * @return
             */
            @Override
            public Advice getAdvice() {
                return new XiexuAroundAdvice();
            }

            /**
             * 这个方法可以忽略
             * @return
             */
            @Override
            public boolean isPerInstance() {
                return false;
            }
        });
				// 获取代理对象
        UserInterface userService = (UserInterface) proxyFactory.getProxy();
        userService.test();
    }

}

Untitled

上面代码表示,产生的代理对象,只有在执行 test() 这个方法时才会被增强,才会执行额外的逻辑,而在执行其他方法时是不会被增强的。

5、创建代理对象的方式

上面介绍了 Spring 中所提供的 ProxyFactory、Advisor、Advice、PointCut 等技术来实现代理对象的创建,但是我们在使用 Spring 时,并不会直接这么去使用 ProxyFactory,比如说,我们希望 ProxyFactory 所产生的代理对象能直接就是 Bean,能直接从 Spring 容器中得到 UserSerivce 的代理对象,而这些 Spring 都是支持的,只不过作为开发者的我们肯定得先告诉 Spring,哪些类需要被代理,代理逻辑是什么。

5.1、ProxyFactoryBean

		// 将产生的代理对象成为一个Bean
		@Bean
    public ProxyFactoryBean userService() {
        UserService userService = new UserService();
				// 创建ProxyFactoryBean对象
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
				// 设置要代理的对象
        proxyFactoryBean.setTarget(userService);
				// 代理逻辑
        proxyFactoryBean.addAdvice(new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }
        });
        return proxyFactoryBean;
    }

通过这种方式来定义一个 UserService 的 Bean,并且是经过了 AOP 的。但是这种方式只能针对某一个 Bean。它是一个 FactoryBean,所以利用的就是FactoryBean 技术,间接地将 UserService 的代理对象作为了 Bean。

ProxyFactoryBean 还有额外的功能,比如可以把某个 Advice 或 Advisor 定义成为 Bean,然后在 ProxyFactoryBean 中进行设置:

		@Bean
    public MethodInterceptor XiexuAroundAdvice() {
        return new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }
        };
    }

    @Bean
    public ProxyFactoryBean userService() {
				// 被代理对象
        UserService userService = new UserService();
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
				// 设置目标对象
        proxyFactoryBean.setTarget(userService);
        proxyFactoryBean.setInterceptorNames("XiexuAroundAdvice");
        return proxyFactoryBean;
    }

5.2、BeanNameAutoProxyCreator

ProxyFactoryBean 得自己指定被代理的对象,那么我们可以通过 BeanNameAutoProxyCreator 指定某个 bean 的名字,来对该 bean 进行代理

		@Bean
    public MethodInterceptor XiexuAroundAdvice() {
        return new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }
        };
    }
		
		@Bean
    public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
        BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
        beanNameAutoProxyCreator.setBeanNames("userSe*");
        beanNameAutoProxyCreator.setInterceptorNames("XiexuAroundAdvice");
        beanNameAutoProxyCreator.setProxyTargetClass(true);
        return beanNameAutoProxyCreator;
    }

通过 BeanNameAutoProxyCreator 可以对批量的 Bean 进行 AOP,并且指定了代理逻辑,指定了一个 InterceptorName,也就是一个 Advice,前提条件是这个 Advice 也得是一个 Bean,这样 Spring 才能找到,但是 BeanNameAutoProxyCreator 的缺点很明显,它只能根据 beanName 来指定想要代理的 Bean。

5.3、DefaultAdvisorAutoProxyCreator

public class AppConfig {

		/**
     * 定义一个Advisor类型的Bean
     *
     * @return
     */
    @Bean
    public DefaultPointcutAdvisor defaultPointcutAdvisor() {
        NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
        pointcut.addMethodName("test");
        DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
        defaultPointcutAdvisor.setPointcut(pointcut);
        defaultPointcutAdvisor.setAdvice(new XiexuAfterReturningAdvice());
        return defaultPointcutAdvisor;
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        return defaultAdvisorAutoProxyCreator;
    }

}

通过 DefaultAdvisorAutoProxyCreator 会直接去找所有 Advisor 类型的 Bean,然后根据 Advisor 中的 PointCutAdvice 信息,确定要代理的 Bean 以及代理逻辑。

通过这种方式,我们得依靠某一个类来实现定义我们的 Advisor,或者 Advice,或者 Pointcut,那么这个步骤能不能更加简化一点呢?

答案是可以的,我们可以通过注解的方式进行简化!

比如我们可以只定义一个类,然后通过在类中的方法上加上某些注解,来定义 PointCut 以及 Advice,比如:

		@Aspect
    @Component
    public class XiexuAspect {

        @Before("execution(public void cn.xx.UserService.test())")
        public void xiexuBefore(JoinPoint joinPoint) {
            System.out.println("xiexuBefore");
        }

    }

通过上面这个类,我们就直接定义好了所要代理的方法(通过一个表达式),以及代理逻辑(被 @Before 修饰的方法),简单明了,这样对于 Spring 来说,它要做的就是来解析这些注解了,解析之后得到对应的 Pointcut 对象、Advice 对象,生成 Advisor 对象,扔进 ProxyFactory 中,进而产生对应的代理对象,具体怎么解析这些注解就是 @EnableAspectJAutoProxy 注解所要做的事情了,后面详细分析。

6、对Spring AOP的理解

OOP 表示面向对象编程,是一种编程思想,AOP 表示面向切面编程,也是一种编程思想,而我们上面所描述的就是 Spring 为了让程序员更加方便的做到面向切面编程所提供的技术支持,换句话说,就是 Spring 提供了一套机制,可以让我们更加容易的进行 AOP,所以这套机制我们也可以称之为 Spring AOP。

但是值得注意的是,上面所提供的注解的方式来定义 PointcutAdvice,Spring 并不是首创,首创是 AspectJ,而且也不仅仅只有 Spring 提供了一套机制来支持 AOP,还有比如 JBoss 4.0、aspectwerkz 等技术都提供了对于 AOP 的支持。而刚刚说的注解的方式,Spring 是依赖了 AspectJ 的,换句话说,Spring 是直接把 AspectJ 中所定义的那些注解直接拿过来用,自己没有再重新定义了,不过也仅仅只是把注解的定义复制过来了,每个注解具体底层是怎么解析的,还是 Spring 自己做的,所以我们在使用 Spring 时,如果你想用 @Before@Around 等注解,是需要单独引入 AspectJ 相关 jar 包的,比如:

compile group: 'org.aspectj', name: 'aspectjrt', version: '1.9.5'
compile group: 'org.aspectj', name: 'aspectjweaver', version: '1.9.5'

值得注意的是:AspectJ 是在编译时对字节码进行了修改,是直接在 UserService 类对应的字节码中进行增强的,也就是可以理解为是在编译时就会去解析@Before 这些注解,然后得到代理逻辑,加入到被代理类中的字节码中去的,所以如果想用 AspectJ 技术来生成代理对象 ,是需要用单独的 AspectJ 编译器的。我们在项目中很少这么使用,我们仅仅只是用了 @Before 这些注解,而我们在启动 Spring 的过程中,Spring 会去解析这些注解,然后利用动态代理机制生成代理对象的。

IDEA 中使用 AspectJ:https://blog.csdn.net/gavin_john/article/details/80156963

7、AOP中的概念

上面我们已经提到 Advisor、Advice、PointCut 等概念了,还有一些其他的概念,首先关于 AOP 中的概念本身是比较难理解的,Spring 官网上是这么说的:

Let us begin by defining some central AOP concepts and terminology. These terms are not Spring-specific. Unfortunately, AOP terminology is not particularly intuitive. However, it would be even more confusing if Spring used its own terminology

意思是,AOP 中的这些概念并不是 Spring 特有的,而且不幸的是,AOP 中的概念不是特别直观的,如果 Spring 重新定义自己的那可能会导致更加混乱。

1、Aspect:表示切面,比如被 @Aspect 注解的类就是切面,可以在切面中去定义 PointcutAdvice 等等。

2、Join point:表示连接点,表示一个程序在执行过程中的一个点,比如一个方法的执行(被代理方法)、一个异常的处理,在 Spring AOP 中,一个连接点通常表示一个方法的执行。

3、Advice:表示通知,表示在一个特定连接点上所采取的动作。Advice 分为不同的类型,后面详细讨论,在很多 AOP 框架中,包括 Spring,会用Interceptor 拦截器来实现 Advice,并且会在连接点周围维护一个 Interceptor 链。

4、Pointcut:表示切点,用来匹配一个或多个连接点,Advice 与切点表达式是关联在一起的,Advice 将会执行在和切点表达式所匹配的连接点上。

5、Introduction:可以使用 @DeclareParents 来给所匹配的类添加一个接口,并指定一个默认实现。

6、Target object:目标对象,也就是被代理对象。

7、AOP Proxy:表示代理工厂,用来创建代理对象的,在 Spring Framework 中,要么是 JDK 动态代理,要么是 CGLIB 动态代理。

8、Weaving:表示织入,表示创建代理对象的动作,这个动作可以发生在编译时期(比如 Aspejctj),也可以发生在运行时期(比如 Spring AOP)。

8、Advice在Spring AOP中对应的API

上面说到的 AspjectJ 中的注解,其中有五个是用来定义 Advice 的,表示代理逻辑,以及执行时机:

1、@Before

2、@AfterReturning

3、@AfterThrowing

4、@After

5、@Around

我们前面也提到过,Spring 自己也提供了类似的实现类:

1、接口MethodBeforeAdvice,继承了接口BeforeAdvice

2、接口AfterReturningAdvice,继承了接口AfterAdvice

3、接口ThrowsAdvice,继承了接口AfterAdvice

4、接口AfterAdvice,继承了接口Advice

5、接口MethodInterceptor,继承了接口Interceptor

Spring 会把这五个注解解析成对应的 Advice 类:

1、@Before:AspectJMethodBeforeAdvice,实际上就是一个 MethodBeforeAdvice

2、@AfterReturning:AspectJAfterReturningAdvice,实际上就是一个 AfterReturningAdvice

3、@AfterThrowing:AspectJAfterThrowingAdvice,实际上就是一个 MethodInterceptor

4、@After:AspectJAfterAdvice,实际上就是一个 MethodInterceptor

5、@Around:AspectJAroundAdvice,实际上就是一个 MethodInterceptor

9、TargetSource的使用

在我们日常的 AOP 中,被代理对象就是 Bean 对象,是由 BeanFactory 给我们创建出来的,但是 Spring AOP 中提供了 TargetSource 机制,可以让我们自定义逻辑来创建被代理对象。

比如之前提到的 @Lazy 注解,当加在属性上时,会产生一个代理对象并赋值给这个属性,产生代理对象的代码为:

	/**
	 * 创建@Lazy懒加载的代理对象
	 *
	 * @param descriptor
	 * @param beanName
	 * @return
	 */
	protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final @Nullable String beanName) {
		// 获取Spring的Bean工厂
		BeanFactory beanFactory = getBeanFactory();
		Assert.state(beanFactory instanceof DefaultListableBeanFactory, "BeanFactory needs to be a DefaultListableBeanFactory");
		final DefaultListableBeanFactory dlbf = (DefaultListableBeanFactory) beanFactory;
		/**
		 * 创建TargetSource对象
		 */
		TargetSource ts = new TargetSource() {
			@Override
			public Class<?> getTargetClass() {
				return descriptor.getDependencyType();
			}

			@Override
			public boolean isStatic() {
				return false;
			}

			/**
			 * Lazy的效果:
			 * 当属性上有@Lazy注解,刚开始进行依赖注入时,该属性是被赋了一个代理对象,
			 * 当你真正用到该属性时,这时候才会根据当前属性的类型和名字,去BeanFactory中找到对应的Bean,这时候才会真正去执行对应Bean的原方法。
			 * 当set方法的参数有@Lazy注解时,同理。
			 * @return
			 */
			@Override
			public Object getTarget() {
				Set<String> autowiredBeanNames = (beanName != null ? new LinkedHashSet<>(1) : null);
				// 根据属性的类型和名字去Bean工厂找被代理的对象
				Object target = dlbf.doResolveDependency(descriptor, beanName, autowiredBeanNames, null);
				if (target == null) {
					Class<?> type = getTargetClass();
					if (Map.class == type) {
						return Collections.emptyMap();
					} else if (List.class == type) {
						return Collections.emptyList();
					} else if (Set.class == type || Collection.class == type) {
						return Collections.emptySet();
					}
					throw new NoSuchBeanDefinitionException(descriptor.getResolvableType(), "Optional dependency not present for lazy injection point");
				}
				if (autowiredBeanNames != null) {
					for (String autowiredBeanName : autowiredBeanNames) {
						if (dlbf.containsBean(autowiredBeanName)) {
							dlbf.registerDependentBean(autowiredBeanName, beanName);
						}
					}
				}
				// 找到被代理的对象,直接返回
				return target;
			}

			@Override
			public void releaseTarget(Object target) {
			}
		};

		// 创建ProxyFactory对象
		ProxyFactory pf = new ProxyFactory();
		// 设置被代理对象为TargetSource
		pf.setTargetSource(ts);
		Class<?> dependencyType = descriptor.getDependencyType();
		if (dependencyType.isInterface()) {
			pf.addInterface(dependencyType);
		}
		// 返回一个代理对象
		return pf.getProxy(dlbf.getBeanClassLoader());
	}

这段代码就利用了 ProxyFactory 来生成代理对象,以及使用了 TargetSource,以达到代理对象在执行某个方法时,会去调用 TargetSource 的 getTarget() 方法得到一个被代理对象。

10、ProxyFactory选择CGLIB或JDK动态代理的原理

ProxyFactory 在生成代理对象之前需要先决定到底是使用 JDK 动态代理还是 CGLIB 动态代理:

	@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		/**
		 * config指的是我们在外面创建的ProxyFactory对象
		 * NativeDetector.inNativeImage():当前Spring项目是不是在GraalVM虚拟机上运行的,如果是则使用JDK动态代理创建代理对象
		 * config.isOptimize():如果isOptimize为true,则会使用cglib动态代理创建代理对象,因为Spring认为cglib比jdk动态代理要快
		 * config.isProxyTargetClass():要代理的是不是一个类,如果为true则使用cglib动态代理创建代理对象
		 * hasNoUserSuppliedProxyInterfaces(config):当前ProxyFactory对象有没有去添加接口(addInterface),
		 * 如果添加了则返回false并使用JDK动态代理创建代理对象,如果没有添加接口则返回true并使用cglib动态代理创建代理对象
		 */
		if (!NativeDetector.inNativeImage() &&
				/**
				 * 类似于:
				 * ProxyFactory proxyFactory = new ProxyFactory();
				 * proxyFactory.setOptimize(true);
				 * proxyFactory.setProxyTargetClass(true);
				 * 如果添加了proxyFactory.addInterface();
				 * 那么hasNoUserSuppliedProxyInterfaces(config)为false,如果没有添加则为true
				 */
				(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.");
			}
			/**
			 * targetClass.isInterface():如果被代理的类是一个接口
			 * 举个例子:
			 * ProxyFactory proxyFactory = new ProxyFactory();
			 * proxyFactory.setTargetClass(UserInterface.class);
			 * 这样的话就表示被代理类是一个接口
			 * Proxy.isProxyClass(targetClass):当前所设置的被代理类是不是已经进行过JDK动态代理而生成的代理类
			 */
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				/**
				 * 使用jdk动态代理创建代理对象
				 */
				return new JdkDynamicAopProxy(config);
			}
			/**
			 * 返回Cglib创建的代理对象
			 */
			return new ObjenesisCglibAopProxy(config);
		} else {
			/**
			 * 使用jdk动态代理创建代理对象
			 */
			return new JdkDynamicAopProxy(config);
		}
	}

11、代理对象创建过程

11.1、JdkDynamicAopProxy

1、在构造 JdkDynamicAopProxy 对象时,会先拿到被代理对象自己所实现的接口,并且额外增加 SpringProxy、Advised、DecoratingProxy 三个接口,组合成一个 Class[],并赋值给 proxiedInterfaces 属性

2、并且检查这些接口中是否定义了equals()hashcode()方法

3、执行 Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this),得到代理对象,JdkDynamicAopProxy 作为 InvocationHandler,代理对象在执行某个方法时,会进入到 JdkDynamicAopProxy 的 invoke() 方法中

12、代理对象执行过程

1、在使用 ProxyFactory 创建代理对象之前,需要往 ProxyFactory 中先添加 Advisor

2、代理对象在执行某个方法时,会把 ProxyFactory 中的 Advisor 拿出来和当前正在执行的方法进行匹配筛选

3、把和当前正在执行的方法所匹配的 Advisor 适配成 MethodInterceptor

4、把和当前方法匹配的 MethodInterceptor 链,以及被代理对象、代理对象、代理类、当前 Method 对象、方法参数封装成 MethodInvocation 对象

5、调用 MethodInvocation 的 proceed() 方法,开始执行各个 MethodInterceptor 以及被代理对象的对应方法

6、按顺序调用每个 MethodInterceptor 的 invoke() 方法,并且会把 MethodInvocation 对象传入 invoke() 方法

7、直到执行完最后一个 MethodInterceptor 了,就会调用 invokeJoinpoint() 方法,从而执行被代理对象的当前方法

12.1、各注解对应的MethodInterceptor

1、@Before 对应的是 AspectJMethodBeforeAdvice,在进行动态代理时会把 AspectJMethodBeforeAdvice 转成 MethodBeforeAdviceInterceptor

  • 先执行 advice 对应的方法
  • 再执行 MethodInvocation 的 proceed(),会执行下一个 Interceptor,如果没有下一个 Interceptor 了,会执行 target 对应的方法

2、@After 对应的是 AspectJAfterAdvice,直接实现了 MethodInterceptor

  • 先执行 MethodInvocation 的 proceed(),会执行下一个 Interceptor,如果没有下一个 Interceptor 了,会执行 target 对应的方法
  • 再执行 advice 对应的方法

3、@Around 对应的是 AspectJAroundAdvice,直接实现了 MethodInterceptor

  • 直接执行 advice 对应的方法,由 @Around 自己决定要不要继续往后面调用

4、@AfterThrowing 对应的是 AspectJAfterThrowingAdvice,直接实现了 MethodInterceptor

  • 先执行 MethodInvocation的 proceed(),会执行下一个 Interceptor,如果没有下一个 Interceptor 了,会执行 target 对应的方法
  • 如果上面抛了 Throwable,那么则会执行 advice 对应的方法

5、@AfterReturning 对应的是 AspectJAfterReturningAdvice,在进行动态代理时会把 AspectJAfterReturningAdvice 转成 AfterReturningAdviceInterceptor

  • 先执行 MethodInvocation 的 proceed(),会执行下一个 Interceptor,如果没有下一个 Interceptor 了,会执行 target 对应的方法
  • 执行上面的方法后得到最终的方法的返回值
  • 再执行 Advice 对应的方法

13、AbstractAdvisorAutoProxyCreator

DefaultAdvisorAutoProxyCreator 的父类是 AbstractAdvisorAutoProxyCreator。

Untitled

AbstractAdvisorAutoProxyCreator 非常强大以及重要,只要 Spring 容器中存在这个类型的 Bean,就相当于开启了 AOP,AbstractAdvisorAutoProxyCreator实际上就是一个 BeanPostProcessor,所以在创建某个 Bean 时,就会进入到它对应的生命周期方法中,比如在某个 Bean 初始化之后,会调用wrapIfNecessary() 方法进行 AOP,底层逻辑是:AbstractAdvisorAutoProxyCreator 会找到所有的 Advisor,然后判断当前这个 Bean 是否存在某个 Advisor 与之匹配(根据 Pointcut),如果匹配就表示当前这个 Bean 有对应的切面逻辑,需要进行AOP,需要产生一个代理对象。

14、@EnableAspectJAutoProxy

这个注解主要就是往 Spring 容器中添加了一个 AnnotationAwareAspectJAutoProxyCreator 类型的Bean。

Untitled

AspectJAwareAdvisorAutoProxyCreator 继承了 AbstractAdvisorAutoProxyCreator,重写了 findCandidateAdvisors() 方法,AbstractAdvisorAutoProxyCreator 只能找到所有 Advisor 类型的 Bean 对象,但是 AspectJAwareAdvisorAutoProxyCreator 除了可以找到所有 Advisor 类型的 Bean 对象,还能把 @Aspect 注解所标注的 Bean 中的 @Before 等注解及方法进行解析,并生成对应的 Advisor 对象。

@Aspect
@Component
public class XxAspect {

    @Before("execution(public void cn.xx.UserService.test())")
    public void xiexuBefore(JoinPoint joinPoint) {
        System.out.println("xiexuBefore");
    }

}

所以,我们可以这样理解 @EnableAspectJAutoProxy,其实就是向 Spring 容器中添加了一个 AbstractAdvisorAutoProxyCreator 类型的Bean,从而开启了 AOP,并且还会解析 @Before 等注解并生成 Advisor

15、Spring中AOP原理流程图

https://www.processon.com/view/link/5faa4ccce0b34d7a1aa2a9a5

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猿小羽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值