AOP增强实现-Spring 源码系列(5)

目录:

Ioc容器beanDefinition-Spring 源码(1)

Ioc容器依赖注入-Spring 源码(2)

Ioc容器BeanPostProcessor-Spring 源码(3)

事件机制-Spring 源码(4)

AOP执行增强-Spring 源码系列(5)

AOP的核心就是个动态代理,Spring进行了大量抽象和封装形成一个方便上层使用的基础模块。

而动态代理的两种实现都在上一篇中提供了代码

直接ProxyFactoryBean入手来看Spring是如何产生这个代理对象的:

ProxyFactoryBean中getObject 作为入口:

    //获得代理
//需要对target的增强都在这个入口里处理完成
public Object getObject() throws BeansException {
// 初始化通知链
initializeAdvisorChain();
// 默认单例
if (isSingleton()) {
return getSingletonInstance();
}
else {
if (this.targetName == null) {
logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
"Enable prototype proxies by setting the 'targetName' property.");
}
return newPrototypeInstance();
}
}

singletonInstance缓存单例:

private synchronized Object getSingletonInstance() {
//
if (this.singletonInstance == null) {
this.targetSource = freshTargetSource();
if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
// Rely on AOP infrastructure to tell us what interfaces to proxy.
Class<?> targetClass = getTargetClass();
if (targetClass == null) {
throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
}
// 存住target继承的全部接口 ClassUtils api getAllInterfacesForClass
setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
}
// Initialize the shared singleton instance.
super.setFrozen(this.freezeProxy);
// 这里createAopProxy产生一个AopProxy,在spring中的两个AopProxy实现你已经猜到了吧
this.singletonInstance = getProxy(createAopProxy());
}
return this.singletonInstance;
}
// AopProxyFactory里去做了一个区分是用jdk的还是cglib
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
// 默认DefaultAopProxyFactory
return getAopProxyFactory().createAopProxy(this);
}

DefaultAopProxyFactory实现,这个方法参数需要AdvisedSupport,在上面的调用代码上传的是this,因为它也继承了AdvisedSupport:

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.");
}
// 有接口就用jdk方式
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}

再回去看getProxy方法:

public Object getProxy() {
// 调用JdkDynamicAopProxy 或 ObjenesisCglibAopProxy的getProxy方法
return createAopProxy().getProxy();
}

这里就只看一下JdkDynamicAopProxy实现,两者最终目的相同:

public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
// 筛选Equals方法和HashCode方法
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// 这个代码就熟悉了 调用newProxyInstance方法,最后传入的InvocationHandler是this,那么JdkDynamicAopProxy继承InvocationHandler,实现了invoke方法,增强都在这个方法里做文章
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

invoke方法:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false; TargetSource targetSource = this.advised.targetSource;
Class<?> targetClass = null;
Object target = null; try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
} Object retVal; if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
} // May be null. Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
} // Get the interception chain for this method.
// 拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); // Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
// 使用AopUtils直接使用反射机制调用目标方法
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
// 执行拦截器链
retVal = invocation.proceed();
} // Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}

以上已经调用到增强部分的拦截器链,这些拦截器被调用由ReflectiveMethodInvocation来完成:

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);
// 分两种拦截器:InterceptorAndDynamicMethodMatcher 和 MethodInterceptor
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
// 匹配一遍拦截器
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
// 执行拦截器的invoke方法
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);
}
}

其中调用目标方法的方式采用反射方式具体调用代码值得阅读,实际场景中可以借鉴:

protected Object invokeJoinpoint() throws Throwable {
return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}
public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)
throws Throwable { // Use reflection to invoke the method.
try {
ReflectionUtils.makeAccessible(method);
return method.invoke(target, args);
}
catch (InvocationTargetException ex) {
// Invoked method threw a checked exception.
// We must rethrow it. The client won't see the interceptor.
throw ex.getTargetException();
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
method + "] on target [" + target + "]", ex);
}
catch (IllegalAccessException ex) {
throw new AopInvocationException("Could not access method [" + method + "]", ex);
}
}

到这里,基本流通了一个代理类如何产生,实际增强执行,和目标方法最终被调用的流程,增强如何轻松配置的呢?

Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);

拦截器是叫interceptorsAndDynamicMethodMatchers的list在前面invoke方法中取得:

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

调用基类AdvisedSupport方法:

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
// 这里对缓存的key做了封装
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;
}

advisorChainFactory 通知器链工厂

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, Class<?> targetClass) { // This is somewhat tricky... We have to process introductions first,
// but we need to preserve order in the ultimate list.
List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
// config.getAdvisors来自ioc容器的组装,也就是通过xml配置,注解等元数据来描述的通知器
for (Advisor advisor : config.getAdvisors()) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
// 通知器转变成拦截器,拦截器才是执行链路上可以直接用于增强的
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
// 匹配规则在Pointcut里
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
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;
}

将advisor转化成拦截器在DefaultAdvisorAdapterRegistry中完成:

public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
Advice advice = advisor.getAdvice();
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
// 遍历全部适配器,调用supportsAdvice方法
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[interceptors.size()]);
}

这里使用了适配器模式,也是spring中经常拿来做例子的代码,因为非常清晰。

我们可以查看DefaultAdvisorAdapterRegistry的代码发现默认只有三个适配器:
MethodBeforeAdviceAdapter
AfterReturningAdviceAdapter
ThrowsAdviceAdapter

对应这三个Advice

MethodBeforeAdvice
AfterReturningAdvice
ThrowsAdvice

转变的三个拦截器:

MethodBeforeAdviceInterceptor
AfterReturningAdviceInterceptor
ThrowsAdviceInterceptor

而在前面的流程中调用到拦截器的入口在ReflectiveMethodInvocation的interceptor.invoke(this)方法,这三个拦截器的invoke方法如下:

public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
return mi.proceed();
}
public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
catch (Throwable ex) {
Method handlerMethod = getExceptionHandler(ex);
if (handlerMethod != null) {
invokeHandlerMethod(mi, ex, handlerMethod);
}
throw ex;
}
}

注意mi.proceed();的执行位置,这里继续递归了ReflectiveMethodInvocation的interceptor.invoke(this)方法

那么这个代码最终就可以实现一个执行链:

这样就明白了如何在目标方法执行后再执行配置的增强业务代码,我个人觉得这个递归的实现是整个串联执行链路的核心了,不得不说递归的写法非常简洁而高效。

另外我们一定使用过spring环绕增强,根据上面的分析,那它也只要继承MethodBeforeAdvice,AfterReturningAdvice两者即可实现。
 
 
 
 
 
 
 
 
 
 
 

AOP执行增强-Spring 源码系列(5)的更多相关文章

  1. 事件机制-Spring 源码系列(4)

    事件机制-Spring 源码系列(4) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器BeanPostProcess ...

  2. Ioc容器依赖注入-Spring 源码系列(2)

    Ioc容器依赖注入-Spring 源码系列(2) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器BeanPostPr ...

  3. Ioc容器BeanPostProcessor-Spring 源码系列(3)

    Ioc容器BeanPostProcessor-Spring 源码系列(3) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Io ...

  4. Ioc容器beanDefinition-Spring 源码系列(1)

    Ioc容器beanDefinition-Spring 源码系列(1) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器 ...

  5. Spring源码系列 — Bean生命周期

    前言 上篇文章中介绍了Spring容器的扩展点,这个是在Bean的创建过程之前执行的逻辑.承接扩展点之后,就是Spring容器的另一个核心:Bean的生命周期过程.这个生命周期过程大致经历了一下的几个 ...

  6. Spring源码系列 — BeanDefinition扩展点

    前言 前文介绍了Spring Bean的生命周期,也算是XML IOC系列的完结.但是Spring的博大精深,还有很多盲点需要摸索.整合前面的系列文章,从Resource到BeanDefinition ...

  7. Spring源码系列 — BeanDefinition

    一.前言 回顾 在Spring源码系列第二篇中介绍了Environment组件,后续又介绍Spring中Resource的抽象,但是对于上下文的启动过程详解并未继续.经过一个星期的准备,梳理了Spri ...

  8. Spring源码系列(三)--spring-aop的基础组件、架构和使用

    简介 前面已经讲完 spring-bean( 详见Spring ),这篇博客开始攻克 Spring 的另一个重要模块--spring-aop. spring-aop 可以实现动态代理(底层是使用 JD ...

  9. Spring源码系列(四)--spring-aop是如何设计的

    简介 spring-aop 用于生成动态代理类(底层是使用 JDK 动态代理或 cglib 来生成代理类),搭配 spring-bean 一起使用,可以使 AOP 更加解耦.方便.在实际项目中,spr ...

随机推荐

  1. java算法 蓝桥杯 格子位置

    问题描述 输入三个自然数N,i,j (1<=i<=N,1<=j<=N),输出在一个N*N格的棋盘中,与格子(i,j)同行.同列.同一对角线的所有格子的位置. 输入格式 输入共三 ...

  2. linux系统下find删除目录下除一文件外的所有文件

    /data/目录下有a.txt b.txt c.txt d.txt删除/data/目录下所有文件,保留b.txt两种方法:1.[root@xuegod62 ~]# find /data/ -type ...

  3. ADXL345经验总结,采用SPI和I2C总线操作

    一. ADXL345简介       ADXL345是ADI公司推出的三轴(x,y,z)iMEMS数字加速度计(digital accelerometer),具有在16G下高分辨率(13Bit)测量能 ...

  4. MATLAB绘制等高线和梯度场

    clear;clc;close all [X,Y] = meshgrid(-:.:); % 产生网格数据X和Y Z = X.*exp(-X.^ - Y.^); % 计算网格点处曲面上的Z值 [DX,D ...

  5. [css]《css揭秘》学习笔记(一)

    一.background-clip属性 <html> <head> <meta charset="utf-8"> <title>背景 ...

  6. Wireshark网络抓包(三)——网络协议

    一.ARP协议 ARP(Address Resolution Protocol)地址解析协议,将IP地址解析成MAC地址. IP地址在OSI模型第三层,MAC地址在OSI第二层,彼此不直接通信: 在通 ...

  7. 面试之MySQL基本命令

    既然要操作数据库就从数据库链接写起,包括建库.建表.增删该查字段及约束,删库,删表的数据,以下主要是对我以往面试的总结,欢迎补充! 一.数据库连接 1.连接本机(p和密码123456之间无空格) my ...

  8. 浅谈时间复杂度- 算法衡量标准Big O

    写在前面: 今天有一场考试,考到了Big-O的知识点,考到了一道原题,原题的答案我记住了,但实际题目有一些改动导致答案有所改动,为此作者决定重新整理一下复杂度相关知识点 Efficiency and ...

  9. BZOJ [HAOI2011]防线修建(动态凸包)

    听说有一种很高端的东西叫动态凸包维护dp就像学一下,不过介于本人还不会动态凸包就去学了下,还是挺神奇的说,维护上下凸包的写法虽然打得有点多不过也只是维护复制黏贴的事情而已罢了. 先说下动态凸包怎么写吧 ...

  10. Linux实战教学笔记17:精简shell基础

    第十七节 精简shell基础 标签(空格分隔): Linux实战教学笔记 1,前言 1.1 为什么学习shell编程 Shell脚本语言是实现Linux/UNIX系统管理及自动化运维所必备的重要工具, ...