1. 先分析Advice

before执行Cglib2AopProxy的intercept方法:

/*** General purpose AOP callback. Used when the target is dynamic or when the* proxy is not frozen.*/private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {private AdvisedSupport advised;public DynamicAdvisedInterceptor(AdvisedSupport advised) {this.advised = advised;}public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {MethodInvocation invocation = null;Object oldProxy = null;boolean setProxyContext = false;Class targetClass = null;Object target = null;try {Object retVal = null;if (this.advised.exposeProxy) {// Make invocation available if necessary.oldProxy = AopContext.setCurrentProxy(proxy);setProxyContext = true;}// May be <code>null</code>. Get as late as possible to minimize the time we// "own" the target, in case it comes from a pool.target = getTarget();if (target != null) {targetClass = target.getClass();}List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);// Check whether we only have one InvokerInterceptor: that is,// no real advice, but just reflective invocation of the target.if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {// 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.retVal = methodProxy.invoke(target, args);}else {// We need to create a method invocation...invocation = new CglibMethodInvocation(proxy, target, method, args,targetClass, chain, methodProxy);// If we get here, we need to create a MethodInvocation.retVal = invocation.proceed();}retVal = massageReturnTypeIfNecessary(proxy, target, method, retVal);return retVal;}finally {if (target != null) {releaseTarget(target);}if (setProxyContext) {// Restore old proxy.
                    AopContext.setCurrentProxy(oldProxy);}}}

第一步:获取target

target.getClass();

第二步:获取拦截器和advice,返回定义好的org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor示例

/*** Determine a list of {@link org.aopalliance.intercept.MethodInterceptor} objects* for the given method, based on this configuration.* @param method the proxied method* @param targetClass the target class* @return List of MethodInterceptors (may also include InterceptorAndDynamicMethodMatchers)*/public List getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) {MethodCacheKey cacheKey = new MethodCacheKey(method);List cached = (List) this.methodCache.get(cacheKey);if (cached == null) {cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);this.methodCache.put(cacheKey, cached);}return cached;}

第三步创建一个方法的invocation

                    // We need to create a method invocation...invocation = new CglibMethodInvocation(proxy, target, method, args,targetClass, chain, methodProxy);

第四步 执行aop的before方法

    public void before(Method method, Object[] args, Object target)throws Throwable {System.out.println(" Before method!");}

第五步 触发MethodBeforeAdviceInterceptor的invoke方法

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

第六步:触发ReflectiveMethodInvocation的process方法

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

第七步,包装返回值Cglib2AopProxy

/*** Wrap a return of this if necessary to be the proxy*/private static Object massageReturnTypeIfNecessary(Object proxy, Object target, Method method, Object retVal) {// Massage return value if necessaryif (retVal != null && retVal == target &&!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {// Special case: it returned "this".// Note that we can't help if the target sets a reference// to itself in another returned object.retVal = proxy;}return retVal;}

最后执行finanly方法

finally {if (target != null) {releaseTarget(target);}if (setProxyContext) {// Restore old proxy.
                    AopContext.setCurrentProxy(oldProxy);}

before,after,around,throw基本相似,不一一赘述

2.PointCut和Advisor为例

2.1 创建代理的过程

首先是ProxyFactoryBean获取对象代理

    /*** Return a proxy. Invoked when clients obtain beans from this factory bean.* Create an instance of the AOP proxy to be returned by this factory.* The instance will be cached for a singleton, and create on each call to* <code>getObject()</code> for a proxy.* @return a fresh AOP proxy reflecting the current state of this factory*/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();}}

获取过程如下:

    /*** Return the singleton instance of this class's proxy object,* lazily creating it if it hasn't been created already.* @return the shared singleton proxy*/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");}setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));}// Initialize the shared singleton instance.super.setFrozen(this.freezeProxy);this.singletonInstance = getProxy(createAopProxy());}return this.singletonInstance;} 

父类创建代理的过程

    /*** Subclasses should call this to get a new AOP proxy. They should <b>not</b>* create an AOP proxy with <code>this</code> as an argument.*/protected final synchronized AopProxy createAopProxy() {if (!this.active) {activate();}return getAopProxyFactory().createAopProxy(this);}

调用代理工厂创建代理的过程

    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.");}if (targetClass.isInterface()) {return new JdkDynamicAopProxy(config);}if (!cglibAvailable) {throw new AopConfigException("Cannot proxy target class because CGLIB2 is not available. " +"Add CGLIB to the class path or specify proxy interfaces.");}return CglibProxyFactory.createCglibProxy(config);}else {return new JdkDynamicAopProxy(config);}}

可以看出,代理的实现主要是jdk本身自带的动态代理和cglib提供的代理。

2.2 获取代理的过程

this.singletonInstance = getProxy(createAopProxy());

Cglib2AopProxy类的Object getProxy(ClassLoader classLoader)

    public Object getProxy(ClassLoader classLoader) {if (logger.isDebugEnabled()) {logger.debug("Creating CGLIB2 proxy: target source is " + this.advised.getTargetSource());}try {Class rootClass = this.advised.getTargetClass();Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");Class proxySuperClass = rootClass;if (AopUtils.isCglibProxyClass(rootClass)) {proxySuperClass = rootClass.getSuperclass();Class[] additionalInterfaces = rootClass.getInterfaces();for (int i = 0; i < additionalInterfaces.length; i++) {Class additionalInterface = additionalInterfaces[i];this.advised.addInterface(additionalInterface);}}// Validate the class, writing log messages as necessary.
            validateClassIfNecessary(proxySuperClass);// Configure CGLIB Enhancer...Enhancer enhancer = createEnhancer();if (classLoader != null) {enhancer.setClassLoader(classLoader);if (classLoader instanceof SmartClassLoader &&((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {enhancer.setUseCache(false);}}enhancer.setSuperclass(proxySuperClass);enhancer.setStrategy(new UndeclaredThrowableStrategy(UndeclaredThrowableException.class));enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));enhancer.setInterceptDuringConstruction(false); Callback[] callbacks = getCallbacks(rootClass);enhancer.setCallbacks(callbacks);enhancer.setCallbackFilter(new ProxyCallbackFilter(this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));Class[] types = new Class[callbacks.length];for (int x = 0; x < types.length; x++) {types[x] = callbacks[x].getClass();}enhancer.setCallbackTypes(types);// Generate the proxy class and create a proxy instance.
            Object proxy;if (this.constructorArgs != null) {proxy = enhancer.create(this.constructorArgTypes, this.constructorArgs);}else {proxy = enhancer.create();}return proxy;}catch (CodeGenerationException ex) {throw new AopConfigException("Could not generate CGLIB subclass of class [" +this.advised.getTargetClass() + "]: " +"Common causes of this problem include using a final class or a non-visible class",ex);}catch (IllegalArgumentException ex) {throw new AopConfigException("Could not generate CGLIB subclass of class [" +this.advised.getTargetClass() + "]: " +"Common causes of this problem include using a final class or a non-visible class",ex);}catch (Exception ex) {// TargetSource.getTarget() failedthrow new AopConfigException("Unexpected AOP exception", ex);}}

获取回调方法

    private Callback[] getCallbacks(Class rootClass) throws Exception {// Parameters used for optimisation choices...boolean exposeProxy = this.advised.isExposeProxy();boolean isFrozen = this.advised.isFrozen();boolean isStatic = this.advised.getTargetSource().isStatic();// Choose an "aop" interceptor (used for AOP calls).Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);// Choose a "straight to target" interceptor. (used for calls that are// unadvised but can return this). May be required to expose the proxy.Callback targetInterceptor = null;if (exposeProxy) {targetInterceptor = isStatic ?(Callback) new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :(Callback) new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());}else {targetInterceptor = isStatic ?(Callback) new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :(Callback) new DynamicUnadvisedInterceptor(this.advised.getTargetSource());}// Choose a "direct to target" dispatcher (used for// unadvised calls to static targets that cannot return this).Callback targetDispatcher = isStatic ?(Callback) new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp();Callback[] mainCallbacks = new Callback[]{aopInterceptor, // for normal advicetargetInterceptor, // invoke target without considering advice, if optimizednew SerializableNoOp(), // no override for methods mapped to thistargetDispatcher, this.advisedDispatcher,new EqualsInterceptor(this.advised),new HashCodeInterceptor(this.advised)};Callback[] callbacks;// If the target is a static one and the advice chain is frozen,// then we can make some optimisations by sending the AOP calls// direct to the target using the fixed chain for that method.if (isStatic && isFrozen) {Method[] methods = rootClass.getMethods();Callback[] fixedCallbacks = new Callback[methods.length];this.fixedInterceptorMap = new HashMap(methods.length);// TODO: small memory optimisation here (can skip creation for// methods with no advice)for (int x = 0; x < methods.length; x++) {List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());this.fixedInterceptorMap.put(methods[x].toString(), new Integer(x));}// Now copy both the callbacks from mainCallbacks// and fixedCallbacks into the callbacks array.callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];for (int x = 0; x < mainCallbacks.length; x++) {callbacks[x] = mainCallbacks[x];}for (int x = 0; x < fixedCallbacks.length; x++) {callbacks[x + mainCallbacks.length] = fixedCallbacks[x];}this.fixedInterceptorOffset = mainCallbacks.length;}else {callbacks = mainCallbacks;}return callbacks;}

获取拦截器和动态拦截器Advice

    /*** Determine a list of {@link org.aopalliance.intercept.MethodInterceptor} objects* for the given method, based on this configuration.* @param method the proxied method* @param targetClass the target class* @return List of MethodInterceptors (may also include InterceptorAndDynamicMethodMatchers)*/public List getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) {MethodCacheKey cacheKey = new MethodCacheKey(method);List cached = (List) this.methodCache.get(cacheKey);if (cached == null) {cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);this.methodCache.put(cacheKey, cached);}return cached;}

继续调用DefaultAdvisorChainFactory:

public List 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 interceptorList = new ArrayList(config.getAdvisors().length);boolean hasIntroductions = hasMatchingIntroductions(config, targetClass);AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();Advisor[] advisors = config.getAdvisors();for (int i = 0; i < advisors.length; i++) {Advisor advisor = advisors[i];if (advisor instanceof PointcutAdvisor) {// Add it conditionally.PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) {MethodInterceptor[] interceptors = registry.getInterceptors(advisor);MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) {if (mm.isRuntime()) {// Creating a new object instance in the getInterceptors() method// isn't a problem as we normally cache created chains.for (int j = 0; j < interceptors.length; j++) {interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptors[j], mm));}}else {interceptorList.addAll(Arrays.asList(interceptors));}}}}else if (advisor instanceof IntroductionAdvisor) {IntroductionAdvisor ia = (IntroductionAdvisor) advisor;if (config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) {Interceptor[] interceptors = registry.getInterceptors(advisor);interceptorList.addAll(Arrays.asList(interceptors));}}else {Interceptor[] interceptors = registry.getInterceptors(advisor);interceptorList.addAll(Arrays.asList(interceptors));}}return interceptorList;}

NameMatchMethodPointcut

    public boolean matches(Method method, Class targetClass) {for (int i = 0; i < this.mappedNames.size(); i++) {String mappedName = (String) this.mappedNames.get(i);if (mappedName.equals(method.getName()) || isMatch(method.getName(), mappedName)) {return true;}}return false;}

转载于:https://www.cnblogs.com/davidwang456/p/5534090.html

spring aop源码实现分析相关推荐

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

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

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

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

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

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

  4. spring AOP源码分析(一)

    spring AOP源码分析(一) 对于springAOP的源码分析,我打算分三部分来讲解:1.配置文件的解析,解析为BeanDefination和其他信息然后注册到BeanFactory中:2.为目 ...

  5. 一步一步手绘Spring AOP运行时序图(Spring AOP 源码分析)

    相关内容: 架构师系列内容:架构师学习笔记(持续更新) 一步一步手绘Spring IOC运行时序图一(Spring 核心容器 IOC初始化过程) 一步一步手绘Spring IOC运行时序图二(基于XM ...

  6. 【Spring】Spring AOP源码分析-导读(一)

    文章目录 1.简介 2.AOP 原理 3.AOP 术语及相应的实现 3.1 连接点 - Joinpoint 3.2 切点 - Pointcut 3.3 通知 - Advice 3.4 切面 - Asp ...

  7. Spring AOP 源码系列(一)解析 AOP 配置信息

    在进行源码阅读之前建议先看一下这篇文章:Spring AOP 源码分析系列文章导读 by 田小波,写的非常好,推荐阅读. 关于 AOP 中常用的一些术语这里就不解释了,如果不清楚的建议先看一遍上面推荐 ...

  8. 轻轻松松看懂Spring AOP源码

    轻轻松松看懂Spring AOP源码 https://baijiahao.baidu.com/s?id=1596466083334197175&wfr=spider&for=pc 如果 ...

  9. Spring AOP源码(1)—<aop:config/>AOP配置标签解析【一万字】

      基于最新Spring 5.x,对Spring AOP中的<aop:config/>标签的解析源码进行了详细分析,这是Spring AOP源码的入口!   此前我们已经详细学习了Spri ...

最新文章

  1. python可以处理任何字符编码文本_python数据类型、字符编码、文件处理
  2. 记录一次maven jar包冲突的排查过程
  3. SIMD学习 -- 用SSE2指令作点乘和累加计算
  4. 设计模式(九)——适配器模式
  5. python取的键不存在_Python3基础 dict get 在查询不存在的键时,返回指定的内容
  6. python字典value排序_python字典按照value排序方法
  7. 【深度学习】【U-net】医学图像(血管)分割实验记录
  8. javascript学习心得(1)replace
  9. insert php code test
  10. [SRv6]《SRv6网络编程》SRv6 OAM与随路网络测量(1/2:OAM)
  11. AssetBundle接口详解与优化
  12. 视频下载离线工具—“Softorino YouTube Converter”
  13. 信而泰ALPS 用户管理——网络测试仪实操
  14. 地图导航中的路径规划算法(综述)
  15. 手机软件测试英语,手机软件测试,mobile phone software testing,音标,读音,翻译,英文例句,英语词典...
  16. 短视频的地方搞笑配音怎么做?分享一个小技巧,不会方言也能配
  17. P2380 狗哥采矿 (二维dp)
  18. CCleaner的使用
  19. MAC下 抖音APK反编译
  20. 服务器架构项目计划书,VMware服务器虚拟架构实施方案计划书模板v2[1].0.doc

热门文章

  1. as工程放到源码编译_关于AS高版本SDK编译生成的apk放入低版本android源码中集成编译...
  2. php对json随机排序,按月对PHP JSON数组进行排序
  3. 阿里云物联网生活平台简介
  4. 安徽省计算机二级大题教程,安徽省计算机二级例题
  5. 相关系数excel_跟着思想学外汇-如何用Excel计算货币相关性
  6. php中的伪类选择器,css伪类选择器介绍
  7. php 立即释放session 去除其缓存,ThinkPHP关于session无法清除的一个小问题
  8. 手机黑圆点怎么打_黑鲨游戏手机3S手机配置怎么样,是否值得购买?
  9. c++ const 常指针
  10. not in the sudoers file. This incident will be reported.