Spring-Aop源码解析(上)上文讲解了到底什么是Aop,以及围绕方法该如何去找对应的增强点,包括整个Advisor链路的执行顺序,本文来对上文中存在的一些关键点进行一个深入挖掘
Advice:要增强的逻辑,就是我们执行额外逻辑的那坨代码,比如要在test方法之前横向插入一段逻辑,那么我们就需要实现BeforeAdvice接口,来重写里面的before方法。
JointPoint:具体要增强的哪个点,比如我要对UserService下的test方法进行增强,那么test方法就是JointPoint
PointCut:切入点,我要对哪一些点进行增强, 这些点就被我们称为PointCut,就是一类JoinPoint
Advisor:PointCut+Advice,我要对哪一类进行一个额外的逻辑增强,Advisor可以理解为一种行为
下面的代码可以一目了然:
设置一个Advisor,并且在Advisor中可以设置PointCut和Advice,PointCut中又分为ClassFilter过滤和MethodMatcher过滤,MethodMatcher中的runtime属性设置成true的时候会对方法中的参数进行一个额外的逻辑校验。Advice就是我们自己要实现的增强逻辑,所以这段代码翻译成中文就是,我要对UserService下的test方法,并且test方法中只有一个参数的这个方法进行前置逻辑的增强。那么在Spring中是如何实现这段逻辑的
proxyFactory.addAdvisor(new PointcutAdvisor() {@Overridepublic Pointcut getPointcut() {return new Pointcut() {@Overridepublic ClassFilter getClassFilter() {return new ClassFilter() {@Overridepublic boolean matches(Class<?> clazz) {//只对UserSer的类进行增强return UserService.class.equals(clazz);}};}@Overridepublic MethodMatcher getMethodMatcher() {return new MethodMatcher() {@Overridepublic boolean matches(Method method, Class<?> targetClass) {//只对UserService下的test方法进行增强if(method.equals("test")){return true;}return false;}@Overridepublic boolean isRuntime() {//如果这边设置成true,那么下面那个matches才会生效return true;}@Overridepublic boolean matches(Method method, Class<?> targetClass, Object... args) {//根据方法中的参数进行额外逻辑的判断if(args.length == 1){return true;}return false;}};}};}@Overridepublic Advice getAdvice() {//实现了BeforeAdvice的一个类return new MyBeforeAdvice();}@Overridepublic boolean isPerInstance() {return false;}});
在Spring-Aop源码解析(上)篇中,我们遗留了一个方法getCallbacks的方法,这里面就是Spring处理这些Advisor的实现逻辑,getCallBacks中核心逻辑如下
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {//获取被代理对象的所有方法Method[] methods = rootClass.getMethods();Callback[] fixedCallbacks = new Callback[methods.length];for (int x = 0; x < methods.length; x++) {Method method = methods[x];//将方法和被代理类传入,进行Advisor的过滤,到底哪些Advisor是被我需要的List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass);//针对于我要增强的方法和类得到的代理链(Advice链),生成一个Interceptor,然后缓存fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());this.fixedInterceptorMap.put(method, x);}}
继续追踪源码:AdvisedSupport.getInterceptorsAndDynamicInterceptionAdvice->DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice,这块代码的逻辑就完美呈现了PointCut到底是如何去匹配的,如果匹配,就将该Advisor转换成成MethodInterceptor(这里面会借用适配器去强行转换),所以最后我们返回的就是针对于匹配到的被代理对象的一串List<MethodInterceptor>,上文中的疑惑(DynamicMethodMatcher到底是啥玩意,包括Advisor是如何整合成MethodInterceptor的)也在本文中得到了解析
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass) {// 从ProxyFactory中拿到所设置的Advice(添加时被封装成了DefaultPointcutAdvisor)// 添加的时候会控制顺序//这个Advisor是怎么塞进去的会在后续章节详细讲解,主要是在Bean的生命周期初始化后那边塞得Advisor[] advisors = config.getAdvisors();List<Object> interceptorList = new ArrayList<>(advisors.length);Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());for (Advisor advisor : advisors) {if (advisor instanceof PointcutAdvisor) {PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;// 先匹配类if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {// 再匹配方法MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();boolean match = mm.matches(method, actualClass);if (match) {// 如果匹配则将Advisor封装成为Interceptor,当前Advisor中的Advice可能即是MethodBeforeAdvice,也是ThrowsAdviceMethodInterceptor[] interceptors = registry.getInterceptors(advisor);if (mm.isRuntime()) {//如果是runTIme属性被设置成true,那么会将它封装成Dynamic类型,就是针对方法额外做了一个参数的匹配for (MethodInterceptor interceptor : interceptors) {interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));}}else {interceptorList.addAll(Arrays.asList(interceptors));}}// 最终,interceptorList中存储的是当前正在执行的Method所匹配的MethodInterceptor,可能动态的,也可能是非动态的,// 找到Method所匹配的MethodInterceptor后,就会开始调用这些MethodInterceptor,如果是动态的,会额外进行方法参数的匹配}}}}//Advisor是如何转换成MethodInterceptor的@Overridepublic MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {List<MethodInterceptor> interceptors = new ArrayList<>(3);Advice advice = advisor.getAdvice();//如果默认是MethodInterceptor,那么就直接转if (advice instanceof MethodInterceptor) {interceptors.add((MethodInterceptor) advice);}//借助于适配器,将其转换成MethodInterceptor// 将Advice适配成MethodInterceptorfor (AdvisorAdapter adapter : this.adapters) {if (adapter.supportsAdvice(advice)) {interceptors.add(adapter.getInterceptor(advisor));}}if (interceptors.isEmpty()) {throw new UnknownAdviceTypeException(advisor.getAdvice());}return interceptors.toArray(new MethodInterceptor[0]);}
总结:
Advisor中可以自行的设置PointCut和Advice,在方法执行的时候(method.invoke())PointCut则会对被代理对象的类和方法进行匹配,如果匹配成功,那么就会将该Advisor打包成一个MethodInterceptor链(因为可能有很多增强逻辑,针对于同一个类或者方法),然后返回。匹配逻辑则是先匹配类,在匹配方法,如果runTime属性设置成true,那么会再去匹配方法中的参数是否匹配,然后针对于参数这种情况会返回一个DynamicMethodMatcher(上文中有讲解到这是在哪用的)
将Advisor转换成MethodInterceptor的适配器如下,Spring-Aop并没有提供给我们AfterAdvice的适配器,但是Aspectj里面有就是@After注解(AspectJAfterAdvice),你要的话可以自己使用,他是实现了MethodInterceptor接口的,所以在之前就可以直接强转了,不用这些适配器
public DefaultAdvisorAdapterRegistry() {registerAdvisorAdapter(new MethodBeforeAdviceAdapter());registerAdvisorAdapter(new AfterReturningAdviceAdapter());registerAdvisorAdapter(new ThrowsAdviceAdapter());}