下面我們來看看Spring的AOP的一些相關代碼是怎麼得到Proxy的,讓我們我們先看看 AOP和Spring AOP的一些基本概念:
Advice:
通知,制定在連接點做什麼,在Sping中,他主要描述Spring圍繞方法調用注入的額外 的行為,Spring提供的通知類型有:
before advice,AfterReturningAdvice,ThrowAdvice,MethodBeforeAdvice,這些都是 Spring AOP定義的接口類,具體的動作實現需要用戶程序來完成。
Pointcut:
切點,其決定一個advice應該應用於哪個連接點,也就是需要插入額外處理的地方的 集合,例如,被某個advice作為目標的一組方法。Spring pointcut通常意味著標示方法 ,可以選擇一組方法調用作為pointcut,Spring提供了具體的切點來給用戶使用,比如正 則表達式切點 JdkRegexpMethodPointcut通過正則表達式對方法名進行匹配,其通過使用 AbstractJdkRegexpMethodPointcut中的對MethodMatcher接口的實現來完成pointcut功能 :
Java代碼
public final boolean matches(Method method, Class targetClass) {
//這裡通過放射得到方法的全名
String patt = method.getDeclaringClass().getName() + "." + method.getName();
for (int i = 0; i < this.patterns.length; i++) {
// 這裡是判斷是否和方法名是否匹配的代碼
boolean matched = matches(patt, i);
if (matched) {
for (int j = 0; j < this.excludedPatterns.length; j++) {
boolean excluded = matchesExclusion(patt, j);
if(excluded) {
return false;
}
}
return true;
}
}
return false;
}
在JDKRegexpMethodPointcut中通過JDK中的正則表達式匹配來完成pointcut的最終確 定:
Java代碼
protected boolean matches(String pattern, int patternIndex) {
Matcher matcher = this.compiledPatterns[patternIndex].matcher (pattern);
return matcher.matches();
}
Advisor:
當我們完成額外的動作設計(advice)和額外動作插入點的設計(pointcut)以後,我們 需要一個對象把他們結合起來,這就是通知器 - advisor,定義應該在哪裡應用哪個通知 。Advisor的實現有:DefaultPointcutAdvisor他有兩個屬性advice和 pointcut來讓我們 配置advice和pointcut。
接著我們就可以通過ProxyFactoryBean來配置我們的代理對象和方面行為,在 ProxyFactoryBean中有interceptorNames來配置已經定義好的通知器-advisor,雖然這裡 的名字叫做interceptNames,但實際上是供我們配置advisor的地方,具體的代理實現通過 JDK 的Proxy或者CGLIB來完成。因為ProxyFactoryBean是一個FactoryBean,在 ProxyFactoryBean中我們通過getObject()可以直接得到代理對象:
Java代碼
public Object getObject() throws BeansException {
//這裡初始化通知器鏈
initializeAdvisorChain();
if (isSingleton()) {
//根據定義需要生成單件的Proxy
return getSingletonInstance();
}
else {
.......
//這裡根據定義需要生成Prototype類型的Proxy
return newPrototypeInstance();
}
}
我們看看怎樣生成單件的代理對象:
Java代碼
private synchronized Object getSingletonInstance() {
if (this.singletonInstance == null) {
this.targetSource = freshTargetSource();
if (this.autodetectInterfaces && getProxiedInterfaces ().length == 0 && !isProxyTargetClass()) {
// 這裡設置代理對象的接口
setInterfaces(ClassUtils.getAllInterfacesForClass (this.targetSource.getTargetClass()));
}
// Eagerly initialize the shared singleton instance.
super.setFrozen(this.freezeProxy);
// 注意這裡的方法會使用ProxyFactory來生成我們需要的Proxy
this.singletonInstance = getProxy(createAopProxy());
// We must listen to superclass advice change events to recache the singleton
// instance if necessary.
addListener(this);
}
return this.singletonInstance;
}
//使用createAopProxy放回的AopProxy來得到代理對象。
protected Object getProxy(AopProxy aopProxy) {
return aopProxy.getProxy(this.beanClassLoader);
}
ProxyFactoryBean的父類是AdvisedSupport,Spring使用AopProxy接口把AOP代理的實 現與框架的其他部分分離開來;在AdvisedSupport中通過這樣的方式來得到AopProxy,當 然這裡需要得到AopProxyFactory的幫助 - 下面我們看到Spring為我們提供的實現,來幫 助我們方便的從JDK或者cglib中得到我們想要的代理對象:
Java代碼
protected synchronized AopProxy createAopProxy() {
if (!this.isActive) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
而在ProxyConfig中對使用的AopProxyFactory做了定義:
Java代碼
//這個DefaultAopProxyFactory是Spring用來生成AopProxy的地方,
//當然了它包含JDK和Cglib兩種實現方式。
private transient AopProxyFactory aopProxyFactory = new DefaultAopProxyFactory();
其中在DefaultAopProxyFactory中是這樣生成AopProxy的:
Java代碼
public AopProxy createAopProxy(AdvisedSupport advisedSupport) throws AopConfigException {
//首先考慮使用cglib來實現代理對象,當然如果同時目標對象不是接口的實 現類的話
if (advisedSupport.isOptimize() || advisedSupport.isProxyTargetClass() ||
advisedSupport.getProxiedInterfaces().length == 0) {
//這裡判斷如果不存在cglib庫,直接拋出異常。
if (!cglibAvailable) {
throw new AopConfigException(
"Cannot proxy target class because CGLIB2 is not available. " +
"Add CGLIB to the class path or specify proxy interfaces.");
}
// 這裡使用Cglib來生成Proxy,如果target不是接口的實現的話,返回 cglib類型的AopProxy
return CglibProxyFactory.createCglibProxy(advisedSupport);
}
else {
// 這裡使用JDK來生成Proxy,返回JDK類型的AopProxy
return new JdkDynamicAopProxy(advisedSupport);
}
}
於是我們就可以看到其中的代理對象可以由JDK或者Cglib來生成,我們看到 JdkDynamicAopProxy類和Cglib2AopProxy都實現的是AopProxy的接口,在 JdkDynamicAopProxy實現中我們可以看到Proxy是怎樣生成的:
Java代碼
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
Class targetClass = this.advised.getTargetSource ().getTargetClass();
logger.debug("Creating JDK dynamic proxy" +
(targetClass != null ? " for [" + targetClass.getName() + "]" : ""));
}
Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
//這裡我們調用JDK Proxy來生成需要的Proxy實例
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
這樣用Proxy包裝target之後,通過ProxyFactoryBean得到對其方法的調用就被Proxy 攔截了, ProxyFactoryBean的getObject()方法得到的實際上是一個Proxy了,我們的 target對象已經被封裝了。對 ProxyFactoryBean這個工廠bean而言,其生產出來的對象 是封裝了目標對象的代理對象。