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.
* <p>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.
* <p>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.
* <p>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 ProxyCreatorSupport
implements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware {
...
@Override
@Nullable
public 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<Advisor> advisors = new ArrayList<>();
...
}