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中是如何实现这段逻辑的
java
proxyFactory.addAdvisor(new PointcutAdvisor() {
@Override
public Pointcut getPointcut() {
return new Pointcut() {
@Override
public ClassFilter getClassFilter() {
return new ClassFilter() {
@Override
public boolean matches(Class<?> clazz) {
//只对UserSer的类进行增强
return UserService.class.equals(clazz);
}
};
}
@Override
public MethodMatcher getMethodMatcher() {
return new MethodMatcher() {
@Override
public boolean matches(Method method, Class<?> targetClass) {
//只对UserService下的test方法进行增强
if(method.equals("test")){
return true;
}
return false;
}
@Override
public boolean isRuntime() {
//如果这边设置成true,那么下面那个matches才会生效
return true;
}
@Override
public boolean matches(Method method, Class<?> targetClass, Object... args) {
//根据方法中的参数进行额外逻辑的判断
if(args.length == 1){
return true;
}
return false;
}
};
}
};
}
@Override
public Advice getAdvice() {
//实现了BeforeAdvice的一个类
return new MyBeforeAdvice();
}
@Override
public boolean isPerInstance() {
return false;
}
});
在Spring-Aop源码解析(上)篇中,我们遗留了一个方法getCallbacks的方法,这里面就是Spring处理这些Advisor的实现逻辑,getCallBacks中核心逻辑如下
java
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的)也在本文中得到了解析
java
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,也是ThrowsAdvice
MethodInterceptor[] 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的
@Override
public 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适配成MethodInterceptor
for (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接口的,所以在之前就可以直接强转了,不用这些适配器
java
public DefaultAdvisorAdapterRegistry() {
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}