SpringAop 源码解析
(一) - Aspect 切面方法的查找匹配过程
一、SpringAop Aspect 切面方法的查找匹配过程
SpringAop
是在项目中经常需要使用的框架,可以用来实现无侵入的逻辑增强。在使用 Aop
时,只需定义一个 Aspect
类,并加上相应的注解,Spring
内部已经帮我们封装好了代理过程,我们只需将精力放在对应的通知方法中即可。
比如有下面 bean
类:
@Component
public class TestAop {
public void test(){
System.out.println("test...");
}
}
然后再定义一个 Aspect
类:
@Aspect
@Component
@EnableAspectJAutoProxy(exposeProxy = true)
public class GlobAop {
/**
* 定义切入点
*/
@Pointcut("execution(public * com.demo.test.*.*(..)))")
public void BrokerAspect(){
}
@Before("BrokerAspect()")
public void doBeforeGame(JoinPoint jp){
String name = jp.getSignature().getName();
System.out.println(name+"方法开始执行!");
}
@After("BrokerAspect()")
public void doAfterGame(JoinPoint jp){
String name = jp.getSignature().getName();
System.out.println(name+"方法执行结束!");
}
@AfterReturning(value = "BrokerAspect()",returning = "result")
public void doAfterReturningGame(JoinPoint jp, Object result){
String name = jp.getSignature().getName();
System.out.println(name+"方法返回 = " + result);
}
@AfterThrowing(value = "BrokerAspect()",throwing = "e")
public void doAfterThrowingGame(JoinPoint jp, Exception e){
String name = jp.getSignature().getName();
System.out.println(name+"方法异常通知:"+e.toString());
}
@Around("BrokerAspect()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
return pjp.proceed();
}
}
使用时也只关心需要的 bean
:
public class App {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext("com.demo.test");
TestAop testAop = context.getBean("testAop", TestAop.class);
testAop.test();
}
}
从这个案例中可以看出 SpringAop
使用起来完全无侵入,只需定好 Aspect
类和对应的切面方法即可生效,下面一起从源码的角度分析下Aspect
切面方法的查找和匹配过程。
在源码分析的过程涉及到 Spring bean
加载的过程 和 BeanPostProcessor
扩展接口,两个知识点,不了解的可以参考下面两篇博客:
二、@EnableAspectJAutoProxy 做了什么
在使用 Aop
前,需要使用 @EnableAspectJAutoProxy
注解开启 Aop
的支持,这里从该注解着手开始分析,先看下该注解:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
// 开启 Aspectj自动代理
// 在springboot中,默认是会配置这个注解,并且默认用的是 cglib的代理,与之相对的是,spring默认用的是 jdk接口代理
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
/**
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
* to standard Java interface-based proxies. The default is {@code false}.
*/
//是否使用CGLIB代理和@AspectJ自动代理支持,该属性为true时,代表需要支持
boolean proxyTargetClass() default false;
/**
* Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
* for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
* Off by default, i.e. no guarantees that {@code AopContext} access will work.
* @since 4.3.1
*/
//是否对切面进行曝光
boolean exposeProxy() default false;
}
该注解使用 @Import
引入了 AspectJAutoProxyRegistrar
类,这个类其实是个动态代理的 bean生成处理器
,看到该类下:
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
/**
* Register, escalate, and configure the AspectJ auto proxy creator based on the value
* of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
* {@code @Configuration} class.
*/
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 这个方法在工厂中,注册了一个 AspectJ注解的自动代理生成器
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
// 这里类似于工厂后置方法,根据注解,修改bean定义
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
由于该类实现了 ImportBeanDefinitionRegistrar
接口,因此 Spring
启动时会触发 registerBeanDefinitions
方法,在该方法中会触发了 AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary
方法,其实是在注册动态代理的 bean生成处理器
,进到该方法下:
这里实际触发的 registerOrEscalateApcAsRequired
方法,并传入了 AnnotationAwareAspectJAutoProxyCreator.class
,这个就是动态代理的 bean生成处理器
,看到该方法下注册的过程:
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
//断言判断注册容器是否为空
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
//如果AUTO_PROXY_CREATOR_BEAN_NAME已经注册过了
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
//取出已经注册过的AUTO_PROXY_CREATOR_BEAN_NAME
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
//判断是不是同一个Class对象
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
//如果不是同一个对象,那就需要根据优先级来判断到底需要使用哪一个了
//获取当前AOP自动代理创建器的优先级
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
//获取指定的AOP自动代理创建器的优先级
int requiredPriority = findPriorityForClass(cls);
//进行优先级比较
if (currentPriority < requiredPriority) {
//如果指定的大于现在的,apcDefinition改变AOP自动代理创建器的class类型
//相当于进行升级动作
//由此可见,此时AOP自动代理创建器还没有实例出来,
//这里只是将Aop自动代理创建其的BeanDefinition的className进行修改
apcDefinition.setBeanClassName(cls.getName());
}
}
//如果是同一个Class对象,证明是同一个处理器
//返回,不需要进行注册
return null;
}
//如果还没进行注册
//使用Class去创建RootBeanDefinition,这里仅仅只是注入Class
//从上面代码中可以看到,是可以进行更改的
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
//封装一些信息
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
//注册进容器中,并且以AUTO_PROXY_CREATOR_BEAN_NAME为key
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
就是通过 BeanDefinitionRegistry
向 Spring IOC
容器中注入了 AnnotationAwareAspectJAutoProxyCreator
类。
三、AnnotationAwareAspectJAutoProxyCreator 做了什么
上一步已经得出 @EnableAspectJAutoProxy
,就是向 Spring IOC
中注入了 AnnotationAwareAspectJAutoProxyCreator
类,这里看下 AnnotationAwareAspectJAutoProxyCreator
的继承关系:
从继承树中可以看出 AnnotationAwareAspectJAutoProxyCreator
通过 BeanPostProcessor
获取 bean
初始化前后通知能力,从 SmartInstantiationAwareBeanPostProcessor
获得循环依赖时早期实例曝光能力,通过 ProxyProcessorSupport
获得代理能力。
这里关注下 BeanPostProcessor
扩展接口,在 BeanPostProcessor
中有 postProcessBeforeInitialization
和 postProcessAfterInitialization
两个重要的前后通知方法,而这两个方法和 Spring bean
初始化过程紧密相关,方法如下:
public interface BeanPostProcessor {
/**
* 实例化及依赖注入完成后、bean 初始化方法触发之前执行
*/
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
/**
* bean 初始化方法触发后执行
*/
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
如果还不了解 BeanPostProcessor
这里也简单提一下, BeanPostProcessor
的前后两个通知方法在 Spring
实例化过程中 AbstractAutowireCapableBeanFactory
类 initializeBean
方法中会被触发,如果通知方法返回的 bean
不为空就替换掉原先的 bean
,因此 BeanPostProcessor
有控制 bean
生成实例的能力,这也是为什么主要对他分析:
由于 AnnotationAwareAspectJAutoProxyCreator
类及其父类并没有对 postProcessBeforeInitialization
方法进行重写,而 postProcessAfterInitialization
方法在父类 AbstractAutoProxyCreator
类下有重写,因此这里可以猜测在postProcessAfterInitialization
方法中生成了代理对象,可以 debug
下AbstractAutowireCapableBeanFactory
类的 initializeBean
方法验证一下:
从 debug
的过程可以看出在 postProcessAfterInitialization
方法确实创建了一个代理对象,并且最后使用的也是代理对象,下面就主要分析下 AbstractAutoProxyCreator
类下的 postProcessAfterInitialization
方法。
进入到 AbstractAutoProxyCreator
类的 postProcessAfterInitialization
方法中:
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
//某个bean 已经实例化后
if (bean != null) {
//获取缓存的键名,这里的形式是beanClassName_beanName
Object cacheKey = getCacheKey(bean.getClass(), beanName);
//判断是否已经提前曝光代理过
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
//如果没被代理过,执行wrapIfNecessart
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
//如果bean为Null,直接返回,如果不为null,但已经被曝光出来,直接返回bean
//解决了循环依赖的问题
return bean;
}
这里判断了 earlyProxyReferences
是否有缓存过该 bean
,这样做的目的是在循环依赖的情况下是否已经提前曝光代理对象了,看过Spring
源码的应该知道,三级缓存中存储的是一个 ObjectFactory
,通过 getObject
获取早期实例,在Spring
放入三级缓存时,实际getObject
方法会触发 AbstractAutowireCapableBeanFactory
类的 getEarlyBeanReference
方法,逻辑如下:
这里会使用 SmartInstantiationAwareBeanPostProcessor
类型的通知器的 getEarlyBeanReference
方法获取一个早期实例,而AnnotationAwareAspectJAutoProxyCreator
也实现了 SmartInstantiationAwareBeanPostProcessor
因此会调用 getEarlyBeanReference
方法尝试获取一个早期对象,逻辑如下:
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
return wrapIfNecessary(bean, beanName, cacheKey);
}
这里先对 earlyProxyReferences
容器中加入了缓存,然后调用 wrapIfNecessary
方法生成代理对象,同样在上面的 postProcessAfterInitialization
方法中,如果 earlyProxyReferences
中不存在或者存在的和当前不是一个实例也会执行 wrapIfNecessary
方法获取代理对象。
下面就来分析 wrapIfNecessary
方法,进到该方法下:
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
//判断是不是已经增强过,根据 targetSourcedBeans 容器里面已经包含了这个 beanName
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)) {
//在 advusedBeans 容器增加标识,后面再出现直接中断
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
// 根据beanName拿到需要增强的方法
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));
//保存代理的Class类型
this.proxyTypes.put(cacheKey, proxy.getClass());
//返回代理实例
return proxy;
}
//如果不存在增强方法,则不需要进行代理
//写入标识,后面再出现直接中断
this.advisedBeans.put(cacheKey, Boolean.FALSE);
// 返回当前实例
return bean;
}
这里主要通过 getAdvicesAndAdvisorsForBean
方法,根据 beanName
获取到所有匹配的增强方法,也就是Aspect
中的切面方法,本篇文章重点分析的逻辑就在这里。
getAdvicesAndAdvisorsForBean
方法是个抽象方法,具体实现在 AbstractAdvisorAutoProxyCreator
类下,看该方法下:
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();
}
这里又调用 findEligibleAdvisors
方法获取当前 bean
匹配的增强方法,如果是空的话,则返回一个固定的空数组,在 wrapIfNecessary
方法中如果是这个固定的空数组,则标记直接返回,后续该类也直接返回不做处理。
下面进到 findEligibleAdvisors
方法中:
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
//获取所有的增强方法
List<Advisor> candidateAdvisors = findCandidateAdvisors();
//从所有的增强方法中匹配适合该 bean 的增强方法
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
//对匹配后的增强方法进行扩展
extendAdvisors(eligibleAdvisors);
//判断是否为空
if (!eligibleAdvisors.isEmpty()) {
//如果不为空,进行排序
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
//返回处理后的增强方法
return eligibleAdvisors;
}
这里使用 findAdvisorsThatCanApply
查找全部的增强方法,使用findAdvisorsThatCanApply
匹配出适合当前类的增强方法,这两个方法也是本篇的核心,下面挨个来分析下。
三、查找 Aspect 切面方法
findCandidateAdvisors
方法主要看 AnnotationAwareAspectJAutoProxyCreator
类下的重载:
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
// 调用父类的查找方法,父类是对配置文件中的信息进行解析,在Spring2.0之前仅支持配置文件
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;
}
这里也会调用父类 AbstractAdvisorAutoProxyCreator
下的 findCandidateAdvisors
方法,不过父类中的方法是对配置文件进行解析处理的,而下面的 aspectJAdvisorsBuilder.buildAspectJAdvisors
则是对注解形式处理的,由于现在基本都使用注解形式,所以这里直接看注解形式的处理,进到 BeanFactoryAspectJAdvisorsBuilder
类下的buildAspectJAdvisors
方法中:
public List<Advisor> buildAspectJAdvisors() {
//获取缓存中包含@Aspect注解的 BeanName,取之前缓存的数据
List<String> aspectNames = this.aspectBeanNames;
//如果缓存中不存在,则是第一次初始化
if (aspectNames == null) {
//加锁
synchronized (this) {
// 在获取一次缓存中的数据
aspectNames = this.aspectBeanNames;
// 判断是否还为空
if (aspectNames == null) {
//创建一个集合,存储解析后的 Advisor
List<Advisor> advisors = new ArrayList<>();
// 给 aspectNames 赋初始值
aspectNames = new ArrayList<>();
//获取所有的 beanName
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
// 遍历所有的 beanName
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.
// 检查bean的类型是否为空了
Class<?> beanType = this.beanFactory.getType(beanName, false);
// 如果bean的类型为空直接跳过了
if (beanType == null) {
continue;
}
//判断类上有无 @Aspect 注解
if (this.advisorFactory.isAspect(beanType)) {
//将 beanName 写入 aspectNames 集合中
aspectNames.add(beanName);
// 创建一个AspectMetadata,主要存储切面元数据,构造方法注入了 beanName 与 beanType
AspectMetadata amd = new AspectMetadata(beanType, beanName);
//判断切面的实例化模式
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
//如果是SINGLETON模式的话
//创建切面元数据的实例化工厂
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
//进行解析,取出里面的增强方法
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
//判断当前的beanName是不是单例的
if (this.beanFactory.isSingleton(beanName)) {
//如果是单例的,写入缓存,缓存的就是解析出来的增强方法
//key 为beanName,value 为classAdvisors
this.advisorsCache.put(beanName, classAdvisors);
}
else {
// 不是单例
// 缓存到切面工厂里
// key 为beanName,value为 factory
this.aspectFactoryCache.put(beanName, factory);
}
//将增强方法添加到 advisors 集合中
advisors.addAll(classAdvisors);
}
//如果实例化代理不是SINGLETON方式
else {
// Per target or per this.
// 判断当前beanName是否为单例模式
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 集合中
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
// 将带有 @Aspect 注解的 beanName 记到 aspectBeanNames 中
this.aspectBeanNames = aspectNames;
//返回解析出来的增强方法
return advisors;
}
}
}
// aspectBeanNames 不为空,代表已经进行初始化过了,要考虑从缓存中取了
//判断aspectNames是否为空
if (aspectNames.isEmpty()) {
//如果为空的话,代表没有切面,直接返回一个空集合
return Collections.emptyList();
}
//如果aspectNames不为空
//那么证明已经初始化过了,先考虑从缓存中取
List<Advisor> advisors = new ArrayList<>();
//遍历aspectNames里面所有的切面
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;
}
这个方法内容比较长,主要分了两个处理方向,第一个是缓存中不存在的情况,需要进行初始化,第二个是缓存中存在直接取数据使用,这里看到缓存中不存在的情况下:
首先对当前对象进行加锁,防止并发情况下 aspectBeanNames
出现线程安全问题。aspectBeanNames
主要缓存包含@Aspect
注解的 BeanName
。
然后从 Spring IOC
工厂中获取所有的 beanName
信息,并通过工厂拿到相应的 Class
类型,通过 advisorFactory.isAspect
方法判断是否为 Aspect
类,其实就是判断类上是否带有 @Aspect
注解,逻辑如下:
如果存在就存入 aspectNames
缓存中,再向下主要看到 this.advisorFactory.getAdvisors
方法,是一个抽象方法,具体逻辑由子类实现,其作用是用来对每个 Class
进行解析,取出里面的增强方法也就是切面方法,并封装成 Advisor
形式,这里看到 ReflectiveAspectJAdvisorFactory
类下的 getAdvisors
方法中:
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
//获取 Class 类型
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
//获取 beanName
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<>();
// 反射获取aspectClass中的方法
// 遍历获取到的方法
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 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结果集的第 0 个位置
advisors.add(0, instantiationAdvisor);
}
// Find introduction fields.
//获取aspectClass的所有被 @DeclaredParents 修饰的字段
for (Field field : aspectClass.getDeclaredFields()) {
//同样进行转化成Advisor对象,然后过滤掉一些不符合条件的字段
Advisor advisor = getDeclareParentsAdvisor(field);
//如果不为null,添加进结果集里面
if (advisor != null) {
advisors.add(advisor);
}
}
//最终返回结果集
return advisors;
}
首先获取到前面封装的 Class
类型和 beanName
,下面使用反射获取到 Class
中的 Method
,然后对获取到的 Method
使用 getAdvisor
方法检验是不是增强方法也就是切面方法,如果是话则包装成 Advisor
类型,下面看到 getAdvisor
方法中:
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) {
//如果没有切入点,直接返回null
return null;
}
//如果有切入点,就根据切点信息生成增强器
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
这里再次对标识的类进行校验,比如看类上是否还带有@Aspect
注解等,下面则调用 getPointcut
方法获取到 一个 AspectJExpressionPointcut
对象,其作用主要是判断 Method
是否是切面方法,如果是则封装成 AspectJExpressionPointcut
对象,AspectJExpressionPointcut
从命名就可以看出和 Expression
有关 ,主要用来对切点表达式的解析和匹配,下面在匹配切面方法时会使用到该类。
下面看到 getPointcut
方法:
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
//寻找方法上有无对应的注解
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
//判断有没有匹配的注解
if (aspectJAnnotation == null) {
//没有匹配的注解直接返回Null,
return null;
}
//使用 AspectJExpressionPointCut 来封装数据
AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
// 注入切入点的表达式,也就是规则拦截的表达式
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
if (this.beanFactory != null) {
//注入beanFactory
ajexp.setBeanFactory(this.beanFactory);
}
return ajexp;
}
第一步通过 AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod
寻找有无对应的注解,进到该方法中:
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
//遍历要匹配的注解,分别会处理: @Pointcut, @Around, @Before, @After, @AfterReturning, @AfterThrowing注解
for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
// 查找是否有当前注解
AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
//如果有就直接返回,可以看到如果给方法加上了多个注解,会根据 ASPECTJ_ANNOTATION_CLASSES 中的顺序前面的生效
if (foundAnnotation != null) {
return foundAnnotation;
}
}
return null;
}
遍历了 ASPECTJ_ANNOTATION_CLASSES
数组,该数组的内容如下:
其实就是挨个判断是否是 Aspect
中的注解,如果有包装成 AspectJAnnotation
对象返回,这里看到 findAnnotation
方法中是如何判断的:
private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method, Class<A> toLookFor) {
// 查找注解
A result = AnnotationUtils.findAnnotation(method, toLookFor);
if (result != null) {
return new AspectJAnnotation<>(result);
}
else {
return null;
}
}
使用 AnnotationUtils.findAnnotation
工具找寻对应的注解,如果存在则新建一个 AspectJAnnotation
对象,再看下 AspectJAnnotation
对象的构造方法中初始化可那些内容:
主要将切点表达式,以及 argNames
参数进行了保存,这里可以看下 debug
的内容:
就是 Aspect
类注解中配置的内容,再回到前面 getPointcut
方法中,第一步获取到注解信息后,如果存在则创建了一个 AspectJExpressionPointcut
对象,并将解析出来的 AspectJAnnotation
对象添加进去,同时也将Spring
工厂也添加进去,最后返回出去。
再回到 getAdvisor
方法中,获取到 AspectJExpressionPointcut
对象后,如果不为空就新建一个 InstantiationModelAwarePointcutAdvisorImpl
实例,该实例是 Advisor
的子类。
这里简单介绍下 Advisor
,它通常与Pointcut
和 Advice
组合使用,Pointcut
用于定义切入点,即确定需要被增强的代码位置。而 Advice
则是实际的增强逻辑,它可以在目标代码执行前、执行后或出现异常时进行增强。Advisor
则是将 Pointcut
和 Advice
进行组合的组件。
这里看到 InstantiationModelAwarePointcutAdvisorImpl
的构造方法中:
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
// 当前的切点表达式
this.declaredPointcut = declaredPointcut;
// 切面的 Class
this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
// 切面方法的名称
this.methodName = aspectJAdviceMethod.getName();
// 切面方法的参数类型
this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
// 切面方法
this.aspectJAdviceMethod = aspectJAdviceMethod;
// aspect 通知工厂
this.aspectJAdvisorFactory = aspectJAdvisorFactory;
// aspect 实例工厂
this.aspectInstanceFactory = aspectInstanceFactory;
// 切面的顺序
this.declarationOrder = declarationOrder;
// 切面的名称
this.aspectName = aspectName;
// 如果配置了增强延迟初始化
if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
// Static part of the pointcut is a lazy type.
// 切入点的静态部分是一个惰性类型
Pointcut preInstantiationPointcut = Pointcuts.union(
aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
// Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
// If it's not a dynamic pointcut, it may be optimized out
// by the Spring AOP infrastructure after the first evaluation.
this.pointcut = new PerTargetInstantiationModelPointcut(
this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
this.lazy = true;
}
else {
// A singleton aspect.
this.pointcut = this.declaredPointcut;
this.lazy = false;
// 非懒加载,直接初始化
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}
}
可以看到包含了切点表达式以及切面类信息,再下面判断是否为懒加载情况,如果不是则使用 instantiateAdvice
进行初始化 Advice
,前面提到 Advice
就是实际的增强逻辑,也就是切面方法,看到 instantiateAdvice
方法中:
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
//调用 aspectAdvisorFactory 来获取增强器
Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
return (advice != null ? advice : EMPTY_ADVICE);
}
调用了 aspectJAdvisorFactory.getAdvice
方法来获得 Advice
,再看到该方法下:
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
//获取切面的class
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
//校验
validate(candidateAspectClass);
//获取方法上的注解
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// If we get here, we know we have an AspectJ method.
// Check that it's an AspectJ-annotated class
if (!isAspect(candidateAspectClass)) {
throw new AopConfigException("Advice must be declared inside an aspect type: " +
"Offending method '" + candidateAdviceMethod + "' in class [" +
candidateAspectClass.getName() + "]");
}
if (logger.isDebugEnabled()) {
logger.debug("Found AspectJ method: " + candidateAdviceMethod);
}
//AbstractAspectJAdvice 其实就是增强器的一个抽象模板
AbstractAspectJAdvice springAdvice;
//对注解的类型进行判断
switch (aspectJAnnotation.getAnnotationType()) {
//如果是@PointCut类型
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
//@PointCut类型没有增强器,其代表的仅仅只是一个切入点
return null;
//如果是@Around类型
case AtAround:
//返回一个AspectJAroundAdvice
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
//如果是@Before类型
case AtBefore:
//返回一个AspectJMethodBeforeAdvice
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
//如果是@After类型
case AtAfter:
//返回一个AspectJAfterAdvice
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
//如果是一个@AfterReturning注解
case AtAfterReturning:
//返回一个AspectJAfterReturingAdvice
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
//获取@AfterReturing的属性
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
//判断是否为空,不为空就添加进springAdvice中
//这里对应的属性是returningName
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
//判断是不是@AfterThrowing注解
case AtAfterThrowing:
//返回一个AspectJAfterThrowingAdvice
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
//获取@AfterThrowing注解上的属性
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
//判断是否为空,不为空就添加进springAdvice中
//这里对应的属性是throwingName,
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
//如果不是上面的5种类型,抛错处理
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
// Now to configure the advice...
//接下来给建言添加一些配置
//注入切入的名称
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}
这里对不同类型的 Aspect
注解进行判断,生成不同的 AbstractAspectJAdvice
增强包装类,AbstractAspectJAdvice
是 Advice
的一个子类,这里以 @Before
类型为例,可以看下 AspectJMethodBeforeAdvice
类的实现:
上一步生成对应的 AbstractAspectJAdvice
增强实例后,在回到前面的 getAdvisor
方法中也就是已经声明好了 InstantiationModelAwarePointcutAdvisorImpl
Advisor
实例,再回到 getAdvisors
方法中,将获取到的 Advisor
实例放入了 advisors
集合中,最后返回给了前面的 buildAspectJAdvisors
方法中,接着判断如果是单例的话就将结果缓存下来,便于下次使用,最后在将结果返回给 findEligibleAdvisors
方法中。
在 findEligibleAdvisors
方法中,通过 findCandidateAdvisors
方法已经获取到了所有的增强方法,下面使用 findAdvisorsThatCanApply
进行匹配找出适合该 bean
的增强方法。
四、 匹配 Aspect 切面方法
进到 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);
}
}
第一步现将 beanName
记入ThreadLocal
中标记当前正在匹配的 beanName
,然后触发 AopUtils.findAdvisorsThatCanApply
方法进行匹配,看到该方法下:
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
// 创建一个合适的 Advisor 的集合 eligibleAdvisors
List<Advisor> eligibleAdvisors = new ArrayList<>();
//循环所有的Advisor
for (Advisor candidate : candidateAdvisors) {
// 判断切面是否匹配
//如果Advisor是 IntroductionAdvisor 引介增强 可以为目标类 通过AOP的方式添加一些接口实现
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
//是否有引介增强
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
//如果是IntroductionAdvisor类型的话 则直接跳过
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
// 判断切面是否匹配
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
这里逻辑主要分了两个方向是否为 IntroductionAdvisor
引介增强器,引介增强可以为目标类通过AOP
的方式添加一些接口实现,也就是使用 @DeclareParents
注解的情况下,前面我们分析的 Advisor
类型为InstantiationModelAwarePointcutAdvisorImpl
,这里也主要看下这种类型下的匹配过程,看下该类的继承关系:
属于 PointcutAdvisor
类型的 Advisor
,因此会通过 canApply
方法判断是否匹配,继续看到 canApply
方法中:
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) {
// IntroductionAdvisor,根据类过滤器,进行匹配
//如果是 IntroductionAdvisor 的话,则调用IntroductionAdvisor类型的实例进行类的过滤
//这里是直接调用的ClassFilter的matches方法
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
// 通常情况下 Advisor 都是 PointcutAdvisor 类型
else if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
// 从Advisor中获取Pointcut的实现类 就是是AspectJExpressionPointcut
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn't have a pointcut so we assume it applies.
return true;
}
}
这里又进行了类型判断,上面已经看到InstantiationModelAwarePointcutAdvisorImpl
属于 PointcutAdvisor
类型的 Advisor
,因此再看到 canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions)
方法中,注意 Pointcut
参数传递的 pca.getPointcut()
在声明 InstantiationModelAwarePointcutAdvisorImpl
下,其实就是 AspectJExpressionPointcut
:
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
//进行切点表达式的匹配最重要的就是 ClassFilter 和 MethodMatcher这两个方法的实现。
//首先进行ClassFilter的matches方法校验
//首先这个类要在所匹配的规则下
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
MethodMatcher methodMatcher = pc.getMethodMatcher();
// 通过切点的方法匹配策略 进行匹配
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
// 如果当前 MethodMatcher 也是IntroductionAwareMethodMatcher类型,则转为该类型
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
Set<Class<?>> classes = new LinkedHashSet<>();
if (!Proxy.isProxyClass(targetClass)) {
// 目标对象没有采用jdk动态代理,则要么是cglib代理,要么没有代理,获取到没有代理的原始类
classes.add(ClassUtils.getUserClass(targetClass));
}
// 获取到目标类的所有的超类接口
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
for (Class<?> clazz : classes) {
// 获取目标类即接口的方法,只要有一个方法满足切点条件,即视为切点可以匹配
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
// 只要有一个方法能匹配到就返回true
//MethodMatcher 中有两个 matches 方法。
// boolean matches(Method method, Class<?> targetClass) 用于静态的方法匹配
// boolean matches(Method method, Class<?> targetClass, Object... args) 用于运行期动态的进行方法匹配
for (Method method : methods) {
// 如果 MethodMatcher 是IntroductionAwareMethodMatcher类型,则使用该类型的方法进行匹配
// 否则使用 MethodMatcher.matches() 方法进行匹配
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
这里首先通过 pc.getClassFilter().matches
方法进行匹配,其中 getClassFilter()
方法就是 AspectJExpressionPointcut
类下的 getClassFilter()
方法:
public ClassFilter getClassFilter() {
obtainPointcutExpression();
return this;
}
最后返回的就是自己,也就是调用了 AspectJExpressionPointcut
类下的 matches(Class<?> targetClass)
进行判断的,这里先看下 obtainPointcutExpression()
方法中做了什么:
private PointcutExpression obtainPointcutExpression() {
if (getExpression() == null) { //表达式不存在,直接抛出异常
throw new IllegalStateException("Must set property 'expression' before attempting to match");
}
if (this.pointcutExpression == null) {
// 确认类加载器
this.pointcutClassLoader = determinePointcutClassLoader();
// 创建切点表达式
this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
}
return this.pointcutExpression;
}
其实是生成了一个切点表达式解析器,注意这个切点表达式解析器不是Spring
提供的,是采用的 aspectj
包提供的PointcutExpression
,关于 PointcutExpression
这里不做过多的介绍了,下面主要看到 obtainPointcutExpression()
是怎么创建切点表达式解析器的:
private PointcutExpression buildPointcutExpression(@Nullable ClassLoader classLoader) {
// 初始化切点解析器
PointcutParser parser = initializePointcutParser(classLoader);
PointcutParameter[] pointcutParameters = new PointcutParameter[this.pointcutParameterNames.length];
for (int i = 0; i < pointcutParameters.length; i++) {
pointcutParameters[i] = parser.createPointcutParameter(
this.pointcutParameterNames[i], this.pointcutParameterTypes[i]);
}
// 使用切点解析器进行解析表达式获取切点表达式
return parser.parsePointcutExpression(replaceBooleanOperators(resolveExpression()),
this.pointcutDeclarationScope, pointcutParameters);
}
第一步初始化了切点解析器,看到 initializePointcutParser
方法中,如何操作的:
private PointcutParser initializePointcutParser(@Nullable ClassLoader classLoader) {
// 获得切点解析器
PointcutParser parser = PointcutParser
.getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(
SUPPORTED_PRIMITIVES, classLoader);
parser.registerPointcutDesignatorHandler(new BeanPointcutDesignatorHandler());
return parser;
}
通过 PointcutParser
获取了一个解析器,在回到上一步buildPointcutExpression
方法中,这里将切点表达式填充到了切点解析器中生成 PointcutExpression
。
下面再看到 AspectJExpressionPointcut
下的 matches
方法:
public boolean matches(Class<?> targetClass) {
PointcutExpression pointcutExpression = obtainPointcutExpression();
try {
try {
// 使用切点表达式进行粗筛
return pointcutExpression.couldMatchJoinPointsInType(targetClass);
}
catch (ReflectionWorldException ex) {
logger.debug("PointcutExpression matching rejected target class - trying fallback expression", ex);
// Actually this is still a "maybe" - treat the pointcut as dynamic if we don't know enough yet
PointcutExpression fallbackExpression = getFallbackPointcutExpression(targetClass);
if (fallbackExpression != null) {
return fallbackExpression.couldMatchJoinPointsInType(targetClass);
}
}
}
catch (Throwable ex) {
logger.debug("PointcutExpression matching rejected target class", ex);
}
return false;
}
第一步就是拿到上面已经生成的 PointcutExpression
切点表达式,然后通过 couldMatchJoinPointsInType
判断 targetClass 是否符合。
下面回到前面的 findAdvisorsThatCanApply
方法中,如果 canApply
方法返回 true
也标识匹配成功,就将这个 Advisor
放入 eligibleAdvisors
集合中,最终返回给前面的 findEligibleAdvisors
方法中,在该方法中如果匹配的 Advisor
存在的话排序出先顺序,最终给到 wrapIfNecessary
方法中。
(二) - 代理对象的创建以及执行过程
一、SpringAop 代理创建 以及 执行过程
在上篇文章中分析得出在使用 Aop
时,实际向 Spring
容器中注入了一个 AnnotationAwareAspectJAutoProxyCreator
动态代理 bean
生成处理器,该类有实现 BeanPostProcessor
扩展方法,并且在 postProcessAfterInitialization
进行了代理的创建,主要逻辑在 AbstractAutoProxyCreator
类下的 wrapIfNecessary
方法中,上篇文章主要分析的该方法下getAdvicesAndAdvisorsForBean
方法,主要做了对切面方法的扫描和匹配过程,并且这里拿到的结果就是所有匹配的切面方法包装类集合,本篇文章继续上篇文章的脚步,分析下后面代理对象的创建过程和执行过程。
下面是上篇文章的地址:
二、动态代理类型的判断过程
上面文章分析到这个位置,下面继续,如果存在匹配的切面方法,则先进行标记,反之不存在也进行标记,下次再进来该 beanName
时,不存在就直接跳过了。
这里看到获取到匹配的切面方法后,通过 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());
}
这里创建了一个代理工厂,并将切面方法、目标 bean
资源等,设置进入了该代理工厂中。
下面主要看到 proxyFactory.getProxy
又是如何创建代理对象的:
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
这里首先使用 createAopProxy
方法创建一个 AopProxy
,然后再通过AopProxy
的 getProxy
生成代理对象。
这里先看到 createAopProxy
方法下,在 ProxyCreatorSupport
类中:
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
// 通过 aop动态代理工厂 创建 aop动态代理
return getAopProxyFactory().createAopProxy(this);
}
这里通过 AopProxyFactory
中 createAopProxy
创建一个 AopProxy
,默认情况下 AopProxyFactory
的具体实现为 DefaultAopProxyFactory
类,在ProxyCreatorSupport
类的无参构造方法中进行初始化的。
下面看到 DefaultAopProxyFactory
类中的 createAopProxy
方法中:
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (!IN_NATIVE_IMAGE &&
(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);
}
// 如果被代理对象没有实现接口,则使用 cglib 动态代理
return new ObjenesisCglibAopProxy(config);
}
else {
// 当前环境是否是原生环境,原生环境,使用 jdk动态代理
return new JdkDynamicAopProxy(config);
}
}
这里判断目标类是否有实现接口,如果有的话则使用 JDK
的动态代理,否则的话使用 cglib
进行代理。
下面回到上面的 getProxy
方法中,createAopProxy()
方法生成的要么是JDK
的动态代理,要么是 cglib
的动态代理,这里首先看下 JDK
动态代理的创建过程。
三、JDK 动态代理创建过程
这里先分析下 JdkDynamicAopProxy
类
可以看到实现了 InvocationHandler
接口,因此在执行代理时,会触发该类下的 invoke
方法。
再看下 JdkDynamicAopProxy
类的构造方法中做了什么事情:
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
//判断增强器和拦截器的数量
if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
//如果为0就抛出异常
throw new AopConfigException("No advisors and no TargetSource specified");
}
//注入配置
this.advised = config;
// 获取完整的代理接口,并进行缓存
this.proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
// 判断有没有定义的equals方法和hashCode方法
findDefinedEqualsAndHashCodeMethods(this.proxiedInterfaces);
}
这里先判断增强器也就是切面方法是否存在,如果不存在代理也没有意义了,接着将配置注入到 advised
属性中,最后标记出被代理类是否有定义 equals
方法和 hashCode
方法。
下面再看到 getProxy
方法,如何生成代理对象的:
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
// 通过JDK 的 Proxy完成动态代理
return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
}
直接通过 Proxy.newProxyInstance
创建代理实例,并且 InvocationHandler
就是自己,也就是触发执行代理时会触发该类下的 invoke
方法。
四、JDK 动态代理执行过程
JDK
动态代理执行,直接看到动态的代理的 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.
// 如果被代理对象没有重写 equals方法,则调用本地的方法。 比较的是被代理对象
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
// 如果被代理对象没有重写 hashCode 方法,则调用本地的 hashCode 方法。
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
// 如果实现了 DecoratingProxy的方法,则 分发给代理配置
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...
// 使用代理配置在ProxyConfig上调用服务
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
// 实际方法的返回值
Object retVal;
// 如果需要暴露至 threadLocal,则进行暴露
// 目的是在同一个类中自我方法调用的情况下
// 由于执行问题 被调用的无法执行代理
// 因此可以通过配置 exposeProxy 为 true,将代理方法缓存到 threadLocal 中
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;
}
//如果返回值为null,并且返回类型不是void类型,并且返回类型还被定义为基本数据类型
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);
}
//如果暴露过proxyContext
if (setProxyContext) {
// Restore old proxy.
// 恢复为原始的proxy
AopContext.setCurrentProxy(oldProxy);
}
}
}
这里讲下 this.advised.exposeProxy
的作用,该值就是使用 @EnableAspectJAutoProxy
注解中的 exposeProxy
参数,如果是 true
的话,则会对当前代理对象进行缓存,目的是在同一个类中自我方法调用的情况下,如果被调用的方法带有 @Transactional
或 @Async
等注解,直接调用方法注解会失效,因为指向的是this
指针,并不是代理类,因此可以设置 exposeProxy
参数为true,将代理类缓存下来,自我调用时使用 AopContext.currentProxy()
获取到当前的代理对象,例如下面的案例:
@Component
public class TestAop {
public void test(){
System.out.println("test...");
// 自我调用
((TestAop) AopContext.currentProxy()).test2();
}
@Transactional
public void test2(){
System.out.println("test2");
}
}
这里的缓存其实就是使用的 ThreadLocal
进行的存储:
在继续看 invoke
方法,下面使用 this.advised.getInterceptorsAndDynamicInterceptionAdvice
生成所有匹配的切面方法的执行链,下面看到该方法中:
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
return cached;
}
这里会对执行链进行缓存,这里看下缓存中不存在时,调用的 this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice
方法:
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) {
// 当切面匹配器已经在工作时,则放入 InterceptorAndDynamicMethodMatcher,运行时匹配
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;
}
在该方法中,获取到之前匹配出来的切面方法,再次进行筛选匹配。
下面再回到 invoke
方法中,接着向下看如果执行链为空则直接使用 AopUtils.invokeJoinpointUsingReflection
方法触发目标方法,逻辑如下:
public static Object invokeJoinpointUsingReflection(@Nullable Object target, Method method, Object[] args)
throws Throwable {
// Use reflection to invoke the method.
try {
ReflectionUtils.makeAccessible(method);
return method.invoke(target, args);
}
catch (InvocationTargetException ex) {
// Invoked method threw a checked exception.
// We must rethrow it. The client won't see the interceptor.
throw ex.getTargetException();
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
method + "] on target [" + target + "]", ex);
}
catch (IllegalAccessException ex) {
throw new AopInvocationException("Could not access method [" + method + "]", ex);
}
}
如果执行链存在,则根据切面的配置,构造一个 ReflectiveMethodInvocation
切面方法的执行链,执行链中包含了切面方法、目标方法、目标对象等:
protected ReflectiveMethodInvocation(
Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments,
@Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
this.proxy = proxy;
this.target = target;
this.targetClass = targetClass;
this.method = BridgeMethodResolver.findBridgedMethod(method);
this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
// 拦截器的动态方法匹配器
this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
}
再向下看则调用了 invocation.proceed()
,其实是触发所有的切面增强方法,最后再触发目标方法,看到 ReflectiveMethodInvocation
类中,逻辑如下:
public Object proceed() throws Throwable {
// 该方法为 jdk的AOP实现的核心
// 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);
}
//如果动态匹配失败,递归进行proceed
//不匹配就不执行当前的拦截器
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);
}
}
这里使用 currentInterceptorIndex
变量表示当前触发的第几个切面增强方法,首先判断的当 currentInterceptorIndex
等于interceptorsAndDynamicMethodMatchers
最后一个时,就是代表所有的切面方法都触发完了,这里的 invokeJoinpoint()
等一会再看。
先来看((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this)
是如何触发的目标切面方法,这里可以看到实现有很多种:
这里还是以 MethodBeforeAdviceInterceptor
为例,表示 @Before
前置通知方法:
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
// 继续触发下一个
return mi.proceed();
}
这里通过 this.advice.before
触发前置通知方法后,又递归的方式触发下一个切面增强方法。这里看下 this.advice.before
怎么触发的前置通知方法:
最终触发的是 invokeAdviceMethodWithGivenArgs
方法,逻辑如下:
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
//对参数处理
Object[] actualArgs = args;
if (this.aspectJAdviceMethod.getParameterCount() == 0) {
actualArgs = null;
}
try {
//下面就是通过反射来调用方法了
//先让方法变得可以访问
ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
// TODO AopUtils.invokeJoinpointUsingReflection
//使用切面实例共产获取切面实例,然后执行建言方法
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException("Mismatch on arguments to advice method [" +
this.aspectJAdviceMethod + "]; pointcut expression [" +
this.pointcut.getPointcutExpression() + "]", ex);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
通过反射直接触发目标切面方法。
下面再回到 proceed()
方法中,当执行完所有的切面方法后会触发 invokeJoinpoint
方法:
这里和前面无执行链时调用逻辑一样,使用AopUtils.invokeJoinpointUsingReflection
方法触发目标方法。
五、cglib 动态代理创建过程
cglib
动态代理和 JDK
动态代理实现逻辑大致相同,这里还是先看下继承关系:
继承了 CglibAopProxy
,主要代理创建的逻辑其实都在 CglibAopProxy
中,构造方法也是调用了父类的构造方法中:
public CglibAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
this.advisedDispatcher = new AdvisedDispatcher(this.advised);
}
同样也是将配置注入到 advised
属性中,下面主要看到 getProxy
方法 中:
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 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.
// 创建cglib动态代理实例
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);
}
}
这里主要声明了 cglib
中的 Enhancer
实例,并填充代理的信息,其中创建代理对象在 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 动态代理执行过程
在 JDK
动态代理时,触发代理类时会触发 invoke
方法,同样在 cglib
代理中,触发代理类时,会触发 Enhancer
中 callbacks
类中的 intercept
方法,下面就从 callbacks
开始分析:
在前一步创建代理时 callbacks
就是通过 getCallbacks
方法获取的结果,下面看到该方法下:
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).
// 创建 cgLib 层面的动态切面拦截器,动态代理通过它完成
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;
//判断是否要曝光
//根据是否要曝光并且是动态代理还是静态代理去生成拦截器
//这里的targetInterceptor拦截器称为目标拦截器
//这个拦截器的作用实质上没有对方法进行增强,但里面的额外操作会将当前代理对象切面曝光出来
//Cglib还支持静态代理咧。。。
if (exposeProxy) {
//如果要曝光,对应要创建exposedInterceptor
//并且从创建方法可以看到,直接给了目标对象,并没有给增强器
//在这里exposedInterceptor是会对代理对象进行曝光的
targetInterceptor = (isStatic ?
new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()));
}
else {
//如果不需要曝光,创建unadvvisedInterceptor,从名字就可以看出,是一个没有增强器的拦截器
//但其实还会对返回值做一些处理
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).
// 创建targetDispatcher,这个跟unadvisedInterceptor的作用其实差不多
// 直接执行目标对象的方法,本质上没有做其他任何其他增强操作,不过可能会对返回值做一些处理
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 = CollectionUtils.newHashMap(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);
//封装成FixedChainStaticTargetInterceptor存放进fixedCallBacks中
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都集合起来
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;
}
这里对切面增强方法生成了一个 DynamicAdvisedInterceptor
下面主要看下 DynamicAdvisedInterceptor
中的 intercept
方法:
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = this.advised.getTargetSource();
try {
// 如果需要暴露至 threadLocal,则进行暴露
// 目的是在同一个类中自我方法调用的情况下
// 由于执行问题 被调用的无法执行代理
// 因此可以通过配置 exposeProxy 为 true,将代理方法缓存到 threadLocal 中
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
// 获取被代理对象
target = targetSource.getTarget();
// 对被代理类进行非空安全检查
Class<?> targetClass = (target != null ? target.getClass() : null);
// 获取被代理类的当前方法的增强器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
// 如果没有匹配的通知器,则通过反射直接进行调用
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// We can skip creating a MethodInvocation: just invoke the target directly.
// Note that the final invoker must be an InvokerInterceptor, so we know
// it does nothing but a reflective operation on the target, and no hot
// swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// We need to create a method invocation...
// 通过过滤器链逐步执行连接点,每一个拦截器即是一个连接点
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
可以看到这里实现逻辑和JDK
代理时的大致相同,如果 exposeProxy
为true
,就缓存暴露至threadLocal
中,同样使用 this.advised.getInterceptorsAndDynamicInterceptionAdvice
生成切面增强方法链。
最后 proceed()
方法同样是触发的父类的方法,和 JDK
代理执行了相同的 proceed()
方法:
public Object proceed() throws Throwable {
try {
return super.proceed();
}
catch (RuntimeException ex) {
throw ex;
}
catch (Exception ex) {
if (ReflectionUtils.declaresException(getMethod(), ex.getClass())) {
throw ex;
}
else {
throw new UndeclaredThrowableException(ex);
}
}
}