Spring之AOP底层源码解析
1、动态代理
代理模式的解释:为其他对象提供一种代理以控制对这个对象的访问,增强一个类中的某个方法,对程序进行扩展。
举个例子
public class UserService {
public void test() {
System.out.println("test...");
}
}
此时,我们 new 一个 UserService 对象,然后执行 test()
方法,结果是显而易见的。
那如果我们现在想在不修改 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();
}
得到的都是 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();
}
如果你把 new Class[]{UserInterface.class}
,替换成 new Class[]{UserService.class}
,那么代码会直接报错:
表示一定要是个接口。
由于这个限制,所以产生的代理对象的类型是 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:方法抛异常后执行
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()
}
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();
}
}
上面代码表示,产生的代理对象,只有在执行 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 中的 PointCut
和 Advice
信息,确定要代理的 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。
但是值得注意的是,上面所提供的注解的方式来定义 Pointcut
和 Advice
,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
注解的类就是切面,可以在切面中去定义 Pointcut
、Advice
等等。
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。
AbstractAdvisorAutoProxyCreator 非常强大以及重要,只要 Spring 容器中存在这个类型的 Bean,就相当于开启了 AOP,AbstractAdvisorAutoProxyCreator实际上就是一个 BeanPostProcessor
,所以在创建某个 Bean 时,就会进入到它对应的生命周期方法中,比如在某个 Bean 初始化之后,会调用wrapIfNecessary()
方法进行 AOP,底层逻辑是:AbstractAdvisorAutoProxyCreator 会找到所有的 Advisor,然后判断当前这个 Bean 是否存在某个 Advisor 与之匹配(根据 Pointcut),如果匹配就表示当前这个 Bean 有对应的切面逻辑,需要进行AOP,需要产生一个代理对象。
14、@EnableAspectJAutoProxy
这个注解主要就是往 Spring 容器中添加了一个 AnnotationAwareAspectJAutoProxyCreator
类型的Bean。
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