Spring-Aop源码解析(上)

Aop:在原有功能不变的基础上, 进行功能增强,比如在方法发生异常/方法发生之前/之后进行额外逻辑的插入。这样隐式横向插入逻辑的动作被我们称为Aop。

在Spring中,我们都是将对象交给singletonObjects单例池管理,在使用这个对象之前,就已经生成了对应的Bean。Spring在AspectJ的基础上,进行了封装(就是直接把AspectJ的代码抄了一下),形成了Spring-Aop,让我们可以在原有功能的基础上,进行额外的逻辑增强(代理模式),就是我放到Spring中的Bean,其实不是我认为的Bean,而是生成了一个代理对象来代理这个Bean伪代码如下

java 复制代码
try{
    proxy extends target//代理对象继承自被代理对象

    methodBeforeAround(proxy)//方法执行环绕前
    methodBefore(proxy)//方法执行前
    method.invoke(proxy)//被代理对象执行
    methodAfterAround(proxy)//方法执行环绕后
}
catch(Throwable e){
    exceptionMethod(proxy);//出异常的时候执行
    throw e;
}
finally{
    methodAfter(proxy);//方法执行完之后
}

我们可以对方法执行前后的各个点进行一个额外逻辑的插入,对原有方法进行功能增强。然后在Bean的生命周期中对target(被代理对象)额外生成一个代理对象,将其放到单例池中,然后在使用的时候将该代理对象依赖注入到对应的属性中用于替代target对象。

java中的Demo实现代码如下

java 复制代码
public static void main(String[] args) {

    UserService userService = new UserService();
    ProxyFactory proxyFactory = new ProxyFactory();
    proxyFactory.addAdvice(new MyBeforeAdvice());

    //对UserService的test方法进行前置增强
    UserService proxy = (UserService) proxyFactory.getProxy();
    proxy.test();

}

public class MyBeforeAdvice implements MethodBeforeAdvice {

   @Override
   public void before(Method method, Object[] args, Object target) throws Throwable {
      System.out.println("方法执行前执行");
   }
}


//print:  方法执行前执行
//print:  方法test执行

上述Demo我们对UserService进行了一个前置的代理增强, 可以看到前置处理就是实现了一个MethodBeforeAdvice,那么其他额外功能的插入点,也有对应的Advice接口

AfterReturningAdvice:方法return后执行

MethodInterceptor:围绕方法前后都可以自行实现,需要手动调用proceed方法

ThrowsAdvice:出异常之后执行,这个需要自己手写afterThrowing方法

MethodBeforeAdvice:方法执行前执行

上述就是Spring-Aop提供给我们的Advice,用于额外功能点的增强。这些Advice最后都会被转成MethodInterceptor 。其实还有一种afterAdvice,就是不管有没有异常,都会在最后执行,finally机制,但是spring-Aop提供给我们的接口(AfterAdvice)中并没有对应的实现类,但是Aspectj中有对应的实现类AspectJAfterAdvice

在Spring中我们通常使用Jdk代理和Cglib代理来生成代理对象,我们先来看一下Cglib动态代理方法执行时的核心源码

获取代理对象CglibAopProxy.getProxy()->只提取核心代码

java 复制代码
	public Object getProxy(@Nullable ClassLoader classLoader) {
		//获取被代理的类
		Class<?> rootClass = this.advised.getTargetClass();
		//创建用于生成代理对象的工具
		Enhancer enhancer = createEnhancer();
		// 将代理类的父类设置成被代理类
		enhancer.setSuperclass(proxySuperClass);
		// 代理类额外要实现的接口
		enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
        //这是最核心的源码,获取Spring中匹配的Advisor,后续章节会讲到
        //也是这一步将Advisor转换成了MethodInterceptor
		Callback[] callbacks = getCallbacks(rootClass);
		//返回代理对象
		return createProxyClassAndInstance(enhancer, callbacks);
	}

**执行逻辑(额外逻辑的执行)**CglibAopProxy.proceed()->ReflectiveMethodInvocation.proceed()

java 复制代码
	public Object proceed() throws Throwable {
		//interceptorsAndDynamicMethodMatchers:
		// currentInterceptorIndex初始值为-1,每调用一个interceptor就会加1,然后接着会递归走到这里,就是一个简单的执行链
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			//最后一个interceptor执行完后就会执行被代理方法
			return invokeJoinpoint();
		}
		// 每次递归之后currentInterceptorIndex就++
		Object interceptorOrInterceptionAdvice =
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
		// 当前interceptor是InterceptorAndDynamicMethodMatcher,则先进行匹配,匹配成功后再调用该interceptor
		// 如果没有匹配则递归调用proceed()方法,调用下一个interceptor
		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			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 {
				// 不匹配则执行下一个MethodInterceptor
				return proceed();
			}
		}
		else {
			// 直接调用MethodInterceptor,传入this,在内部会再次调用proceed()方法进行递归
			// 比如MethodBeforeAdviceInterceptor
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}

在执行对应的方法的时候,会对传入进来的Interceptor链进行一个操作(递归执行)(这条链其实就是找到的Advisor转换成的MethodInterceptor,在getCallBacks中会转 ),初始值currentInterceptorIndex为-1,然后每次执行的时候就++,观察是否到达了对应的链Size,如果是,那么代表对应的代理逻辑已经被执行完,该执行被代理方法了,后面有一个判断是否是动态的MethodMatcher(关于Matcher,Spring-Aop源码解析(中)会解析),下面代码也是对其进行的一个简要分析。如果满足了对应的matcher匹配,那么就会执行对应的链路中的额外逻辑(这里面会自动调用proceed方法),如果不满足,那么直接递归,观察下一个MethodInterceptor是否满足(不断的递归)

java 复制代码
		proxyFactory.addAdvisor(new PointcutAdvisor() {
			@Override
			public Pointcut getPointcut() {
				return new Pointcut() {
					@Override
					public ClassFilter getClassFilter() {
                        //先匹配类
						return null;
					}

					@Override
					public MethodMatcher getMethodMatcher() {
                        //再匹配方法
						new MethodMatcher() {
							@Override
							public boolean matches(Method method, Class<?> targetClass) {
								return false;
							}

							@Override
							public boolean isRuntime() {
                            //如果runTime设置成true,那么下面的matches会生效
                            //进行额外方法中的参数是否匹配
                            //也就是转换成了上面我们讲的InterceptorAndDynamicMethodMatcher
								return false;
							}

							@Override
							public boolean matches(Method method, Class<?> targetClass, Object... args) {
								return false;
							}
						}
					}
				};
			}
		});

在匹配对应的Advisor是否匹配当前正在执行的方法的时候,会先根据Class做匹配,观察类是否相等,然后对方法进行一个匹配,观察方法是否相等,第三道过滤必须将MethodMatcher中的Runtime属性设置成true,才会转换成InterceptorAndDynamicMethodMatcher,就是会进一步对方法中的参数进行一个额外的判断,观察参数是否也是匹配的

相关推荐
zpjing~.~23 分钟前
Mongo 分页判断是否有下一页
数据库
2401_8576009524 分钟前
技术与教育的融合:构建现代成绩管理系统
数据库·oracle
秋恬意1 小时前
Mybatis能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别
java·数据库·mybatis
潇湘秦1 小时前
一文了解Oracle数据库如何连接(1)
数据库·oracle
雅冰石1 小时前
oracle怎样使用logmnr恢复误删除的数据
数据库·oracle
web前端神器1 小时前
mongodb给不同的库设置不同的密码进行连接
数据库·mongodb
从以前1 小时前
Berlandesk 注册系统算法实现与解析
数据库·oracle
Muko_0x7d21 小时前
Mongodb
数据库·mongodb
Ren_xixi1 小时前
redis和mysql的区别
数据库·redis·mysql
m0_748233882 小时前
SQL语句整理五-StarRocks
数据库·sql