Spring对AOP的实现
创始人
2024-03-15 16:18:41
0

Spring对AOP实现的模式分为2种,一种是代理,一种是AspectJ,这种区分方式是直接使用实现方式区分的。

二、Spring对动态代理的设计

动态代理我们都知道在Spring中分为JDK动态代理和cglib动态代理,JDK动态代理自不用说,由Java运行时环境提供,而对于cglib,Spring将他封装在了spring-core中,足以证明动态代理在Spring中处于一个基础+核心的地位,所以我们更加有必要搞清楚Spring是如何使用cglib的,而对于Spring AOP而言,则是单独的作为一个模块出现:spring-aop。

三、2种动态代理的特点

JDK动态代理需提供接口,代理类实现的是接口中的方法,如果无法提供目标对象的接口,无法完成代理。
cglib通过继承目标类,所以无法目标类为final时无法代理,目标类中方法为final或private时无法代理。
JDK通过反射实时生成代理对象,cglib通过操作字节码生成代理对象,cglib动态代理会较JDK动态代理快。

四、AOP联盟的标准

先来看看spring-aop包的结构:



其中aopalliance是对AOP和Java有浓厚兴趣的软件开发人员联合成立的开源项目,Spring是按照AOP联盟的规范做的实现,可见Spring是一个集众多基础框架于一身的伟大软件。aopalliance包里面只有接口,没有任何实现,这就是一个规范定义。

AOP联盟定义的顶级概念有:
org.aopalliance.aop.Advice
org.aopalliance.intercept.Joinpoint
aop联盟中定义分为aop包和intercept,我们可以从这里看出aop联盟对切面的理解。advice是切面的逻辑,是切面中最直观的一个概念,其他的都是为advice服务的,要让advice工作的。
org.aopalliance.aop.Advice
aop联盟定义的advice是一个空接口,用来进行类型定义。

/*** Tag interface for Advice. Implementations can be any type* of advice, such as Interceptors.** @author Rod Johnson* @version $Id: Advice.java,v 1.1 2004/03/19 17:02:16 johnsonr Exp $*/
public interface Advice {}

org.aopalliance.intercept.Interceptor

public interface Interceptor extends Advice {}

 org.aopalliance.intercept.Joinpoint
从实现里可以重新对连接点有一个认识,proceed()方法推进到拦截链上的下一个拦截器。getThis()方法返回持一个对象,这个对象持有当前连接点静态部分,如invocation的目标对象。getStaticPart()返回连接点的静态部分。真的很抽象。

public interface Joinpoint {/*** Proceed to the next interceptor in the chain.* 

The implementation and the semantics of this method depends* on the actual joinpoint type (see the children interfaces).* @return see the children interfaces' proceed definition* @throws Throwable if the joinpoint throws an exception*/Object proceed() throws Throwable;/*** Return the object that holds the current joinpoint's static part.*

For instance, the target object for an invocation.* @return the object (can be null if the accessible object is static)*/Object getThis();/*** Return the static part of this joinpoint.*

The static part is an accessible object on which a chain of* interceptors are installed.*/AccessibleObject getStaticPart();}

 org.aopalliance.intercept.Invocation

public interface Invocation extends Joinpoint {/*** Get the arguments as an array object.* It is possible to change element values within this* array to change the arguments.* @return the argument of the invocation*/Object[] getArguments();}

Spring对AOP的设计如下:

Spring定义的顶级概念有:
org.springframework.aop.Advisor
org.springframework.aop.Pointcut
aop联盟没有切点的概念,只有连接点,切点描述的是被切的目标,如哪些方法,连接点描述的是目标被切的位置,如方法的前后。换句话说,aop联盟定义了能切目标,不关心用户要切目标中的哪一些。aop联盟定义的概念还是更加抽象,Spring定义的概念更加贴近实现。

org.aopalliance.aop.Advice

顶级接口增强,建议,也就是要添加的代理逻辑所在位置,Advice处于设计的高层,他会使用Joinpoint
AOP联盟和Spring对Advice的设计如下,可以看出,对ConstructorInterceptor大家一点兴趣也没有,没有人对构造方法处理,BeforeAdvice和AfterAdvice的功能也可以被

org.aopalliance.intercept.Joinpoint

顶级接口连接点,是调用代理逻辑的位置,注意不是代理逻辑所在位置,可以是构造方法,普通方法,字段等,我们通常使用的是方法。所以Joinpoint中有个重要方法proceed(),意思是继续处理。
AOP联盟对Joinpoint的设计如下,看的出来,连接点的子接口就是调用,调用又分为构造方法调用和普通方法调用。

MethodInterceptor里的重要方法是:Object invoke(MethodInvocation invocation) throws Throwable;
MethodInvocation里的重要方法是继承Joinpoint的:Object proceed() throws Throwable;
我们如果要开发框架,通常会继承MethodInterceptor,它像是个钩子,会被回调,代表代理的逻辑。
MethodInvocation通常是被动态代理框架实现,比如cglib,他会去实现里面的proceed()方法。
注意MethodInterceptor会使用MethodInvocation,MethodInterceptor是设计的高层。
以上是AOP联盟对AOP规范的定义。

五、Spring在AOP联盟基础上对AOP的设计

1、代理对象生成方式的设计
Spring AOP在动态代理方式的设计如下:
org.springframework.aop.framework.AopProxy
这个接口定义的是动态代理生成的方式,开箱即用的实现有2个,分别是cglib和JDK dynamic proxies,我们也可以看到实现类为:
org.springframework.aop.framework.JdkDynamicAopProxy
org.springframework.aop.framework.CglibAopProxy
具体实现我们这里不看了

2、生成动态代理对象
org.springframework.aop.framework.ProxyFactoryBean
这里有个ProxyCreatorSupport容易被忽视,但是他是非常重要的一个类
无论是getSingletonInstance()还是newPrototypeInstance()最后都调用了一个createAopProxy(...),这个方法创建代理方式的,一般返回JdkDynamicAopProxy或CglibAopProxy,但是这个我们并不太关心,知道就行了。
getObject()方法是获取代理对象的方法,里面根据情况调用getSingletonInstance()或newPrototypeInstance()方法
这两个方法最终会调用createAopProxy(),虽然这个方法是生成一个一个AopProxy实例,但是这个AopProxy实例是对应着一个具体的客户代理实例,所以里面需要处理很多客户代理的信息
关键是createAopProxy()方法将ProxyCreatorSupport类作为参数传递进去了,也就是说,生成代理实例的时候肯定需要使用ProxyCreatorSupport类。

@SuppressWarnings("serial")
public class ProxyFactoryBean extends ProxyCreatorSupportimplements FactoryBean, BeanClassLoaderAware, BeanFactoryAware {...@Override@Nullablepublic Object getObject() throws BeansException {initializeAdvisorChain();if (isSingleton()) {return getSingletonInstance();}else {if (this.targetName == null) {logger.info("Using non-singleton proxies with singleton targets is often undesirable. " +"Enable prototype proxies by setting the 'targetName' property.");}return newPrototypeInstance();}}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;}private synchronized Object newPrototypeInstance() {// In the case of a prototype, we need to give the proxy// an independent instance of the configuration.// In this case, no proxy will have an instance of this object's configuration,// but will have an independent copy.ProxyCreatorSupport copy = new ProxyCreatorSupport(getAopProxyFactory());// The copy needs a fresh advisor chain, and a fresh TargetSource.TargetSource targetSource = freshTargetSource();copy.copyConfigurationFrom(this, targetSource, freshAdvisorChain());if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {// Rely on AOP infrastructure to tell us what interfaces to proxy.Class targetClass = targetSource.getTargetClass();if (targetClass != null) {copy.setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));}}copy.setFrozen(this.freezeProxy);return getProxy(copy.createAopProxy());}protected final synchronized AopProxy createAopProxy() {if (!this.active) {activate();}return getAopProxyFactory().createAopProxy(this);}...
} 

3、org.springframework.aop.framework.ProxyCreatorSupport的作用
ProxyCreatorSupport本身的逻辑很简单,100多行代理而已,都是些封装一层的逻辑而已。关键是他的父类:

public class ProxyCreatorSupport extends AdvisedSupport {
...
}

4、org.springframework.aop.framework.AdvisedSupport
这个类是一个支持类,非常关键,里面有一个advisors成员,是Advisor列表,我们知道Advice是代理逻辑所在类,而Advisor是Advice的承载类,所以可以很明确的知道,AdvisedSupport类是生成代理的基础材料,因为他包含了所有的代理逻辑
这里的命名是Advised,有几个类的作用是必须要澄清的
org.springframework.aop.framework.Advised
org.springframework.aop.Advisor
org.aopalliance.aop.Advice
Advised使用Advisor,Advisor使用Advice,其实Advisor和Advice是一个一对一的关系,Advisor是Advice的一层封装

public class AdvisedSupport extends ProxyConfig implements Advised {...private List advisors = new ArrayList<>();...
}

相关内容

热门资讯

汽车油箱结构是什么(汽车油箱结... 本篇文章极速百科给大家谈谈汽车油箱结构是什么,以及汽车油箱结构原理图解对应的知识点,希望对各位有所帮...
美国2年期国债收益率上涨15个... 原标题:美国2年期国债收益率上涨15个基点 美国2年期国债收益率上涨15个基...
嵌入式 ADC使用手册完整版 ... 嵌入式 ADC使用手册完整版 (188977万字)💜&#...
重大消息战皇大厅开挂是真的吗... 您好:战皇大厅这款游戏可以开挂,确实是有挂的,需要了解加客服微信【8435338】很多玩家在这款游戏...
盘点十款牵手跑胡子为什么一直... 您好:牵手跑胡子这款游戏可以开挂,确实是有挂的,需要了解加客服微信【8435338】很多玩家在这款游...
senator香烟多少一盒(s... 今天给各位分享senator香烟多少一盒的知识,其中也会对sevebstars香烟进行解释,如果能碰...
终于懂了新荣耀斗牛真的有挂吗... 您好:新荣耀斗牛这款游戏可以开挂,确实是有挂的,需要了解加客服微信8435338】很多玩家在这款游戏...
盘点十款明星麻将到底有没有挂... 您好:明星麻将这款游戏可以开挂,确实是有挂的,需要了解加客服微信【5848499】很多玩家在这款游戏...
总结文章“新道游棋牌有透视挂吗... 您好:新道游棋牌这款游戏可以开挂,确实是有挂的,需要了解加客服微信【7682267】很多玩家在这款游...
终于懂了手机麻将到底有没有挂... 您好:手机麻将这款游戏可以开挂,确实是有挂的,需要了解加客服微信【8435338】很多玩家在这款游戏...