Spring AOP的介绍:
什么是Spring AOP:
面向切面编程,基于动态代理实现的,如果动态代理不了解的,可以翻阅我其它的博客;也就是在执行方法前、方法后和出现异常后做拦截或者做增强处理,我们常用的使用方式就是@AspectJ注解、自己可以使用spring后置处理器自己来实现或者通过实现接口的方式、XML配置的方式;
AOP与AspectJ的关系:
Aspect属于Eclipse基金会,增强的方式是静态织入,它是通过修改代码来实现的,要使用它还要使用它特定的编译器;
SringAO和AspectJ没有什么关系,只是使用了AspectJ的一些概念,用到了其切点解析和匹配。
Spring Aop的发展:
Spring 3.2 以后,spring-core 直接就把 CGLIB 和 ASM 的源码包括进来了,这样在使用CGLB代理是不需要显示的引入这两个依赖。
- Spring 1.2 基于接口的配置:最早的 Spring AOP 是完全基于几个接口的,想看源码的同学可以从这里起步。
- Spring 2.0 schema-based 配置:Spring 2.0 以后使用 XML 的方式来配置,使用 命名空间
- Spring 2.0 @AspectJ 配置:使用注解的方式来配置,这种方式感觉是最方便的,还有,这里虽然叫 做@AspectJ,但是这个和 AspectJ 其实没啥关系。
先来介绍Spring 1.2中基于接口的Aop ,直接上代码,不做介绍了,因为太简单了。
定义advice和intercepter:
public class MyLogAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
//Object invoke = method.invoke(target, args);
String name = method.getName();
System.out.println("执行目标方法:"+name+"的前置通知,入参为:"+ Arrays.asList(args));
}
}
public class MyInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod();
System.out.println("执行目标方法前置通知:"+method.getName());
Object proceed = invocation.proceed();
System.out.println("执行目标方法后置置通知:"+method.getName());
return proceed;
}
}
定义一个目标方法:
```java
@Component
public class MyCalculate implements Calculate {
private int num = 0;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
@Override
public int add(int numA, int numB) {
System.out.println("执行目标方法:add");
//1 / 0
return numA + numB;
}
@Override
public int sub(int numA, int numB) {
System.out.println("执行目标方法:sub");
return numA - numB;
}
}
加入到容器中
@Bean
public Calculate calculate() {
return new MyCalculate();
}
@Bean
public MethodBeforeAdvice myLogAdvice() {
return new MyLogAdvice();
}
@Bean
public MyInterceptor myInterceptor() {
return new MyInterceptor();
}
然后利用FactoryBean创建代理类;
@Bean
public ProxyFactoryBean proxyFactoryBean() {
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
proxyFactoryBean.setInterceptorNames("myLogAdvice","myInterceptor");
proxyFactoryBean.setTarget(calculate());
return proxyFactoryBean;
}
执行一下
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AopConfig.class);
Calculate calculate = context.getBean("proxyFactoryBean",Calculate.class);
//calculate.sub(7, 8);
calculate.add(1, 2);
结果为:
从结果看,使用了责任链的方式对advice和Intercept都进行了调用,使用了FactoryBean的getObject方法创建一个代理类实现的。
下面介绍Advisor,它包含了advice增强和porintCut切点。Advisor有好几个实现类,比如NameMatchMethodPointcutAdvisor
@Bean
public NameMatchMethodPointcutAdvisor nameMatchMethodPointcutAdvisor(){
NameMatchMethodPointcutAdvisor advisor = new NameMatchMethodPointcutAdvisor();
advisor.setAdvice(myLogAdvice());
advisor.setMappedName("add");
return advisor;
}
@Bean
public ProxyFactoryBean proxyFactoryBean() {
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
proxyFactoryBean.setInterceptorNames("nameMatchMethodPointcutAdvisor");
proxyFactoryBean.setTarget(calculate());
return proxyFactoryBean;
}
只对add方法进行拦截
自动生成代理类:BeanNameAutoProxyCreator
@Bean
public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
beanNameAutoProxyCreator.setInterceptorNames("myLogAdvice");
beanNameAutoProxyCreator.setBeanNames("calculate");
return beanNameAutoProxyCreator;
}
其实 Advisor 还有一个更加灵活的实现类 RegexpMethodPointcutAdvisor,它能实现正则匹配
DefaultAdvisorAutoProxyCreator,它的配置非常简单,直接使用下面这段配置就可以了,它 就会使得所有的 Advisor 自动生效,无须其他配置。(记得把之前的autoProxyCreator配置去掉,无需创建2次代理)
@Bean
public DefaultAdvisorAutoProxyCreator autoProxyCreator(){
return new DefaultAdvisorAutoProxyCreator();
}
下面进入正题:Spring Aop @Aspect注解的源码解析
先上自己画的流程图:
直接上代码:不做过多解释,因为代码上都有注释:
使用AOP前要在配置类加上@EnableAspectJAutoProxy注解,其有proxyTargetClass属性,当为ture则强制使用CGLB,如果不设置默认为false,自己判断使用JDK还是CGLB,它的作用就是加入AOP代理对象的创建类AnnotationAwareAspectJAutoProxyCreator
因为Aop代理对象实现了后置处理器SmartInstantiationAwareBeanPostProcessor,所以容器启动的过程中,会为符合AOP规则的bean创建动态代理加入到容器中;
容器在启动的时候会在九处调用后置处理器,如下图,也是自己画的:
那么接下来直接上代码:
容器启动的时候会执行org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation:
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
//获取当前bean是否可以创建AOP的缓存
Object cacheKey = getCacheKey(beanClass, beanName);
//当前是否为是 TargetSource对象,通过自定义targetSource对象可以获取对象,这里就不对此用法做出详解
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
//判断当前bean是否被解析过
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
//1、判断当前Bean是否A为OP的相关基础类Advice.class Pointcut.class Advisor.class AopInfrastructureBean
//2、判断当前bean是否为AspectJPointcutAdvisor :如果 <aop:aspect ref="beanName"> 就会生成此类
//3、如何符合上述条件,则说明不需要进行AOP,加入到缓存中advisedBeans.put(cacheKey, Boolean.FALSE);
//shouldSkip这个里面的逻辑还是比较多的:
// a、它会获取xml配置的Advisor和原生接口的AOP的Advisor ,在第一次doCreateBean时会把获取
//到的beanName缓存到BeanFactoryAdvisorRetrievalHelper.cachedAdvisorBeanNames缓存中,后面会接着使用
// b、获取@Aspect中配置的Advisor,把得到的Advisor的beanName缓存BeanFactoryAspectJAdvisorsBuilder.aspectBeanNames,
// 的到的对象缓存到Map<String, List<Advisor>> advisorsCache = new ConcurrentHashMap<>()
//c、接着判断当前bean是否是AspectJPointcutAdvisor
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
//如果是自定义的 TargetSource对象,则不进行后面doCreateBean的操作,直接进行AOP的操作
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
接着执行org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization,也就是这一步创建了代理对象。
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
//获取当前Bean相关AOP使用的Key;
Object cacheKey = getCacheKey(bean.getClass(), beanName);
//因为循环依赖创建的AOP动态代理,则不在创建,并且直接移除
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
//这个里面逻辑比较多,是AOP创建动态代理并且返回
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
下面的代码时上面两个方法入口的具体细节方法,如果后期自己调试,可以根据我的注释进行理解:
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// TODO: Consider optimization by caching the list of the aspect names
//找到所有候选的Advisors(通知 前置通知、后置通知等..)InstantiationModelAwarePointcutAdvisorImpl
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 判断这个类的原因在于:
// AspectJPointcutAdvisor 是xml <aop:advisor 解析的对象
// 如果 <aop:aspect ref="beanName"> 是当前beanName 就说明当前bean是切面类 那就跳过。
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}
public List<Advisor> buildAspectJAdvisors() {
//获取缓存中切面
List<String> aspectNames = this.aspectBeanNames;
//如果切面不为null,则所用已经解析过容器中的切面,不用在进行解析
if (aspectNames == null) {
//加锁
synchronized (this) {
//再进行一次判断
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
//获取根据类型获取容器中所有的BeanName, 包括Bean定义和一级缓存中的;传的是object类型,说明获取所有的beanName
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.
//通过beanName获取class对象
Class<?> beanType = this.beanFactory.getType(beanName, false);
if (beanType == null) {
continue;
}
//判断当前class是否有@Aspect 是否为切面 (其实也判断了属性中是否有ajc$开开通的)
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
//把beanName和class对象构建成一个AspectMetadata对象
AspectMetadata amd = new AspectMetadata(beanType, beanName);
/**
* AspectJ的singleton、perthis、pertarget、pertypewithin实例化模型(目前不支持percflow、percflowbelow) 参见枚举类PerClauseKind
* // 他将为每个被切入点表达式匹配上的代理对象,都创建一个新的切面实例(此处允许HelloService是接口)
* @Aspect("perthis(this(com.fsx.HelloService))")
* @Aspect("pertarget(切入点表达式)")指定切入点表达式; 此处要求HelloService不能是接口
*
* 另外需要注意一点:若在Spring内要使用perthis和pertarget,请把切面的Scope定义为:prototype
*
*/
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
//根据容器对象和beanName构建切面工厂对象
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
//advisorFactory= new ReflectiveAspectJAdvisorFactory(beanFactory) 其在初始化AnnotationAwareAspectJAutoProxyCreator中赋值的
//根据切面 获取所有的Advisor对象InstantiationModelAwarePointcutAdvisorImpl
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
//加入到缓存中,key为beanName,value为解析出来的Advisor对象集合
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;
//返回容器中所有的Advisor对象
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;
}
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.
//找根据当前的bean,找到符合的advisor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
//在缓存中,标记为已经处理
this.advisedBeans.put(cacheKey, Boolean.TRUE);
//创建我们真正的代理对象:传参为 当前beanClass beanName 符合的Advisor 当前bean
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;
}
@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
//根据bean找到合适的daviosr
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
//找到所有候选的Advisor,这一步会走缓存,因为在第一次创建bean的时候,在实例化之前已经把容器中所有的Advisor进行了缓存
//包括:XML中配置的,传统的实现了Advisor接口的和@AspectJ注解的
List<Advisor> candidateAdvisors = findCandidateAdvisors();
//利用所有的的advisor和当前的bean相匹配,找到符合条件的Advisor,比如注解的会利用切点是否匹配到当前Bean中的任意method
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
//这一步主要是加入ExposeInvocationInterceptor.DefaultPointcutAdviso匿名内部类,其作用就是第一个在执行目标方法时,
//以责任链模式执行通知和切点时放在第一位执行,调用后面的真正通知方法
extendAdvisors(eligibleAdvisors);
//对Advisor进行排序:这个排序在5.2.7之后只能进行切面的排序了@Order这种注解排序,之前版本的spring是利用这个排序前面的排序反过来
//调用这一步之前已经排好序了,是解析切面创建Advisor对象时排序的Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
//把当前beanName放在ThreadLocal中
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
//从候选的Advisor中获取到beanName匹配的Advisor;逻辑比较多的
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
//把当前beanName放在ThreadLocal中
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
//定义一个装载载返回结果的list
List<Advisor> eligibleAdvisors = new ArrayList<>();
//循环候选的Advisor
for (Advisor candidate : candidateAdvisors) {
//IntroductionAdvisor只能应用于类级别的拦截,判断Advisor是否实现此接口;如果是则进行类级别的匹配ClassFilter getClassFilter()
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
//把匹配到当前bean的IntroductionAdvisor类型的Advisor加入到结果集中
eligibleAdvisors.add(candidate);
}
}
//如果候选的Advisor中存在IntroductionAdvisor,则为true,否则为false
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// already processed
//上面已经处理过了,就不需要处理了
continue;
}
//判断当前候选的Advisor是否匹配当前的bean,如果匹配,则加入到结果集中,一般为方法级别的匹配
if (canApply(candidate, clazz, hasIntroductions)) {
//如果匹配上,则进行
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
//ClassFilter getClassFilter()再次判断是否是IntroductionAdvisor
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
//判断是否为PointcutAdvisor,方法级别的匹配
else if (advisor instanceof PointcutAdvisor) {
//获取切点对象
PointcutAdvisor pca = (PointcutAdvisor) advisor;
//判断是否匹配,只要有一个方法匹配上就进行返回。兼容有AspectJ 切点表达式和实现内部AOP接口的方式的匹配
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn't have a pointcut so we assume it applies.
return true;
}
}
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
//进行类级别的过滤,通过AspectJ
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
/**
* 进行方法级别的过滤
*/
//如果pc.getMethodMatcher() 返回了MethodMatcher.TRUE,则匹配所有方法
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
//判断匹配器是否属于IntroductionAwareMethodMatcher,AspectJExpressionPointcut就是实现了此接口
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
//转换成IntroductionAwareMethodMatcher类型
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
//定义一个装class对象的集合
Set<Class<?>> classes = new LinkedHashSet<>();
//判断是否为代理对象,如果不是则加入到集合中
if (!Proxy.isProxyClass(targetClass)) {
classes.add(ClassUtils.getUserClass(targetClass));
}
//获取到当前bean的所有实现接口的class对象转载到集合中
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
//循环当前bean及其实现接口的所有class对象;
//为啥要获取接口中方法名称是否匹配呢,因为是兼容事物,事务的注解可以加在接口上
for (Class<?> clazz : classes) {
//获取class对象的所有方法对象
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
//循环所有的方法对象
for (Method method : methods) {
//利用切点皮匹配器进行方法的匹配,如果命中一个方法,则直接进行返回true,传参为当前方法对象和当前class对象
if (introductionAwareMethodMatcher != null ?
//通过切点表达式进行匹配 AspectJ方式 AspectJExpressionPointcut
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
//通过方法匹配器进行匹配 内置aop接口方式
methodMatcher.matches(method, targetClass)) {
//任意匹配,则直接返回,创建代理
return true;
}
}
}
return false;
}
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();
/**
* 把一些AOP的属性值传给代理工厂,比如proxyTargetClass是否全部使用CGLB代理 exposeProxy是否把当前对象暴露到当前线程中
* this.proxyTargetClass = other.proxyTargetClass;
* this.optimize = other.optimize;
* this.exposeProxy = other.exposeProxy;
* this.frozen = other.frozen;
* this.opaque = other.opaque;
*/
proxyFactory.copyFrom(this);
//如果没有强制使用CGLB代理
if (!proxyFactory.isProxyTargetClass()) {
//判断bean定义中有没有使用CGLB代理的属性,一般配置类上可以配置
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
//如果配置类没有指定,则如果当前Bean 有接口则是JDK动态代理,反之则是CGLB动态代理
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
//把传入的Advisor转成数组,把所有的增强器都转成Advisor类型
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
//把Advisor数组传给代理工厂
proxyFactory.addAdvisors(advisors);
//传入目标对象SingletonTargetSource
proxyFactory.setTargetSource(targetSource);
//空方法
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
//利用代理工厂创建代理对象;传参为类加载器对象,代理工厂已经具有了目标对象bean、 Advisor数组、使用JDK还是CGLB
return proxyFactory.getProxy(getProxyClassLoader());
}
public Object getProxy(@Nullable ClassLoader classLoader) {
// createAopProxy()来获取使用JDK代理JdkDynamicAopProxy 还是CGLB代理ObjenesisCglibAopProxy
return createAopProxy().getProxy(classLoader);
}
JDK动态代理
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
//这个advised其实就是ProxyFactory,其属性中有一个存储目标类所有接口class对象的数组,值是在前面的决定使用jdk
//动态代理设置上的
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
//这和我们创建普通的jdk动态代理一样
// Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
//第一个参数为类加载器 、第二个参数为目标类的所有接口的class对象,第三个参数为实现InvocationHandler接口的对象,
//也就是当前对象,它是实现了此方法;这样就完整返回了JDK动态代理对象
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
CGLB代理
@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...
//创建CGLB使用的Enhancer对象
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
//设置被代理的对象的class
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
//获取到callBack: DynamicAdvisedInterceptor DynamicUnadvisedExposedInterceptor
//SerializableNoOp StaticDispatcher AdvisedDispatcher new EqualsInterceptor(this.advised),
// new HashCodeInterceptor(this.advised)
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
//这个比较重要,因为后面设置了多个callBack, 这一步判断使用哪一个callBack ,正常下有7个callBack ,最重要的还是
//AOP的使用DynamicAdvisedInterceptor
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);
}
}
先看一下执行CGLB代理的方法,其实实现方式和JDK的一样,都是责任链:
/**
*
* @param proxy 代理对象
* @param method 目标方法
* @param args 方法参数
* @param methodProxy
* @return
* @throws Throwable
*/
@Override
@Nullable
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 {
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);
//这个advised是前面创建的ProxyFactry对象,可以拿到排好序的MethodInterceptor(这个是AOP自己的接口); 这个排序规则和spring-5之前的版本是不一样的
//ExposeInvocationInterceptor
//AspectJAroundAdvice
//MethodBeforeAdviceInterceptor
//AspectJAfterAdvice
//AfterReturningAdviceInterceptor
//AspectJAfterThrowingAdvice
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.
//如何没有Interceptor,则直接执行目标方法
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...
//递归chain顺序执行,责任链的形式,创建CGLB方法执行器:
//传参: 动态代理对象、被代理的目标对象、目标方法、目标方法参数、目标对象的calss对象、MethodProxy
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);
}
}
}
@Override
@Nullable
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);
}
}
}
下面的代码就是利用责任链执行通知方法和目标方法:
@Override
@Nullable
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
//interceptorOrInterceptionAdvice从-1开始
//当执行完所有的方法拦截器之后,最后一个执行目标方法;
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
//执行目标方法methodProxy.invoke(target, objects);
return invokeJoinpoint();
}
//分别按以下顺序递归调用拦截器 都实现了 MethodInterceptor接口
// ExposeInvocationInterceptor
// AspectJAroundAdvice
// //MethodBeforeAdviceInterceptor
// //AspectJAfterAdvice
// //AfterReturningAdviceInterceptor
// //AspectJAfterThrowingAdvice
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.
//调用MethodInterceptor拦截器的invoke方法,把当前对象ReflectiveMethodInvocation this传入
//因为是递归调用,每次执行invoke方法的参数都是第一步new CglibMethodInvocation对象(子类中调用父类的方法.则在父类中
// 获取的this就是子类对象)
/**
* 以ReflectiveAspectJAdvisorFactory中的Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class
* 顺序进行Advisor 的排序的,
* 每次都是递归调用当前的 proceed()方法,所以其属性currentInterceptorIndex每执行一次就会加一;每次按顺序获取
* 到不同的Advice,然后执行方法
* 以 ExposeInvocationInterceptor
* AspectJAroundAdvice
* // //MethodBeforeAdviceInterceptor
* // //AspectJAfterAdvice
* // //AfterReturningAdviceInterceptor
* // //AspectJAfterThrowingAdvice
* 为例:
* currentInterceptorIndex =0 先执行ExposeInvocationInterceptor : 把当前的CglibMethodInvocation暴露到threadLocal中,执行完成再清除
*
* currentInterceptorIndex =1 AspectJAroundAdvice :先执行环绕通知的前置通知:会调用环绕通知中的方法执行pjp.proceed();这样又会递归到CglibMethodInvocation.proceed方法
*
* currentInterceptorIndex =2 MethodBeforeAdviceInterceptor :先执行前置通知;然后调用CglibMethodInvocation.proceed方法
*
* currentInterceptorIndex =3 AspectJAfterAdvice :先执行CglibMethodInvocation.proceed方法(这一步会递归到这里,下标递增),在finally里包含了执行后置通知的代码
*
* currentInterceptorIndex =4 AfterReturningAdviceInterceptor :先执行CglibMethodInvocation.proceed方法(这一步会递归到这里,下标递增),然后执行返回通知方法
*
* currentInterceptorIndex =5 AspectJAfterThrowingAdvice :先执行CglibMethodInvocation.proceed方法(这一步会递归到这里,下标递增),在catch里包含了执行异常通知的代码
*
* currentInterceptorIndex =6 这时候满足了下标等于advice集合中元素的个数;执行invokeJoinpoint方法:methodProxy.invoke(this.target, this.arguments)
* 我们熟悉的执行目标对象方法
*
* 但currentInterceptorIndex =6 目标方法执行完毕,返回结果,那么返回到AspectJAfterThrowingAdvice,如果有异常执行异常通知的代码,执行完毕;
* 接着执行AfterReturningAdviceInterceptor执行返回通知方法,执行完毕;接着进入AspectJAfterAdvice执行
*
* 这样又会回到环绕通知的方法中pjp.proceed()执行完毕,环绕通知执行完毕
*
* 这样又因为currentInterceptorIndex =6是直接return的,所以 会进入到调用栈AspectJAfterThrowingAdvice接着执行:如果有异常测进入到catch中
* 接着进入finally包裹的MethodBeforeAdviceInterceptor后置通知方法,执行结束
* 进入AspectJAfterAdvice 执行finally里包含了执行后置通知的代码 执行结束
*
* 这个执行方案和之前方案的对比就是,如果前制通知没有执行成功则,后面的通知不会执行;之前的版本前置通知是放在调用链的最后一个,后置通知在finally,不管调用链是否执行成功
* 都会执行后置通知
*
*/
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
JDK动态代理执行方法:没有注释,因为正在的逻辑就是上面的责任链那块代码。
@Override
@Nullable
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);
}
}
}