Spring源码解读(4)AOP-代理的建立

一、概述

    Spring AOP的核心是基于代理实现的,代理有jdk基于接口的动态代理和基于asm实现的容许类没有接口的cglib代理,上一小结,已经分析过Spring封装了使用了@Aspect注解的类,并将切面方法封装成实现了AbstractAspectJAdvice的类放入缓存中,等待建立代理对象时使用,AbstractAspectJAdvice有三个参数:java

//切面方法 诸如使用了@Before这类的方法
Method aspectJAdviceMethod
//封装了expression表达式,给定一个类和方法名,能返回是否匹配
AspectJExpressionPointcut pointcut
//能够建立一个切面类,而后经过反射执行切面方法
AspectInstanceFactory aspectInstanceFactory
复制代码

    经过这个对象就能够拦截全部的类的建立找出符合条件的bean建立代理执行加强操做,这也是spring的实现原理。git

二、jdk代理

    jdk代理是基于接口的代理,因此被代理的对象必须是有接口实现的类,代理建立时经过Proxy.newProxyInstance实现的,这个方法有三个参数:github

//指定要使用的类加载器
ClassLoader loader,
//被代理的类所实现的接口,加强接口的方法
Class<?>[] interfaces,
//方法处理器,会拦截全部方法,而后执行加强参数。
InvocationHandler inoker
复制代码

    简单实例redis

    订单操做接口spring

public interface OrderUpdateService {
    /** * 订单付款 * @param orderAmt */
    void payOrder(String orderAmt);
}
复制代码

    订单操做实现类express

@Slf4j
public class OrderUpdateServiceImpl implements OrderUpdateService {

    public void payOrder(String orderAmt) {
        log.info("订单付款中.....");
    }
}
复制代码

    订单代理类数组

@Slf4j
public class OrderUpdateServiceImplProxy {
    //目标类 要加强的类
    private OrderUpdateService updateService;

    public OrderUpdateServiceImplProxy(OrderUpdateService updateService) {
        this.updateService = updateService;
    }

    public OrderUpdateService getProxy() {
        return (OrderUpdateService) Proxy.newProxyInstance(OrderUpdateServiceImplProxy.class.getClassLoader(), new Class[]{OrderUpdateService.class}, new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if ("payOrder".equals(method.getName())) {
                    log.info("付款前处理");
                    method.invoke(updateService, args);
                    log.info("付款后处理");
                }
                return proxy;
            }
        });
    }
}
复制代码

    demo验证缓存

public static void main(String[] args) {
    OrderUpdateService orderUpdateService = new OrderUpdateServiceImpl();
    OrderUpdateServiceImplProxy proxy = new OrderUpdateServiceImplProxy(orderUpdateService);
    orderUpdateService = proxy.getProxy();
    orderUpdateService.payOrder("100");
}
复制代码

    验证结果架构

11:18:07.859 [main] INFO  s.a.e.p.OrderUpdateServiceImplProxy - 付款前处理
11:18:07.890 [main] INFO  s.a.e.p.s.OrderUpdateServiceImpl - 订单付款中.....
11:18:07.890 [main] INFO  s.a.e.p.OrderUpdateServiceImplProxy - 付款后处理
复制代码

    payOrder方法的确时被加强了。app

三、cglib代理

    Cglib是一个强大的、高性能的代码生成包,它普遍被许多AOP框架使用,为他们提供方法的拦截。以下图所示Cglib与Spring等应用的关系。

  • 最底层的是字节码Bytecode,字节码是Java为了保证“一次编译、处处运行”而产生的一种虚拟指令格式,例如iload_0、iconst_一、if_icmpne、dup等
  • 位于字节码之上的是ASM,这是一种直接操做字节码的框架,应用ASM须要对Java字节码、Class结构比较熟悉
  • 位于ASM之上的是CGLIBGroovyBeanShell,后两种并非Java体系中的内容而是脚本语言,它们经过ASM框架生成字节码变相执行Java代码,这说明在JVM中执行程序并不必定非要写Java代码----只要你能生成Java字节码,JVM并不关心字节码的来源,固然经过Java代码生成的JVM字节码是经过编译器直接生成的,算是最“正统”的JVM字节码
  • 位于CGLIBGroovyBeanShell之上的就是HibernateSpring AOP这些框架了,这一层你们都比较熟悉
  • 最上层的是Applications,即具体应用,通常都是一个Web项目或者本地跑一个程序

    因此,Cglib的实现是在字节码的基础上的,而且使用了开源的ASM读取字节码,对类实现加强功能的。

    Cglib能够经过Callback回调函数完成对方法的加强,经过CallbackFilter函数过滤符合条件的函数,Spring也是基于这两个接口完成bean的加强功能的,因此能够猜想前面Advice参数的pointCut方法匹配器就是在CallbackFilter中起做用的。下来看看cglib的简单使用:

    下面的验证是拦截GameServiceplayGames方法,在playGames方法以前,执行TransactionManager类的startcommit方法。

@Test
public void testProxyFilter() throws Exception {
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(GameService.class);
    // NoOp.INSTANCE 表示没有被匹配的方法不执行任何操做 若是CallbackFilter返回0
    //表明使用callbacks集合中的第一个元素执行方法拦截策略 1 则使用第二个。
    Callback[] callbacks = {new TransactionInterceptor(), NoOp.INSTANCE};
    //设置回调函数集合
    enhancer.setCallbacks(callbacks);
    //根据回调过滤器返回指定回调函数索引
    enhancer.setCallbackFilter(new TransactionFilter());
    GameService gameService = (GameService) enhancer.create();
    Person person = new Person("lijinpeng", 26, false, new UserDao());
    gameService.setPerson(person);
    gameService.playGames();
}
复制代码

    执行结果:playGames获得了加强。

[2019-06-03 15:13:59] [INFO ][s.r.beans.models.aop.TransactionManager][15][start][]start tx
[2019-06-03 15:13:59] [INFO ][s.road.beans.models.scan.GameService][29][playGames][]person-name:lijinpeng play games
[2019-06-03 15:13:59] [INFO ][s.r.beans.models.aop.TransactionManager][20][commit][]commit tx
复制代码

    方法加强器

@Slf4j
public class TransactionManager {
    public void start() {
        log.info("start tx");
        MessageTracerUtils.addMessage("start tx");
    }

    public void commit() {
        log.info("commit tx");
        MessageTracerUtils.addMessage("commit tx");
    }

    public void rollback() {
        log.info("rollback tx");
        MessageTracerUtils.addMessage("rollback tx");
    }

    public Object getAspectInstance() {
        return new TransactionManager();
    }
}
复制代码

    方法拦截器

//方法拦截器 会拦截 全部方法 ,因此须要加判断 cglib 还提供了filter过滤器 能够用于过滤指定方法
public class TransactionInterceptor implements MethodInterceptor {
    
    TransactionManager tx = new TransactionManager();
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        tx.start();
        Object value = methodProxy.invokeSuper(o, objects);
        tx.commit();
        return value;
    }
}
复制代码

    经过CallbackFilter接口,能够自定义拦截加强策略,返回的是前面设置的Callbacks集合中的回调函数索引,这里的含义是,若是方法名是playGames则使用Callbacks集合中索引为0的回调函数即TransactionInterceptor,该回调函数就是要在playGames前执行TransactionManagerstart()方法,playGames方法后执行commit(),不然使用NoOp.INSTANCE表示什么也不作。

public class TransactionFilter implements CallbackFilter {
    //返回回调函数在集合中的索引
    public int accept(Method method) {
        if ("playGames".equals(method.getName())) {
            return 0;
        } else {
            return 1;
        }
    }
}
复制代码

    cglib代理经过Callback方法控制目标方法的加强逻辑,经过CallbackFilter用来指定适配的方法使用不通的回调函数完成不通的功能加强,cglib还能够为类动态得建立新得方法,不过知道cglib如何实现代理对Spring AOP的源码学习来讲已经足够了。

四、代理对象的校验

    在Spring中,并非全部的bean都须要建立代理,在Spring Aop中,只有被咱们配置的Aspect切面类的PointCut表达式匹配的类才会建立代理,因此在建立代理以前须要对要建立bean进行校验以判断该类是否须要被建立为代理对象。上一篇的结尾处分析过,当解析完@Aspect注解的切面类后,就会调用BeanPostProcessorpostProcessAfterInitialization的方法去建立一个代理对象,这个方法会调用wrapIfNecessary方法,这个方法会完成bean是否须要被建立为代理的校验,在这个方法里面,有一个核心的方法getAdvicesAndAdvisorsForBean,这个方法会返回一个Advisor数组集合,这个数组集合的Advisor即表示要建立的bean是否能被Advisor的Advice中的PointCut匹配到,若是能够匹配到,则为bean建立代理。AbstractAdvisorAutoProxyCreator完成这个方法的功能实现:

@Override
	protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
         //查找全部须要做用于beanClass的Advisor
		List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
		if (advisors.isEmpty()) {
             //直接返回null
			return DO_NOT_PROXY;
		}
		return advisors.toArray();
	}
复制代码

    核心方法是 findEligibleAdvisors(beanClass, beanName)

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
        //核心方法1:查找容器中全部已经生成了的Advisor,这是第二次执行
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
        //核心方法2:从容器中全部的Advisro找出可以做用于beanClass的Advisor
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
        //为Advisor提供钩子方法 方便扩展Advisor
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
             //根据Order排序Advisor
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}
复制代码

    这个方法首先又再次调用了findCandidateAdvisors方法,这个方法在解析切面类的时候也调用了一次,目的是为切面类的切面方法生成Advisor,并根据注解为每一个Advisor再生成一个Advice对象。这里第二次调用的目的是获取容器中全部生成过的Advisor,而后调用findAdvisorsThatCanApply方法找出全部可以做用于目标bean的AdvisorextendAdvisors方法是为了方便扩展AdvisorsortAdvisors是基于Order接口排序Advisor的。接下来主要来看下前两个方法:     AnnotationAwareAspectJAutoProxyCreator重写了findCandidateAdvisors方法,在重写了的方法里面,先调用了父类的,而后调用了基于注解的获取Advisor的方法。

@Override
protected List<Advisor> findCandidateAdvisors() {
   //查找构建全部基于XML配置的切面类的切面方法
   List<Advisor> advisors = super.findCandidateAdvisors();
   //查找构建全部基于注解的切面类的切面方法
   advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
   return advisors;
}
复制代码

    此次咱们来看看基于xml的切面类是如何获取容器中的Advisor的。

public List<Advisor> findAdvisorBeans() {
		String[] advisorNames = null;
		synchronized (this) {
             //这个阶段若是xml配置了切面类 cachedAdvisorBeanNames 应该已经包含了切面方法生成的切面类的 //beanName了
			advisorNames = this.cachedAdvisorBeanNames;
			if (advisorNames == null) {
			    //Aspect 多是基于FactroyBean建立的,这里不实例化Aspect,仍是应该交给代理实现
				advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
						this.beanFactory, Advisor.class, true, false);
				this.cachedAdvisorBeanNames = advisorNames;
			}
		}
		if (advisorNames.length == 0) {
			return new LinkedList<Advisor>();
		}

		List<Advisor> advisors = new LinkedList<Advisor>();
		for (String name : advisorNames) {
			if (isEligibleBean(name)) {
				if (this.beanFactory.isCurrentlyInCreation(name)) {
					if (logger.isDebugEnabled()) {
						logger.debug("Skipping currently created advisor '" + name + "'");
					}
				}
				else {
					try {
                          //直接经过切面方法生成的BeanDefinition 获取bean实例
						advisors.add(this.beanFactory.getBean(name, Advisor.class));
					}
					catch (BeanCreationException ex) {
		      		//异常处理
                        ......       
		}
		return advisors;
	}
复制代码

    从上面的代码看获取xml配置的切面方法生成的Advisor很简单,其实否则,真正复杂的逻辑是读取xml生成BeanDefinitiongetBean()的过程,这里就不展开分析了。 这个方法过程就是找出由XMl配置的切面类生成的全部切面方法的Advisor,而后遍历beanName,生成实例对象,然会返回生成后的Advisor实例对象。

4.1 获取全部Advisor

    接下来再来看看基于注解的Advisor是如何获取的。

public List<Advisor> buildAspectJAdvisors() {
		List<String> aspectNames = null;

		synchronized (this) {
			aspectNames = this.aspectBeanNames;
			if (aspectNames == null) {
				//此时的aspectNames已经不为空了,省略以前生成Advisor的部分
                  .......
				return advisors;
			}
		}
		if (aspectNames.isEmpty()) {
			return Collections.emptyList();
		}
		List<Advisor> advisors = new LinkedList<Advisor>();
		for (String aspectName : aspectNames) {
            //获取全部基于注解生成Advisor
			List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
			if (cachedAdvisors != null) {
				advisors.addAll(cachedAdvisors);
			}
			else {
                 //若是当时生成的Advisor是由工厂生成的,这个时候从工厂获取
				MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
				advisors.addAll(this.advisorFactory.getAdvisors(factory));
			}
		}
		return advisors;
	}
复制代码

    这个方法有两部分,第一部分省略了,内容是上一篇分析过的生成基于注解的Advisor的过程,第二部分是获取已经生成过的Advisor的过程,因为基于注解生成的Advisor已经在建立的同时完成了bean的初始化,因此这里直接从缓存中获取便可,若是Advisor是由工厂类生成,则此时须要经过工厂类获取Advisor

4.2 获取beanClass的Advisor

    上面分析过程已经从xml和注解的方式获取到了容器中的全部Advisor,接下来会执行第二步操做,校验容器中的Advisor是否可以做用与要建立的bean上,回头看核心方法2:findAdvisorsThatCanApply

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
   if (candidateAdvisors.isEmpty()) {
      return candidateAdvisors;
   }
   List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
   for (Advisor candidate : candidateAdvisors) {
       //核心点1:经过Introduction实现的advice
      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;
      }
       //核心点2:匹配可以做用于clazz的Advice
      if (canApply(candidate, clazz, hasIntroductions)) {
         eligibleAdvisors.add(candidate);
      }
   }
   return eligibleAdvisors;
}
复制代码

    这个方法的核心点1作了一次匹配,这个匹配是经过IntroductionAdvisor实现的,首先简单了解下这个问题的背景:

    若是须要对一些组件新增一些功能,好比在付款接口完成后,须要记录这笔交易耗时时间,可是此时根据业务不一样,可能会有不少个付款实现类,这个时候的作法就是新增一个统计耗时的接口,这样作虽然能够解决问题,可是污染了业务代码,并且每一个类中都要实现一遍,这就违反了面向对象的开放封闭原则,这个问题经过装饰者模式解决,Spring为了可以完成这个功能,使用Introduction+advice实现的,Spring经过一个特殊的拦截器IntroductionInterceptor实现。与PointCut做用于接口层次上不一样,这种方式做用于类的层次,可是很不建议在生产环境使用这种粗粒度的实现,只须要知道Spring中有这种实现的方式就能够了,这里也不做为重点分析。

    咱们来看核心点2,canApply(candidate, clazz, hasIntroductions)从方法参数能够看出参数candidate是一个Advisor,claszz是目标类对象,因为Advisor实现类里面有PointCut,因此就能够匹配clazz类的方法是否属于切入方法,须要被加强。

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) {
      //转换成成PointCut接口
      PointcutAdvisor pca = (PointcutAdvisor) advisor;
      return canApply(pca.getPointcut(), targetClass, hasIntroductions);
   }
   else {
      //若是advisor没有一个pointcut,默认它对全部的bean都是生效的
      return true;
   }
}
复制代码

    上面的方法首先校验了advisor是不是IntroductionAdvisor,上面分析过,IntroductionAdvisor是基于类型的,因此这里直接针对这种bean直接调用了ClassFilter接口去匹配,而后若是advisor是一个PointcutAdvisor,则转换成PointcutAdvisor再调用canApply方法,最后若是Advisor并无配置成一个PointcutAdvisor,就默认对全部的bean都是生效的,进入canApply方法继续看

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
   Assert.notNull(pc, "Pointcut must not be null"); 
   if (!pc.getClassFilter().matches(targetClass)) {
      return false;
   }
    //前面说过 PointCut接口getMethodMatcher的返回一个方法匹配器
   MethodMatcher methodMatcher = pc.getMethodMatcher();
   IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
   if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
      introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
   }
    //获取目标类得全部接口接口
   Set<Class<?>> classes = new LinkedHashSet<Class<?>>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
   classes.add(targetClass);
   for (Class<?> clazz : classes) {
       //获取目标类及其接口的全部方法
      Method[] methods = clazz.getMethods();
      for (Method method : methods) {
         if ((introductionAwareMethodMatcher != null &&
               introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
               methodMatcher.matches(method, targetClass)) {
            return true;
         }
      }
   }
   return false;
}
复制代码

    这个方法其实很明确了,就是经过PointCut获取到一个方法匹配器MethodMatcher,这个匹配器经过match方法能够判断当前的方法是否可以被匹配到,PointCut的封装其实就是aspectj的,但咱们关注点并不在这,就不进入里面分析了, 而后获取目标类的全部接口,循环全部的接口而后获取各个接口的全部方法,调用MethodMatchermatch方法用来判断当前方法是否可以被匹配,只要有一个方法被匹配到,则但会true,代表当前的advisor可以做用于当前bean。

    Spring在bean的建立过程当中,就是经过上面的过程查找可以做用于bean的Advisor的,若是可以找到,就为bean建立代理,不然就当普通的bean建立,通过上面的判断,咱们案例中的bean确定是有符合条件的Advisor,因此接下来看看Spring是如何建立代理的。

五、代理模式的查找

再来回忆下这个方法:

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    //若是bean是经过TargetSource接口获取 则直接返回
   if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
      return bean;
   }
    //若是bean是切面类 直接返回
   if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
      return bean;
   }
    //若是bean是Aspect 并且容许跳过建立代理, 加入advise缓存 返回
   if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
      this.advisedBeans.put(cacheKey, Boolean.FALSE);
      return bean;
   }
   //若是前面生成的advisor缓存中存在可以匹配到目标类方法的Advisor 则建立代理
   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;
}
复制代码

    通过前面的分析,经过getAdvicesAndAdvisorsForBean方法能够获取到容器中全部能被做用于当前bean的Advisor,此时的specificInterceptors确定是不为null,因此就会执行createProxy建立代理的方法了。

protected Object createProxy( Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {

   if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
       //若是是基于IntroductionAdvisor,直接指定代理的目标类便可
      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 {
         //将beanClass的接口设置到代理工厂上
         evaluateProxyInterfaces(beanClass, proxyFactory);
      }
   }
   //构建可以做用于beanClass类的Advisor集合
   Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
   for (Advisor advisor : advisors) {
      proxyFactory.addAdvisor(advisor);
   }

   proxyFactory.setTargetSource(targetSource);
   customizeProxyFactory(proxyFactory);
   proxyFactory.setFrozen(this.freezeProxy);
   if (advisorsPreFiltered()) {
      proxyFactory.setPreFiltered(true);
   }
   //建立代理对象
   return proxyFactory.getProxy(getProxyClassLoader());
}
复制代码

    因为IntroductionAdvisor这样特殊的拦截器已经指定了加强的类对象,也就是说该类实现了IntroductionInterceptor拦截器,定义过了类的方法须要如何加强,因此上面的方法第一步就是给他指定了加强类,而后建立ProxyFactory代理工厂,先校验代理工厂是否可以直接代理目标类及其接口,若是不能则evaluateProxyInterfaces方法会将beanClass的接口设置到代理工厂上,接下来经过buildAdvisors方法构建一个可以做用于beanClass类的Advisor集合放入到代理工厂中,以便后续建立代理时使用,最后调用proxyFactory.getProxy方法一个代理对象,在这里buildAdvisors方法没可看的,就是将Advisor封装到一个集合里等待备用:

protected Advisor[] buildAdvisors(String beanName, Object[] specificInterceptors) {
   Advisor[] commonInterceptors = resolveInterceptorNames();
   List<Object> allInterceptors = new ArrayList<Object>();
   if (specificInterceptors != null) {
       //将全部Advisor放入到allInterceptors集合中
      allInterceptors.addAll(Arrays.asList(specificInterceptors));
      if (commonInterceptors.length > 0) {
         if (this.applyCommonInterceptorsFirst) {
            allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
         }
         else {
            allInterceptors.addAll(Arrays.asList(commonInterceptors));
         }
      }
   }
   if (logger.isDebugEnabled()) {
      int nrOfCommonInterceptors = commonInterceptors.length;
      int nrOfSpecificInterceptors = (specificInterceptors != null ? specificInterceptors.length : 0);
   Advisor[] advisors = new Advisor[allInterceptors.size()];
   for (int i = 0; i < allInterceptors.size(); i++) {
       //根据Advice类型转换成不用的Advisor实现
      advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
   }
   return advisors;
}
复制代码

下面看看Spring时如何建立代理的

public Object getProxy(ClassLoader classLoader) {
    //createAopProxy方法建立一个代理对象
   return createAopProxy().getProxy(classLoader);
}
复制代码

    createAopProxy方法建立一个代理对象,这个方法由DefaultAopProxyFactory类实现:

@Override
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);
   }
}
复制代码

    这个方法决定了是使用jdk代理仍是cglib代理,上面的判断由三个校验组成,只要有任何一个结果为true都会进入else使用jdk代理,来看下这个三个判断条件:

//自定义指定配置
config.isOptimize()
//是否使用了proxy-target-class="true"
config.isProxyTargetClass()
//目标类是否实现了接口 并且接口不能与SpringProxy类相同
hasNoUserSuppliedProxyInterfaces(config)) 
复制代码

    这三个方法中的config.isOptimize()config.isProxyTargetClass()默认都会返回false,针对最后一个方法是判断目标类是否没有接口,当目标类有接口实现的时候就会走到最后一个else,使用JdkDynamicAopProxy建立代理,也就是jdk代理。

private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
   Class<?>[] ifcs = config.getProxiedInterfaces();
    //若是目标类是实现了接口 会直接返回false
   return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
}
复制代码

    而后再来看config.isOptimize(),这个属性的初始值是false,我并无在源码中发现有哪里能够修改这个值,可是若是咱们自定义一个实现了AbstractAdvisorAutoProxyCreator类的处理器,像下面这样配置,就能够设置这个值为true了。这个应该是基于Sping的扩展的,但这里对普通注解bean都是false的,因此不须要太纠结。

<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
        <property name="optimize" value="true"/>
    </bean>
复制代码

    而后再看一个比较关键的判断config.isProxyTargetClass(),这个配置实际上就是aop基于自动注解配置里面的一个属性

<aop:aspectj-autoproxy proxy-target-class="true">
复制代码

    这个值就是proxy-target-class的值,这个值的注入是注册AnnotationAwareAspectJAutoProxyCreator时候设置的,来看下面的代码,这部分是注册AnnotationAwareAspectJAutoProxyCreator时候,设置proxyTargetClass属性的

private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) {
   if (sourceElement != null) {
     // PROXY_TARGET_CLASS_ATTRIBUTE就是proxy-target-class属性
      boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
      if (proxyTargetClass) {
          //主要执行这个方法
         AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
      }
      boolean exposeProxy = Boolean.valueOf(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
      if (exposeProxy) {
         AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
      }
   }
}
复制代码
public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
   if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
      BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
       //若是proxy-target-class属性配置的是true 直接设置这个值的类型为true
      definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
   }
}
复制代码

    因此说若是咱们经过<aop:aspectj-autoproxy proxy-target-class="true">方式若是配置了proxy-target-class为true,则就会直接使用cglib代理了,固然下面还会有一些校验,不过最终仍是会走到cglib代理,此次先来看看cglib代理吧

六、Cglib模式的代理

6.1 Enhancer的建立

    cglib代理就是由ObjenesisCglibAopProxy这个类实现的,获取代理对象直接调用其父类CglibAopProxy的getProxy方法获取。

@Override
public Object getProxy(ClassLoader classLoader) {
   try {
      Class<?> rootClass = this.advised.getTargetClass();
      Class<?> proxySuperClass = rootClass;
      if (ClassUtils.isCglibProxyClass(rootClass)) {
         proxySuperClass = rootClass.getSuperclass();
         Class<?>[] additionalInterfaces = rootClass.getInterfaces();
         for (Class<?> additionalInterface : additionalInterfaces) {
            this.advised.addInterface(additionalInterface);
         }
      }
      //校验类
      validateClassIfNecessary(proxySuperClass, classLoader);
      //开始建立cglib代理
      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 ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
      //核心点1:获取回调集合
      Callback[] callbacks = getCallbacks(rootClass);
      Class<?>[] types = new Class<?>[callbacks.length];
      for (int x = 0; x < types.length; x++) {
         types[x] = callbacks[x].getClass();
      }
      //核心点2:设置过滤器
      enhancer.setCallbackFilter(new ProxyCallbackFilter(
            this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
      enhancer.setCallbackTypes(types);

      // 建立代理对象
      return createProxyClassAndInstance(enhancer, callbacks);
   }
   catch (Exception ex) {
      //异常捕获抛出
       .........
   }
  
}
复制代码

    cglib代理的使用方式和咱们以前作的简单案例的使用是同样的:

首先建立一个Enhancer,setSuperclass设置要代理的对象,

setInterfaces能够不设置,由于是基于cglib代理的,不须要接口实现,这里的含义是指定建立的代理继承AopProxy的一些接口。

setNamingPolicy设置cglib的命名策略,这里是以BySpringCGLIB为前缀:

***getCallbacks***方法用于获取加强器,会详细解析。

***enhancer.setCallbackFilter()***用于过滤器用于过滤不须要加强的方法的,也会详细解析

最后经过***createProxyClassAndInstance***建立一个代理实例对象。

    从上面单独对cglib单例的使用讲解能够知道,cglib代理是基于asm在字节码上的实现,能够动态的建立一个继承于目标类的代理对象,而后执行加强操做,此外cglib还提供了Callback接口用于执行对方法的拦截,由MethodInterceptor接口的intercept方法拦截,而后cglib还能够经过CallbackFilter类来指定对不一样的类或者方法执行不一样的加强操做,accept方法会返回一个索引,这个索引是设置的CallbackFilter集合中集合的索引,经过accpet方法若是返回0就会使用Callback集合中第一个加强拦截器,下面会针对Spring设置的Callback集合和CallbackFilter分别分析。

6.2 Callback拦截器集合

    首先来看下Spring是如何获取CallbackFilter集合。

private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
   // Parameters used for optimisation choices...
   boolean exposeProxy = this.advised.isExposeProxy();
   boolean isFrozen = this.advised.isFrozen();
   boolean isStatic = this.advised.getTargetSource().isStatic();
   Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
   Callback targetInterceptor;
   if (exposeProxy) {
      //这个方法是表示处理嵌套的,也就是在代理方法中调用本次的其余方法 那么针对该方法的加强效果将会失效
      ........
   }
   else {
      targetInterceptor = isStatic ?
            new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
            new DynamicUnadvisedInterceptor(this.advised.getTargetSource());
   }
   Callback targetDispatcher = isStatic ?
         new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp();
   //这个事核心点,从这里能够看出Spring里面总共设置了6个方法加强器
   //其中第一个就是咱们咱们配置的加强器
   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 (isStatic && isFrozen) {
      .........
   }
   else {
      callbacks = mainCallbacks;
   }
   return callbacks;
}
复制代码

    首先Spring将建立的的ProxyFactroy对象封装到DynamicAdvisedInterceptor,这个代理类里面有以前匹配到的Advisor集合,而后判断exposeProxy是不是true,这个属性也是在xml配置文件中配置的,背景就是若是在事务A中使用了代理,事务A调用了目标类的的方法a,在方法a中又调用目标类的方法b,方法a,b同时都是要被加强的方法,若是不配置exposeProxy属性,方法b的加强将会失效,若是配置exposeProxy,方法b在方法a的执行中也会被加强了。接下来再看mainCallbacks这个集合,这个集合里面封装了6个是实现了CallbackMethodInterceptor接口的类,其中第一个aopInterceptor就是封装了目标类的要加强的逻辑也就是Advisor集合,第二个是针对以前配置的optimize属性使用的,后面的四个基本上不会作太多业务逻辑上的拦截,Spring最终将这6个加强器集合返回做为cglib的拦截器链,以后经过CallbackFilteraccpet方法返回的索引从这个集合中返回对应的拦截加强器执行加强操做。

6.3 CallbackFilter 过滤器

    Spring实现的是经过ProxyCallbackFilter实现CallbackFilter接口,而后赋值给代理对象,上面分析过,这个接口主要是经过accpet接口实现的,来看看是如何匹配的:

@Override
public int accept(Method method) {
   if (AopUtils.isFinalizeMethod(method)) {
      logger.debug("Found finalize() method - using NO_OVERRIDE");
       //不使用代理
      return NO_OVERRIDE;
   }
   if (!this.advised.isOpaque() && method.getDeclaringClass().isInterface() &&
         method.getDeclaringClass().isAssignableFrom(Advised.class)) {
      if (logger.isDebugEnabled()) {
         logger.debug("Method is declared on Advised interface: " + method);
      }
      return DISPATCH_ADVISED;
   }
   // We must always proxy equals, to direct calls to this.
   if (AopUtils.isEqualsMethod(method)) {
      logger.debug("Found 'equals' method: " + method);
      return INVOKE_EQUALS;
   }
   // We must always calculate hashCode based on the proxy.
   if (AopUtils.isHashCodeMethod(method)) {
      logger.debug("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.isDebugEnabled()) {
            logger.debug("Must expose proxy on advised method: " + method);
         }
         //使用封装了Advisor的拦截加强器
         return AOP_PROXY;
      }
      String key = method.toString();
      // Check to see if we have fixed interceptor to serve this method.
      // Else use the AOP_PROXY.
      if (isStatic && isFrozen && this.fixedInterceptorMap.containsKey(key)) {
         // We know that we are optimising so we can use the FixedStaticChainInterceptors.
         int index = this.fixedInterceptorMap.get(key);
         return (index + this.fixedInterceptorOffset);
      }
      else {
         if (logger.isDebugEnabled()) {
            logger.debug("Unable to apply any optimisations to advised method: " + method);
         }
         //使用封装了Advisor的拦截加强器
         return AOP_PROXY;
      }
   }
   else {
      if (exposeProxy || !isStatic) {
         return INVOKE_TARGET;
      }
      Class<?> returnType = method.getReturnType();
      if (targetClass == returnType) {
         return INVOKE_TARGET;
      }
      else if (returnType.isPrimitive() || !returnType.isAssignableFrom(targetClass)) {
         return DISPATCH_TARGET;
      }
      else {
         return INVOKE_TARGET;
      }
   }
}
复制代码

    这个方法里面,咱们只须要关心AOP_PROXY这个值就能够了,这个值是0,也就是对应上面生成的Callback集合中的第一个拦截加强器,也就是aopInterceptor,这个拦截器里面封装了全部可以做用于目标类的Advisor加强类,因此就会调用到切面类定义的切面方法来进行加强操做了。

6.4 Advisor调用链

    上面分析过,Spring使用的是aopInterceptor做为拦截加强器,这个加强器被封装进了DynamicAdvisedInterceptor类中,这个类实现了MethodInterceptor方法,因此被拦截到的方法会进入intercept方法中,因为这个类里面封装了前面咱们匹配到的全部可以做用于这个类的Advisor集合,可是可能针对这些Advisor可能执行顺序有些疑问,虽然Spring容许经过继承Order接口实现排序,可是好比@Before@After,@Round等是须要在某个方法的不一样时机执行的,因此这须要构造一个调用链,废话很少,仍是先来看aopInterceptor的intercept方法是如何作的:

@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
   try {
      if()
      {
          //省略不重要代码
          ........
      }
      else {
         //建立一个方法执行器 主要逻辑在这里
         retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
      }
      retVal = processReturnType(proxy, target, method, retVal);
      return retVal;
   }
   finally {
      if (target != null) {
         releaseTarget(target);
      }
      if (setProxyContext) {
         // Restore old proxy.
         AopContext.setCurrentProxy(oldProxy);
      }
   }
}
复制代码

    在这个方法里面,咱们只须要关心CglibMethodInvocationproceed方法,调用链就是在这里构建的

@Override
public Object proceed() throws Throwable {
   //首先获取到全部的Advisor 而后去除一个下标-1
   if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
      return invokeJoinpoint();
   }
   //获取当前Advisor
   Object interceptorOrInterceptionAdvice =
         this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    //若是是动态方法匹配器
   if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
      InterceptorAndDynamicMethodMatcher dm =
            (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
      if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
         return dm.interceptor.invoke(this);
      }
      else {
         //匹配失败直接跳过,再次执行proceed方法
         return proceed();
      }
   }
   else {
      //调用拦截器加强集合
      return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
   }
}
复制代码

    这个方法是构造调用链的实现原理,首先获取到Advisor集合,而后用currentInterceptorIndex表示当前集合剩余未执行的AdvisorcurrentInterceptorIndex=0的时候,集合中全部的Advisor已经执行完毕了,这种方法仍是很巧妙的,咱们从总体上看下是如何造成调用链的,该方法最终调用最后一行代码,也就是MethodInterceptor类的invoke方法,把当前对象做为参数传进去,当前对象也就是aopInterceptor,这里面封装了全部符合条件的Advisor(每次都要强调这个类里面的数据就是让咱们始终能保持在主线上),该类实现了ProxyMethodInvocation接口间接实现了MethodInvocation接口,最后一行的代码调用invoke方法,也就是MethodInterceptor接口的方法,来看下这个方法的定义:

public interface MethodInterceptor extends Interceptor {
    Object invoke(MethodInvocation invocation) throws Throwable;
}
复制代码

    invoke的参数是MethodInvocation,因为aopInterceptorMethodInvocation的实现类,因此能够将该类做为参数往下传递,前面分析过了切面的注解方法注解对应的类为:

@Before MethodBeforeAdviceInterceptor
@After AspectJAfterReturningAdvice
@Around AspectJAroundAdvice
@AfterThrowing AspectJAfterThrowingAdvice

    这些生成的Advice切面类毫无疑问都实现了MethodInterceptor方法,而MethodInterceptorinvoke方法须要接收一个类型为MethodInvocation的对象,正好aopInterceptor实现了MethodInvocation,因此能够做为参数在多个Advisor间流转,每执行完一个Advisor就进入aopInterceptorprocess方法再次校验,直至执行完全部的Advisor`。

    假设此时的aopInterceptor里面包含了两个切面方法MethodBeforeAdviceInterceptorAspectJAfterReturningAdvice,此时先取出AspectJAfterReturningAdvice,而后执行invoke方法,看下AspectJAfterReturningAdviceinvoke方法:

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
   try {
      //此时的mi对象就是 aopInterceptor ,又回到了proceed方法
      return mi.proceed();
   }
   finally {
       //自身的方法最后执行
      invokeAdviceMethod(getJoinPointMatch(), null, null);
   }
}
复制代码

    AspectJAfterReturningAdviceinvoke方法会首先调用参数 mi 的proceed方法,此时mi就是aopInterceptor对象(这里面封装了全部适用于目标类对象的切面方法类),因此会再次返回到拦截器集合里,取出MethodBeforeAdviceInterceptor对象,调用它的invoke方法,最后自调用AspectJAfterReturningAdvice封装的切面方法也就是经过@After注解修饰的方法。再来看看AspectJAfterReturningAdvice的invoke方法

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
   this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
   return mi.proceed();
}
复制代码

    这里会先调用经过@Before注解修饰的方法,而后再次调用aopInterceptor拦截器链,虽然这两个注解是最简单的,可是确时逻辑最清晰的,也是最容易理解的,其余的切面注解方法的调用过程也是这样,最终完成这个拦截器链的调用。

    通过上面的步骤,就能够建立一个代理对象了, 而后Spring将代理对象放入缓存中,咱们使用时获得的是一个代理对象,调用目标方法,就会执行到加强器方法,进而找到全部的Advisor,构造一个调用链,这样就完成业务的加强了。我相信若是对照着源码看,多调试几遍代码,应该会大体了解Spring实现Cglib的代理的一个流程。关于Spring时如何实现cglib代理的暂时就分析到这里。

七、JDK模式的代理

    jdk模式的代理是经过JdkDynamicAopProxy这个类实现的,因为jdk的代理的实现比cglib代理稍微简单一点,我这里暂时就先不分析了,关于jdk代理模式的解析估计有不少资料,之后有时间我补上这部份内容

八、总结

    Spring源码很复杂,若是想把每一个细节都搞明白,几乎是不可能的,并且无疑会浪费不少时间,咱们只须要搞懂经常使用的功能的实现方式,遇到问题能够从源码的角度解决问题就好了,说的更高一点,若是咱们能学到做者的一些架构思路以及对代码的功能抽象,之后能够对Spring进行扩展,那就再好不过了,废话很少了,总结下一些这部份内容究竟在说些什么吧。

    这一部份内容是Spring AOP的第二部份内容,是基于上一步解析@Aspect注解,将注入@Before等注解方法生成Advice切面方法类的过程,这一部分则是使用这些切面方法类,而后找出可以做用于目标类的Advisor,而后建立代理对象,具体流程是:

一、从Advisor缓存中获取第一步生成的全部Advisor(包括经过xml配置和注解配置的)

二、遍历Advisor集合,从Advisor里面获取PointCut,获取方法匹配器MethodMatcher,经过match方法匹配一个当前Advisor是否可以做用于目标类,若是能,则放入集合中

三、若是第二部获取的集合为空,则直接返回,不须要建立代理,若是不为空,也就是Advisor缓存中有可以做用于目标类的Advisor,则根据配置选择不一样的代理的方法(cglib 仍是 jdk 代理)

四、假如是cglib代理,须要构建Callback拦截加强器集合,而后建立一个CallbackFilter过滤器,选择合适的拦截加强器对bean实现加强处理

五、返回建立的代理对象。

    写完这一篇,我终于把这两个月看Spring的源码对其的理解记录下来了, 即使如此,我感受我对Spring仍是知之甚少,还须要巩固,我认为若是能经过Spring封装本身写的框架,就像Sping-redis,Spring-kafka 那样直接经过注解或者配置就能够拿来使用了,确定对Spring有一个更高层次的认识,为了加深对Spring的理解,经过刘欣老师的讲解,我也跟着写了一遍稍微简单的Spring实现,那段代码花了我将近一个月的时间,可是写完再看Spring的源码就会容易理解的多,源码地址是:

github.com/StringBuild…

感兴趣的能够拉下来看看。

相关文章
相关标签/搜索