SpringAOP的核心首先是创建代理对象存入SpringIoC容器中,然后就是调用的时候使用责任链模式进行调用。首先研究SpringAOP创建代理对象的机制。
在Spring的AOP实现中,使用的核心技术是代理技术,而这种动态代理实际上是JDK的一个特性(1.3)。基于JDK动态代理的target目标对象必须实现接口。如果没有实现的接口需要基于Cglib代理。当然可以使用@EnableAspectJAutoProxy(proxyTargetClass = true) 强转使用Cglib代理。
在Java社区里AspectJ是最完整的AOP框架,但SpringAOP也提供了另外一种实现,这种实现并不是AspectJ的竞争者,相反,SpringAOP还将AspectJ集成了进来,为IoC容器和Spring应用开发提供了一个一致性的AOP解决方案。
SpringAOP的核心技术是代理技术。以动态代理技术为基础,设计出了一系列AOP的横切实现,比如前置通知、返回通知、异常通知等。同时,SpringAOP还提供了一系列的Pointcut来匹配切入点,可以使用现有的切入点来设计横切面,也可以扩展相应的Pointcut来实现切入需求。(我们可以看到好多aspectj包相关的东西,其实Spring只是引用了AspectJ的语法,其实现核心还是基于代理以及责任链模式来实现代理链条调用)。
在SpringAOP中,对于AOP的使用者来说,只需要配置相关的bean。但是为了能让AOP起作用,需要完成一系列的过程,比如:为目标对象建立代理对象,这个代理对象可以用JDK代理,也可以用CGLIB代理;然后还需要启动代理对象的拦截器来完成切面的织入,这一系列的织入设计是通过一系列Adapter来实现的。通过Adapter的设计,可以把AOP的横切面设计和Proxy模式有机地结合起来,从而实现在AOP中定义好的各种织入方式。
1. 代理测试
1. jdk动态代理测试:
接口:
package proxy; public interface UserDao { String method1(); }
实现类:
package cn.qz.proxy; public class UserDaoImpl implements UserDao { @Override public String method1() { System.out.println("cn.qz.proxy.UserDaoImpl.method1===="); return "method1"; } }
测试代理:
package cn.qz.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class Client { public static void main(String[] args) { final UserDao target = new UserDaoImpl(); UserDao o = (UserDao) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { /** * @author * @date 2021/2/23 18:56 * @param proxy: 代理对象 * @param method: 反射方法对象 * @param args: 参数列表 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("方法执行前"); //运用反射执行目标对象方法 Object returnValue = method.invoke(target, args); System.out.println("方法执行后"); return returnValue; } }); String s = o.method1(); System.out.println(s); } }
结果:
方法执行前 cn.qz.proxy.UserDaoImpl.method1==== 方法执行后 method1
2. cglib代理测试
cglib的流程大体是创Enhancer对象,然后设置其父类,设置回调(回调是个Callback对象,也可以传递数组。实际net.sf.cglib.proxy.MethodInterceptor 继承自Callback接口)。单个Callback不需要传递设置CallbackFilter,多个Callback需要设置CallbackFilter( 内部accept方法返回Cabblack数组的下标),让Cglib知道获取Callback的规则。
0. pom:
<!-- https://mvnrepository.com/artifact/cglib/cglib --> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.12</version> </dependency>
1. 单个Callback的测试:
代理类:
package cn.qz.proxy; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class CglibMethodInterceptor1 implements MethodInterceptor { /** * 1、代理对象;2、委托类方法;3、方法参数;4、代理方法的MethodProxy对象。 * * @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("CglibMethodInterceptor1 start......" + method.getName()); Object o1 = methodProxy.invokeSuper(o, objects); System.out.println("CglibMethodInterceptor1 end......." + method.getName()); return o1; } }
测试类:
public static void main(String[] args) { //在指定目录下生成动态代理类,我们可以反编译看一下里面到底是一些什么东西 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "G:/proxy"); CglibMethodInterceptor1 methodInterceptor1 = new CglibMethodInterceptor1();//jdk需要提供接口,cglib需要是非私有类,且不能处理final关键字修饰的方法 Enhancer enhancer = new Enhancer(); //设置父类 enhancer.setSuperclass(UserDaoImpl.class); //设置回调对象 enhancer.setCallback(methodInterceptor1); UserDaoImpl proxy = (UserDaoImpl) enhancer.create(); proxy.method1(); }
结果:
CglibMethodInterceptor1 start......method1 cn.qz.proxy.UserDaoImpl.method1==== CglibMethodInterceptor1 end.......method1
2. 多个Callback的测试
接口:
package cn.qz.proxy; public interface UserDao { String method1(); String method2(); }
实现类:
package cn.qz.proxy; public class UserDaoImpl implements UserDao { @Override public String method1() { System.out.println("cn.qz.proxy.UserDaoImpl.method1===="); return "method1"; } @Override public String method2() { System.out.println("cn.qz.proxy.UserDaoImpl.method2===="); return "method2"; } }
增加Callback2
package cn.qz.proxy; import net.sf.cglib.proxy.MethodInterceptor; import java.lang.reflect.Method; public class CglibMethodInterceptor2 implements MethodInterceptor { /** * 1、代理对象;2、委托类方法;3、方法参数;4、代理方法的MethodProxy对象。 * * @param o * @param method * @param objects * @param methodProxy * @return * @throws Throwable */ @Override public Object intercept(Object o, Method method, Object[] objects, net.sf.cglib.proxy.MethodProxy methodProxy) throws Throwable { System.out.println("CglibMethodInterceptor2 start......" + method.getName()); Object o1 = methodProxy.invokeSuper(o, objects); System.out.println("CglibMethodInterceptor2 end......." + method.getName()); return o1; } }
测试:
package cn.qz.proxy; import net.sf.cglib.core.DebuggingClassWriter; import net.sf.cglib.proxy.Callback; import net.sf.cglib.proxy.CallbackFilter; import net.sf.cglib.proxy.Enhancer; import java.lang.reflect.Method; public class CglibClient { public static void main(String[] args) { //在指定目录下生成动态代理类,我们可以反编译看一下里面到底是一些什么东西 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "G:/proxy"); CglibMethodInterceptor1 methodInterceptor1 = new CglibMethodInterceptor1(); CglibMethodInterceptor2 methodInterceptor2 = new CglibMethodInterceptor2(); //jdk需要提供接口,cglib需要是非私有类,且不能处理final关键字修饰的方法 Enhancer enhancer = new Enhancer(); //设置父类 enhancer.setSuperclass(UserDaoImpl.class); //设置回调对象 enhancer.setCallbacks(new Callback[]{methodInterceptor1, methodInterceptor2}); // 设置CallbackFilter enhancer.setCallbackFilter(new CallbackFilter() { @Override public int accept(Method method) { String name = method.getName(); if ("method1".equals(name)) { return 0; } return 1; } }); UserDaoImpl proxy = (UserDaoImpl) enhancer.create(); proxy.method1(); proxy.method2(); } }
结果:
CglibMethodInterceptor1 start......method1 cn.qz.proxy.UserDaoImpl.method1==== CglibMethodInterceptor1 end.......method1 CglibMethodInterceptor2 start......method2 cn.qz.proxy.UserDaoImpl.method2==== CglibMethodInterceptor2 end.......method2
2. 测试Spring代理对象
简单测试Aop代理生成的类的class信息
1. pom
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>cn.qz</groupId> <artifactId>springlearn</artifactId> <version>1.0-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.1.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <name>springlearn</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!-- 引入 spring aop 依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> </dependencies> <build> <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --> <plugins> <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle --> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>3.1.0</version> </plugin> <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging --> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>3.0.2</version> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.1</version> </plugin> <plugin> <artifactId>maven-jar-plugin</artifactId> <version>3.0.2</version> </plugin> <plugin> <artifactId>maven-install-plugin</artifactId> <version>2.5.2</version> </plugin> <plugin> <artifactId>maven-deploy-plugin</artifactId> <version>2.8.2</version> </plugin> <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle --> <plugin> <artifactId>maven-site-plugin</artifactId> <version>3.7.1</version> </plugin> <plugin> <artifactId>maven-project-info-reports-plugin</artifactId> <version>3.0.0</version> </plugin> </plugins> </pluginManagement> </build> </project>
2. 类信息
主类
package cn.qz; import cn.qz.user.DeptDao; import cn.qz.user.UserDao; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.EnableAspectJAutoProxy; @ComponentScan @EnableAspectJAutoProxy public class App { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(App.class); UserDao bean = applicationContext.getBean(UserDao.class); System.out.println(bean.getClass()); DeptDao bean1 = applicationContext.getBean(DeptDao.class); System.out.println(bean1.getClass()); } }
Aop类
package cn.qz.aop; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; import java.lang.reflect.Method; import java.util.Arrays; @Aspect // 表示该类是一个通知类 @Component // 交给spring管理 public class MyAdvice { // 定义一个空方法,借用其注解抽取切点表达式 @Pointcut("execution(* cn.qz..*.*(..))") public void pc() { } // 前置通知 @Before("MyAdvice.pc()") public void before(JoinPoint joinPoint) throws Exception { System.out.println("---------------前置通知开始~~~~~~~~~~~"); // 获取到类名 String targetName = joinPoint.getTarget().getClass().getName(); System.out.println("代理的类是:" + targetName); // 获取到方法名 String methodName = joinPoint.getSignature().getName(); System.out.println("增强的方法是:" + methodName); // 获取到参数 Object[] parameter = joinPoint.getArgs(); System.out.println("传入的参数是:" + Arrays.toString(parameter)); // 获取字节码对象 Class<?> targetClass = Class.forName(targetName); // 获取所有的方法 Method[] methods = targetClass.getMethods(); for (Method method : methods) { if (method.getName().equals(methodName)) { Class[] clazzs = method.getParameterTypes(); if (clazzs.length == parameter.length) { System.out.println("找到这个方法"); //处理一些业务逻辑 break; } } } System.out.println("---------------前置通知结束~~~~~~~~~~~"); } // 后置通知(异常发生后不会调用) @AfterReturning("MyAdvice.pc()") public void afterRunning() { System.out.println("这是后置通知(异常发生后不会调用)"); } // 环绕通知(推荐下面这种方式获取方法) @Around("MyAdvice.pc()") public Object around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("----------------环绕通知之前 的部分----------------"); // 获取到类名 String targetName = pjp.getTarget().getClass().getName(); System.out.println("代理的类是:" + targetName); // 获取到参数 Object[] parameter = pjp.getArgs(); System.out.println("传入的参数是:" + Arrays.toString(parameter)); // 获取到方法签名,进而获得方法 MethodSignature signature = (MethodSignature) pjp.getSignature(); Method method = signature.getMethod(); System.out.println("增强的方法名字是:" + method.getName()); //处理一些业务逻辑 // 获取参数类型 Class<?>[] parameterTypes = method.getParameterTypes(); System.out.println("参数类型是:" + parameterTypes.toString()); //让方法执行(proceed是方法的返回结果,可以针对返回结果处理一下事情) System.out.println("--------------方法开始执行-----------------"); Object proceed = pjp.proceed(); //环绕通知之后的业务逻辑部分 System.out.println("----------------环绕通知之后的部分----------------"); return proceed; } // 异常通知 @AfterThrowing("MyAdvice.pc()") public void afterException() { System.out.println("这是异常通知(发生异常后调用)~~~~~~~~~~~"); } // 最终通知(发生异常也会在最终调用) @After("MyAdvice.pc()") public void after() { System.out.println("这是后置通知(发生异常也会在最终调用)"); } }
测试类:
UserDao
package cn.qz.user; public interface UserDao { void addUser(); }
UserDaoImpl
package cn.qz.user; import org.springframework.stereotype.Service; @Service public class UserDaoImpl implements UserDao{ @Override public void addUser() { System.out.println("addUser"); } }
DeptDao
package cn.qz.user; import org.springframework.stereotype.Component; @Component public class DeptDao { public void test(){ System.out.println("test"); } }
启动后测试结果如下:
class com.sun.proxy.$Proxy22 class cn.qz.user.DeptDao$$EnhancerBySpringCGLIB$$fb860d23
上面也证实了有接口是基于JDK的动态代理,没有实现接口是基于CGLIB的继承代理。
3.创建代理代码跟踪
在IoC中研究中,大致了解到对象的创建过程,且了解到BeanPostProcessor在对象创建过程中的调用过程以及调用时机。
1. org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean 对象初始化过程如下:
protected Object initializeBean(final String beanName, final 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; }
2. 上面代码中在调用 invokeInitMethods 初始化方法之后会调用applyBeanPostProcessorsAfterInitialization
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization 源码如下:
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) { Object current = processor.postProcessAfterInitialization(result, beanName); if (current == null) { return result; } result = current; } return result; }
其实代理对象的创建也是在这个过程中,中发生的。debug查看getBeanPostProcessors() 的返回结果如下:
可以猜测进行代理对象的创建是在 AnnotationAwareAspectJAutoProxyCreator 类中,AnnotationAwareAspectJAutoProxyCreator类继承自的方法,org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization源码如下:
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; }
这个方法内部通过处理后返回代理对象的引用。
3. org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary 源码如下;
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { return bean; } if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // Create proxy if we have 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) Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); 这一行代码返回 该对象的Advice和Advisor,也就是通知相关对象,debug查看返回的结果如下:
实际上也是AOP调用链的数组,第一个ExposeInvocationInterceptor 是Spring内置的一个通知,在AOP调用链过程中起作用。
再次查看Advisor解析过程:
1》org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean 获取结果
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(); }
2》接着调用org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisors
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; }
2.1》 List<Advisor> candidateAdvisors = findCandidateAdvisors(); 获取到所有的Advisor
org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors如下:
protected List<Advisor> findCandidateAdvisors() { // Add all the Spring advisors found according to superclass rules. List<Advisor> advisors = super.findCandidateAdvisors(); // Build Advisors for all AspectJ aspects in the bean factory. if (this.aspectJAdvisorsBuilder != null) { advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); } return advisors; }
2.1.1》this.aspectJAdvisorsBuilder.buildAspectJAdvisors()会调用到org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors
public List<Advisor> buildAspectJAdvisors() { List<String> aspectNames = this.aspectBeanNames; if (aspectNames == null) { synchronized (this) { aspectNames = this.aspectBeanNames; if (aspectNames == null) { List<Advisor> advisors = new ArrayList<>(); aspectNames = new ArrayList<>(); String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Object.class, true, false); for (String beanName : beanNames) { if (!isEligibleBean(beanName)) { continue; } // We must be careful not to instantiate beans eagerly as in this case they // would be cached by the Spring container but would not have been weaved. Class<?> beanType = this.beanFactory.getType(beanName); if (beanType == null) { continue; } 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)); } } } this.aspectBeanNames = aspectNames; return advisors; } } } if (aspectNames.isEmpty()) { return Collections.emptyList(); } List<Advisor> advisors = new ArrayList<>(); for (String aspectName : aspectNames) { List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName); if (cachedAdvisors != null) { advisors.addAll(cachedAdvisors); } else { MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName); advisors.addAll(this.advisorFactory.getAdvisors(factory)); } } return advisors; }
2.1.2》上面BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false); 获取到Spring IoC中所有的bean的name。
2.1.3》this.advisorFactory.isAspect(beanType) 判断是否是Aspect切面类,org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#isAspect如下:
public boolean isAspect(Class<?> clazz) { return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz)); } private boolean hasAspectAnnotation(Class<?> clazz) { return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null); } private boolean compiledByAjc(Class<?> clazz) { // The AJTypeSystem goes to great lengths to provide a uniform appearance between code-style and // annotation-style aspects. Therefore there is no 'clean' way to tell them apart. Here we rely on // an implementation detail of the AspectJ compiler. for (Field field : clazz.getDeclaredFields()) { if (field.getName().startsWith(AJC_MAGIC)) { return true; } } return false; }
2.1.4》如果是Aspect切面会进行if里面的操作:aspectNames 添加该aspect的名称、并且解析方法内部的advisor通知信息(List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);)
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) { Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass(); String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName(); validate(aspectClass); // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator // so that it will only instantiate once. MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory = new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory); List<Advisor> advisors = new ArrayList<>(); for (Method method : getAdvisorMethods(aspectClass)) { // Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect // to getAdvisor(...) to represent the "current position" in the declared methods list. // However, since Java 7 the "current position" is not valid since the JDK no longer // returns declared methods in the order in which they are declared in the source code. // Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods // discovered via reflection in order to support reliable advice ordering across JVM launches. // Specifically, a value of 0 aligns with the default value used in // AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor). Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName); if (advisor != null) { advisors.add(advisor); } } // If it's a per target aspect, emit the dummy instantiating aspect. if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) { Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory); advisors.add(0, instantiationAdvisor); } // Find introduction fields. for (Field field : aspectClass.getDeclaredFields()) { Advisor advisor = getDeclareParentsAdvisor(field); if (advisor != null) { advisors.add(advisor); } } return advisors; } private List<Method> getAdvisorMethods(Class<?> aspectClass) { final List<Method> methods = new ArrayList<>(); ReflectionUtils.doWithMethods(aspectClass, method -> { // Exclude pointcuts if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) { methods.add(method); } }, ReflectionUtils.USER_DECLARED_METHODS); if (methods.size() > 1) { methods.sort(METHOD_COMPARATOR); } return methods; }
上面代码getAdvisorMethods(aspectClass) 可以看到会解析到@Aspect类里面的方法并且排除掉Pointcut修饰的方法。getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName) 会创建一个Advisor,如下:
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrderInAspect, String aspectName) { validate(aspectInstanceFactory.getAspectMetadata().getAspectClass()); AspectJExpressionPointcut expressionPointcut = getPointcut( candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass()); if (expressionPointcut == null) { return null; } return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod, this, aspectInstanceFactory, declarationOrderInAspect, aspectName); }
2.2 findAdvisorsThatCanApply 里面根据pointcut里面的方法判断bean可以使用的Advisor
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findAdvisorsThatCanApply
protected List<Advisor> findAdvisorsThatCanApply( List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) { ProxyCreationContext.setCurrentProxiedBeanName(beanName); try { return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass); } finally { ProxyCreationContext.setCurrentProxiedBeanName(null); } }
org.springframework.aop.support.AopUtils#findAdvisorsThatCanApply 如下:
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) { if (candidateAdvisors.isEmpty()) { return candidateAdvisors; } List<Advisor> eligibleAdvisors = new ArrayList<>(); for (Advisor candidate : candidateAdvisors) { if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) { eligibleAdvisors.add(candidate); } } boolean hasIntroductions = !eligibleAdvisors.isEmpty(); for (Advisor candidate : candidateAdvisors) { if (candidate instanceof IntroductionAdvisor) { // already processed continue; } if (canApply(candidate, clazz, hasIntroductions)) { eligibleAdvisors.add(candidate); } } return eligibleAdvisors; } 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; } }
2.3》然后在extendAdvisors(eligibleAdvisors); 将ExposeInvocationInterceptor 加到第一个调用链
org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator#extendAdvisors
protected void extendAdvisors(List<Advisor> candidateAdvisors) { AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors); }
接着调用: org.springframework.aop.aspectj.AspectJProxyUtils#makeAdvisorChainAspectJCapableIfNecessary
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; }
(2) 继续查看org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary 里面获取到Advisor之后调用createProxy 方法创建代理对象
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy
protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) { if (this.beanFactory instanceof ConfigurableListableBeanFactory) { AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass); } ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.copyFrom(this); if (!proxyFactory.isProxyTargetClass()) { if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); } else { evaluateProxyInterfaces(beanClass, proxyFactory); } } Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); proxyFactory.addAdvisors(advisors); proxyFactory.setTargetSource(targetSource); customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy); if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); } return proxyFactory.getProxy(getProxyClassLoader()); }
0》前期准备advisor等操作
1》org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader) 获取代理对象如下:
public Object getProxy(@Nullable ClassLoader classLoader) { return createAopProxy().getProxy(classLoader); }
org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy 获取AOP代理方式如下:
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); } }
可以看到选择代理工厂的方式是根据ProxyTargetClass来判断。也就是当target有实现接口默认使用JDK代理,否则使用Cglib。当然可以在App上指定强制使用Cglib
@EnableAspectJAutoProxy(proxyTargetClass = true)
2》接下来调用 代理工程生成代理对象:
2.1》org.springframework.aop.framework.JdkDynamicAopProxy#getProxy(java.lang.ClassLoader) 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); }
可以看到使用了JDK的代理模式, InvocationHandler 是自身,也就是处理逻辑在自己内部实现:org.springframework.aop.framework.JdkDynamicAopProxy#invoke
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; TargetSource targetSource = this.advised.targetSource; Object target = null; try { if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { // The target does not implement the equals(Object) method itself. return equals(args[0]); } else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { // The target does not implement the hashCode() method itself. return hashCode(); } else if (method.getDeclaringClass() == DecoratingProxy.class) { // There is only getDecoratedClass() declared -> dispatch to proxy config. return AopProxyUtils.ultimateTargetClass(this.advised); } else if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) { // Service invocations on ProxyConfig with the proxy config... return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); } Object retVal; if (this.advised.exposeProxy) { // Make invocation available if necessary. oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } // 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); // 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(); } // Massage return value if necessary. Class<?> returnType = method.getReturnType(); if (retVal != null && retVal == target && returnType != Object.class && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { // Special case: it returned "this" and the return type of the method // is type-compatible. Note that we can't help if the target sets // a reference to itself in another returned object. retVal = proxy; } else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) { throw new AopInvocationException( "Null return value from advice does not match primitive return type for: " + method); } return retVal; } finally { if (target != null && !targetSource.isStatic()) { // Must have come from TargetSource. targetSource.releaseTarget(target); } if (setProxyContext) { // Restore old proxy. AopContext.setCurrentProxy(oldProxy); } } }
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); 获取到核心的调用链,也就是advice链条。
可以看到核心的代理逻辑被转交给ReflectiveMethodInvocation,并且传入上面的advice链条。
org.springframework.aop.framework.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); } }
关于使用Advice调用链然后调用过程之后研究。
2.2 》 Cglib创建对象过程:org.springframework.aop.framework.CglibAopProxy#getProxy()
@Override public Object getProxy(@Nullable ClassLoader classLoader) { if (logger.isTraceEnabled()) { logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource()); } try { Class<?> rootClass = this.advised.getTargetClass(); Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy"); Class<?> proxySuperClass = rootClass; if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) { proxySuperClass = rootClass.getSuperclass(); Class<?>[] additionalInterfaces = rootClass.getInterfaces(); for (Class<?> additionalInterface : additionalInterfaces) { this.advised.addInterface(additionalInterface); } } // Validate the class, writing log messages as necessary. validateClassIfNecessary(proxySuperClass, classLoader); // Configure CGLIB Enhancer... 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); } catch (CodeGenerationException | IllegalArgumentException ex) { throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() + ": Common causes of this problem include using a final class or a non-visible class", ex); } catch (Throwable ex) { // TargetSource.getTarget() failed throw new AopConfigException("Unexpected AOP exception", ex); } }
2.2.1》org.springframework.aop.framework.CglibAopProxy#getCallbacks 获取回调Callback数组如下:(这个就和之前测试的Callback数组一样)
private Callback[] getCallbacks(Class<?> rootClass) throws Exception { // Parameters used for optimization choices... boolean exposeProxy = this.advised.isExposeProxy(); boolean isFrozen = this.advised.isFrozen(); boolean isStatic = this.advised.getTargetSource().isStatic(); // Choose an "aop" interceptor (used for AOP calls). Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised); // Choose a "straight to target" interceptor. (used for calls that are // unadvised but can return this). May be required to expose the proxy. Callback targetInterceptor; if (exposeProxy) { targetInterceptor = (isStatic ? new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) : new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource())); } else { targetInterceptor = (isStatic ? new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) : new DynamicUnadvisedInterceptor(this.advised.getTargetSource())); } // Choose a "direct to target" dispatcher (used for // unadvised calls to static targets that cannot return this). Callback targetDispatcher = (isStatic ? new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp()); Callback[] mainCallbacks = new Callback[] { aopInterceptor, // for normal advice targetInterceptor, // invoke target without considering advice, if optimized new SerializableNoOp(), // no override for methods mapped to this targetDispatcher, this.advisedDispatcher, new EqualsInterceptor(this.advised), new HashCodeInterceptor(this.advised) }; Callback[] callbacks; // If the target is a static one and the advice chain is frozen, // then we can make some optimizations by sending the AOP calls // direct to the target using the fixed chain for that method. if (isStatic && isFrozen) { Method[] methods = rootClass.getMethods(); Callback[] fixedCallbacks = new Callback[methods.length]; this.fixedInterceptorMap = new HashMap<>(methods.length); // TODO: small memory optimization here (can skip creation for methods with no advice) for (int x = 0; x < methods.length; x++) { Method method = methods[x]; List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass); fixedCallbacks[x] = new FixedChainStaticTargetInterceptor( chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass()); this.fixedInterceptorMap.put(method, x); } // Now copy both the callbacks from mainCallbacks // and fixedCallbacks into the callbacks array. callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length]; System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length); System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length); this.fixedInterceptorOffset = mainCallbacks.length; } else { callbacks = mainCallbacks; } return callbacks; }
debug查看获取到的Callbacks链条如下: (DnamicAdvisedInteceptor 也是Cglib代理调用的入口)
2.2.2》由于是多个Callback,所以需要设置CallbackFilter,否则cglib会报错(不知道应该用哪个Callback-这里没有用链条模式进行依次调用,只是根据CallbackFilter中返回的下标拿到Callback进行单个调用)
org.springframework.aop.framework.CglibAopProxy.ProxyCallbackFilter#accept 选择方法如下:
public int accept(Method method) { if (AopUtils.isFinalizeMethod(method)) { logger.trace("Found finalize() method - using NO_OVERRIDE"); return NO_OVERRIDE; } if (!this.advised.isOpaque() && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) { if (logger.isTraceEnabled()) { logger.trace("Method is declared on Advised interface: " + method); } return DISPATCH_ADVISED; } // We must always proxy equals, to direct calls to this. if (AopUtils.isEqualsMethod(method)) { if (logger.isTraceEnabled()) { logger.trace("Found 'equals' method: " + method); } return INVOKE_EQUALS; } // We must always calculate hashCode based on the proxy. if (AopUtils.isHashCodeMethod(method)) { if (logger.isTraceEnabled()) { logger.trace("Found 'hashCode' method: " + method); } return INVOKE_HASHCODE; } Class<?> targetClass = this.advised.getTargetClass(); // Proxy is not yet available, but that shouldn't matter. List<?> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); boolean haveAdvice = !chain.isEmpty(); boolean exposeProxy = this.advised.isExposeProxy(); boolean isStatic = this.advised.getTargetSource().isStatic(); boolean isFrozen = this.advised.isFrozen(); if (haveAdvice || !isFrozen) { // If exposing the proxy, then AOP_PROXY must be used. if (exposeProxy) { if (logger.isTraceEnabled()) { logger.trace("Must expose proxy on advised method: " + method); } return AOP_PROXY; } // Check to see if we have fixed interceptor to serve this method. // Else use the AOP_PROXY. if (isStatic && isFrozen && this.fixedInterceptorMap.containsKey(method)) { if (logger.isTraceEnabled()) { logger.trace("Method has advice and optimizations are enabled: " + method); } // We know that we are optimizing so we can use the FixedStaticChainInterceptors. int index = this.fixedInterceptorMap.get(method); return (index + this.fixedInterceptorOffset); } else { if (logger.isTraceEnabled()) { logger.trace("Unable to apply any optimizations to advised method: " + method); } return AOP_PROXY; } } else { // See if the return type of the method is outside the class hierarchy of the target type. // If so we know it never needs to have return type massage and can use a dispatcher. // If the proxy is being exposed, then must use the interceptor the correct one is already // configured. If the target is not static, then we cannot use a dispatcher because the // target needs to be explicitly released after the invocation. if (exposeProxy || !isStatic) { return INVOKE_TARGET; } Class<?> returnType = method.getReturnType(); if (targetClass != null && returnType.isAssignableFrom(targetClass)) { if (logger.isTraceEnabled()) { logger.trace("Method return type is assignable from target type and " + "may therefore return 'this' - using INVOKE_TARGET: " + method); } return INVOKE_TARGET; } else { if (logger.isTraceEnabled()) { logger.trace("Method return type ensures 'this' cannot be returned - " + "using DISPATCH_TARGET: " + method); } return DISPATCH_TARGET; } } }
2.2.3》org.springframework.aop.framework.CglibAopProxy#createProxyClassAndInstance 如下:
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) { enhancer.setInterceptDuringConstruction(false); enhancer.setCallbacks(callbacks); return (this.constructorArgs != null && this.constructorArgTypes != null ? enhancer.create(this.constructorArgTypes, this.constructorArgs) : enhancer.create());
至此,cglib 代理对象创建完成。
对象创建完成之后会返回代理对象,然后放入容器中,也就是容器存放的是代理对象作为对应beanName的primary对象。
下节研究AOP的调用过程。