天天看点

Spring AOP原理学习-看书记录笔记1. 整体2. 重点

1. 整体

2. 重点

2.1 重要概念

  • 切点
  • 通知
  • 代理
  • 拦截
  • 增强

2.2 动态代理原理

记住一点,AOP的核心技术就是动态代理

AOP用的是代理,管理代理。java有自带的代理机制,还有Cglb代理机制。这两种机制Aop都在应用,Java代理主要运用于接口,而Cglb主要是类。

很重要的一段话

Spring AOP原理学习-看书记录笔记1. 整体2. 重点

了解一下ProxyCreatorSupport

Spring AOP原理学习-看书记录笔记1. 整体2. 重点

AOP的具体实现就是在这个类中。

都是从DefaultAopProxyFactory中的createAopProxy()开始下面操作的。

  • 生成代理对象
  • 执行拦截器。

JdkDynamicAopProxy拦截器

从JdkDynamicAopProxy的invoke()方法,到ReflectiveMethodInvocation的process()

CglibAopProxy拦截器

intercept()方法,拦截器不是凭空来的,需要进行拦截器注册才能保存到拦截器链中,在拦截器注册之间有一个:从拦截器注册器中进行适配,确定哪些拦截器是该代理目标的拦截器的。

ReflectiveMethodInvocation反射

这里通过反射调用目标方法。 process()方法中实现,这里也是执行matches()的地方。

2.3 invoke()方法逻辑分析

代理中最主要的方法就是invoke()方法了,那就介绍一下该方法的逻辑。

  • 获取目标源TargetSource
  • 赋值代理目标对象Target
  • 获取代理对象类
  • 获取代理对象参数,用数组来存放
  • 通过反射调用目标方法
  • 获取目标方法执行后返回信息

2.4 关于切点

知道切点都是到,就是增强的目标方法,一般是方法。但是Aop怎么知道对那些方法进行操作,这就要在配置的时候告诉Aop需要操作哪些方法。

先看一下Pointcut的整体架构:

Spring AOP原理学习-看书记录笔记1. 整体2. 重点

这里每一个实现类都要实现一个方法matchs(),至于不同的切点匹配规则不一样。通常用到的

  • 方法名
  • 注解
  • 正则表达式

2.4 Advisor通知器

将增强设计,也就是Advice和切点(Pointcut)结合起来。 也就是哪个切点上使用哪个通知。

2.4.1 DefaultPointcutAdvisor默认切点通知器

也就是当通知器为空的时候,就是用默认的。 默认就是对任何方法的匹配都成功。

TrueMethodMatcher这个方法的匹配对任何方法的匹配都会成功

总结

  1. 关于Spring AOP的介绍

    AOP是基于代理对象的,,通过ProxyCreateSuport来设置创建代理对象的通用操作,在这个类中主要就是获取代理目标对象的SourceTarget,获取代理对象的信息。

  2. 再通过DefaultAopProxyFactory确定AopProxy代理对象的生成策略,生成策略的配置主要实在createAopProxy()方法中,其实也就是确定是有Java Proxy还是CGLIB第三来生成AopProxy代理对象。

    在确定了生成策略之后,真正的Proxy实在ObjenesisCglibAopProxy和JdkDynamicAopProxy类中生成的。

  3. 代理对象生成之后,在ObjenesisCglibAopProxy-(intercept)和JdkDynamicAopProxy-(invoke)都有自己的回调函数,回调函数的作用就是对代理的方法进行各种增强操作。
  4. 回调函数的作用是,获取目标对象(包括目标方法,方法参数),拦截器链,创建ReflectiveMethodInvocation的process()方法来完成Aop的各种增强处理。这里的拦截器链其实就是通过遍历连接器链,用一个一个的拦截器来执行拦截增强。
  5. 这里有一个问题,当拦截器为空的时候,直接使用反射来调用目标方法,不需要创建ReflectiveMethodInvocation。这也是我之前运用AOP的一个例子,没有用到拦截器,获取了代理的目标对象方法之后,通过目标对象方法调用invoke(target, args)来执行方法。

    这里记住一点这些操作是在ObjenesisCglibAopProxy-(intercept)和JdkDynamicAopProxy-(invoke)完成的,执行的方法是括号的方法。

  6. 拦截器分类两种JdkDynamicAopProxy拦截器和CglibAopProxy拦截器,其实不难理解,既然是对AopProxy代理对象的拦截,针对AopProxy两种生成策略,肯定也有两种拦截器。上面已经讲过了,当拦截器链不为空的时候,这两种连接器都是通过ReflectiveMethodInvocation的process()方法进行代理目标函数的增强的。
  7. 所以接下来的重心就是ReflectiveMethodInvocation的process()方法,该方法中中实现了具体的增强逻辑。贴一个代码吧。代码的核心是从interceptorsAndDynamicMethodMatchers集合中获取拦截器或者拦截通知,然后执行增强操作。这里的interceptorsAndDynamicMethodMatchers连接器接口是从前面提到的方法中传过来的,那就返回获取看看。
public Object proceed() throws Throwable {
		// We start with an index of -1 and increment early.
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			return invokeJoinpoint();
		}

		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.
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}
           
  1. 关于通知或者拦截器来源我们在JdkDynamicAopProxy的invoke方法中看到了下面这段代码,跟进去发现是在AdvisedSupport获取的。代码如第二段代码,该类中用了一个Map来缓存所有代理方法的拦截器,

    Map定义:

    private transient Map<MethodCacheKey, List<Object>> methodCache;

    从代码中可以看到,真正获取拦截器的方法是:

    this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice( this, method, targetClass);

    方法。跟进去看看。

    这里有一个问题,通过advisorChainFactory工程来获取拦截器,advisorChainFactory是该类的一个属性,看代码发现,该属性的具体实例被配置成DefaultAdvisorChainFactory类

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
		MethodCacheKey cacheKey = new MethodCacheKey(method);
		List<Object> cached = this.methodCache.get(cacheKey);
		if (cached == null) {
			// 真正获取拦截器
			cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
					this, method, targetClass);
			this.methodCache.put(cacheKey, cached);
		}
		return cached;
	}
           
  1. 进入了

    this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice( this, method, targetClass);

    方法。发现该方法的具体实现是在DefaultAdvisorChainFactory中。这里算是找到了获取拦截器链的源头了。
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
			Advised config, Method method, @Nullable Class<?> targetClass) {

		// This is somewhat tricky... We have to process introductions first,
		// but we need to preserve order in the ultimate list.
		AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
		Advisor[] advisors = config.getAdvisors();
		List<Object> interceptorList = new ArrayList<>(advisors.length);
		Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
		Boolean hasIntroductions = null;

		for (Advisor advisor : advisors) {
			if (advisor instanceof PointcutAdvisor) {
				// Add it conditionally.
				PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
				if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
					MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
					boolean match;
					if (mm instanceof IntroductionAwareMethodMatcher) {
						if (hasIntroductions == null) {
							hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
						}
						match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
					}
					else {
						match = mm.matches(method, actualClass);
					}
					if (match) {
						MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
						if (mm.isRuntime()) {
							// Creating a new object instance in the getInterceptors() method
							// isn't a problem as we normally cache created chains.
							for (MethodInterceptor interceptor : interceptors) {
								interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
							}
						}
						else {
							interceptorList.addAll(Arrays.asList(interceptors));
						}
					}
				}
			}
			else if (advisor instanceof IntroductionAdvisor) {
				IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
				if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
					Interceptor[] interceptors = registry.getInterceptors(advisor);
					interceptorList.addAll(Arrays.asList(interceptors));
				}
			}
			else {
				Interceptor[] interceptors = registry.getInterceptors(advisor);
				interceptorList.addAll(Arrays.asList(interceptors));
			}
		}

		return interceptorList;
	}
           
  1. 接下来就来看看这个方法的逻辑,该方法就是用一个单例类来注册通知-拦截器。首先通过获取所有的advisors,然后遍历获得所有advisiors,在匹配代理目标方法切点是否有该拦截器,如果有,就将该拦截器注册,保存到一个List拦截器集合中。 这里基本是理解了,但是有个问题,advisior是怎么读入系统的呢? 这将是整个Aop的最后一个环节了。
  2. advisior真正注册的地方就是在ProxyFacrotyBean中的initializeAdvisorChain()。之前在代码中有这一行代码。

    Advisor[] advisors = config.getAdvisors();

    ,那个时候我就在这里的Advisor[] 从哪里来的,经过一番查看,就是从ProxyFacrotyBean中的initializeAdvisorChain()配置的。 这样这个Aop的逻辑就很清晰了。

AopProxy代理类的获取,Advisior的注册,执行增强操作。 这一套都能联系起来。其实Aop的逻辑组件确实就这三个,理解深刻了就会化繁就简。