最近看了SpringAop的源码实现  大概记录一下aop的源码流程

创建一个最简单的一个测试类

package com.zcg.learn.Test;

import org.aopalliance.aop.Advice;
import org.junit.Test;
import org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.tests.aop.advice.CountingAfterReturningAdvice;
import org.springframework.tests.aop.advice.CountingBeforeAdvice;

import com.zcg.learn.UserService;
import com.zcg.learn.UserServiceImpl;

/**
* SpringAop源码分析测试类
* @author zcg
* 2018/3/1
*
*/
public class SpringAopTest {

/**
* 创建代理
*/
@Test
public void createProxyTest() {
Object target = new UserServiceImpl();
ProxyFactory pf = new ProxyFactory(target);
//CountingBeforeAdvice 前置通知计数器
CountingBeforeAdvice countingBeforeAdvice = new CountingBeforeAdvice();
pf.addAdvice(countingBeforeAdvice);
UserService service = (UserService) pf.getProxy();
service.addUser();
}

/**
* 动态添加 移除通知
*/
@Test
public void createProxyTest2() {
Object target = new UserServiceImpl();
ProxyFactory pf = new ProxyFactory(target);
UserService service = (UserService) pf.getProxy();
Advised advised = (Advised) service;
CountingBeforeAdvice countingBeforeAdvice = new CountingBeforeAdvice();
CountingAfterReturningAdvice countingAfterReturningAdvice = new CountingAfterReturningAdvice();
advised.addAdvice(countingAfterReturningAdvice);
advised.addAdvice(countingBeforeAdvice);
service.addUser();
advised.removeAdvice(countingAfterReturningAdvice);
service.addUser();
}

@Test
public void createProxyAspectJByTest() {
Object target = new UserServiceImpl();
AspectJProxyFactory pf = new AspectJProxyFactory(target);
AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
advisor.setExpression("execution(* *.addUser(..))");
CountingBeforeAdvice counting = new CountingBeforeAdvice();
advisor.setAdvice(counting);
pf.addAdvisor(advisor);
UserService userService = pf.getProxy();
userService.addUser();
/**
* advice 通知拦截器
* advisor 通知加切入点适配器
*/

}

}

其中测试方式

@Test
public void createProxyTest() {
Object target = new UserServiceImpl();

ProxyFactory pf = new ProxyFactory(target);
//CountingBeforeAdvice 前置通知计数器
CountingBeforeAdvice countingBeforeAdvice = new CountingBeforeAdvice();
pf.addAdvice(countingBeforeAdvice);
UserService service = (UserService) pf.getProxy();
service.addUser();
}

1.target 以构造参数的形式放入在ProxyFactory中,实际上将该tartget放入在AdvisedSupport类中

2.countingBeforeAdvice 为Spring Aop自带的前置通知计数

3.1 UserService service = (UserService) pf.getProxy();从中获取代理类

ProxyFactory类中 extends ProxyCreatorSupport

/*

* 代理生成工厂
*/
@SuppressWarnings("serial")
public class ProxyFactory extends ProxyCreatorSupport {

/**
* Create a new proxy according to the settings in this factory.
* <p>Can be called repeatedly. Effect will vary if we've added
* or removed interfaces. Can add and remove interceptors.
* <p>Uses a default class loader: Usually, the thread context class loader
* (if necessary for proxy creation).
* @return the proxy object
*/
public Object getProxy() {
return createAopProxy().getProxy();
}

}

3.2 createAopProxy()方法是父类ProxyCreatorSupport里面的方法

protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}

//得到Aop代理工厂和在当前代理工厂创建该代理类
return getAopProxyFactory().createAopProxy(this);
}

其中getAopProxyFactory().createAopProxy(this)在DefaultAopProxyFa1ctory类中执行 具体代码如下

@SuppressWarnings("serial")
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

@Override
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.");
}

//r如果目标类有接口或者是代理类,则走jdk的动态代理 否则走cglib的动态代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}

/**
* Determine whether the supplied {@link AdvisedSupport} has only the
* {@link org.springframework.aop.SpringProxy} interface specified
* (or no proxy interfaces specified at all).
*/
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] ifcs = config.getProxiedInterfaces();
return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
}

}

3.3 JdkDynamicAopProxy类实现了InvocationHandler 对invoke进行的重写 核心代码如下

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {

@Override
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]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else 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);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...

//初始化MethodInvocation类
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 != Object.class && 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);
}
}
}

}

其中的 AdvisedSupport类的this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)方法主要得到代理的所有拦截器方法

核心代码如下

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, 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;
}

getInterceptorsAndDynamicInterceptionAdvice方法核心代码如下:

public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {

@Override
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();

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();
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;
}

}

3.4 invocation.proceed()核心代码如下

public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable{

@Override
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;
if (dm.methodMatcher.matches(this.method, this.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);
}
}

}

其中前置拦截器方法如下

@SuppressWarnings("serial")
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {

private MethodBeforeAdvice advice;

/**
* Create a new MethodBeforeAdviceInterceptor for the given advice.
* @param advice the MethodBeforeAdvice to wrap
*/
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}

//重写invoke方法

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
return mi.proceed();
}

}

后置通知拦截器方法

@SuppressWarnings("serial")
public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {

private final AfterReturningAdvice advice;

/**
* Create a new AfterReturningAdviceInterceptor for the given advice.
* @param advice the AfterReturningAdvice to wrap
*/
public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}

}

流程大概如此  可能有点模糊,如果想继续学习加我QQ:1051980588 一起探讨和看其他相关的源码解析视频

Spring Aop源码分析的更多相关文章

  1. spring AOP源码分析(三)

    在上一篇文章 spring AOP源码分析(二)中,我们已经知道如何生成一个代理对象了,那么当代理对象调用代理方法时,增强行为也就是拦截器是如何发挥作用的呢?接下来我们将介绍JDK动态代理和cglib ...

  2. Spring AOP 源码分析 - 拦截器链的执行过程

    1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在我们的得 ...

  3. Spring AOP 源码分析 - 创建代理对象

    1.简介 在上一篇文章中,我分析了 Spring 是如何为目标 bean 筛选合适的通知器的.现在通知器选好了,接下来就要通过代理的方式将通知器(Advisor)所持有的通知(Advice)织入到 b ...

  4. Spring AOP 源码分析 - 筛选合适的通知器

    1.简介 从本篇文章开始,我将会对 Spring AOP 部分的源码进行分析.本文是 Spring AOP 源码分析系列文章的第二篇,本文主要分析 Spring AOP 是如何为目标 bean 筛选出 ...

  5. Spring AOP 源码分析系列文章导读

    1. 简介 前一段时间,我学习了 Spring IOC 容器方面的源码,并写了数篇文章对此进行讲解.在写完 Spring IOC 容器源码分析系列文章中的最后一篇后,没敢懈怠,趁热打铁,花了3天时间阅 ...

  6. Spring AOP源码分析(三):基于JDK动态代理和CGLIB创建代理对象的实现原理

    AOP代理对象的创建 AOP相关的代理对象的创建主要在applyBeanPostProcessorsBeforeInstantiation方法实现: protected Object applyBea ...

  7. 5.2 Spring5源码--Spring AOP源码分析二

    目标: 1. 什么是AOP, 什么是AspectJ 2. 什么是Spring AOP 3. Spring AOP注解版实现原理 4. Spring AOP切面原理解析 一. 认识AOP及其使用 详见博 ...

  8. 5.2 spring5源码--spring AOP源码分析二--切面的配置方式

    目标: 1. 什么是AOP, 什么是AspectJ 2. 什么是Spring AOP 3. Spring AOP注解版实现原理 4. Spring AOP切面原理解析 一. 认识AOP及其使用 详见博 ...

  9. spring aop 源码分析(三) @Scope注解创建代理对象

    一.源码环境的搭建: @Component @Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON,proxyMode = ScopedP ...

  10. 最简 Spring AOP 源码分析!

    前言 最近在研究 Spring 源码,Spring 最核心的功能就是 IOC 容器和 AOP.本文定位是以最简的方式,分析 Spring AOP 源码. 基本概念 上面的思维导图能够概括了 Sprin ...

随机推荐

  1. PAT1034;Head of a Gang

    1034. Head of a Gang (30) 时间限制 100 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue One wa ...

  2. CAS 4.0.x 自定义登录页面

    版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[-] CAS默认登录页面 复制一个新的页面管理页面 修改页面引用 修改casproperties 修改casLoginViewjs ...

  3. 谈谈对Javascript构造函数和原型对象的理解

    对象,是javascript中非常重要的一个梗,是否能透彻的理解它直接关系到你对整个javascript体系的基础理解,说白了,javascript就是一群对象在搅..(哔!).   常用的几种对象创 ...

  4. java.lang.IllegalArgumentException: Request header is too large

    tomcat运行项目时,有一个请求过去后,后台报这样的错java.lang.IllegalArgumentException: Request header is too large原因:请求头超过了 ...

  5. 在Python中用Request库模拟登录(一):字幕库(无加密,无验证码)

    字幕库的登录表单如下所示,其中省去了无关紧要的内容: <form class="login-form" action="/User/login.html" ...

  6. Spring-cloud (九) Hystrix请求合并的使用

    前言: 承接上一篇文章,两文本来可以一起写的,但是发现RestTemplate使用普通的调用返回包装类型会出现一些问题,也正是这个问题,两文没有合成一文,本文篇幅不会太长,会说一下使用和适应的场景. ...

  7. Java API获取topic所占磁盘空间(Kafka 1.0.0)

    很多用户都有这样的需求:实时监控某个topic各分区在broker上所占的磁盘空间大小总和.Kafka并没有提供直接的脚本工具用于统计这些数据. 如果依然要实现这个需求,一种方法是通过监控JMX指标得 ...

  8. mac上如何解压和压缩rar文件

    许多喜欢mac的人都知道,这个os没有像win上winRAR或者hao123解压等类似软件,对于文件的压缩和解压很不方便,在下载rar的文件包之后就会束手无策,很是尴尬至极,为了避免这种情况,自己动手 ...

  9. SSH(Spring_SpringMVC_Hibernate)

    Users实体类 package com.tao.pojo; public class Users { private int id; private String name; private Str ...

  10. selenium处理iframe定位于切换问题解决办法

    首先还是围绕以下几个方面来看: 1.什么是iframe? 2.为什么我们要定位iframe? 3.我们怎样定位iframe,与切换iframe? 1.什么是iframe? ♦ b/s架构都使用ifra ...