前言
前面兩部分講了程式入口 和 切面和增強的取得。這一部分講解代理的建立。
正文
查找Advisor的getAdvicesAndAdvisorsForBean方法的實作方式已經介紹完了,接下來我們介紹一下生成代理的createProxy方法的實作方式。在這個方法裡重要的方法如下:
- buildAdvisors:建立切面(todo:在找出适合的Advisor時,取得的結果可能是Advice嗎)
- getProxy:取得代理(也是建立代理過程)
protected Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
// 設定ProxyTargetClass屬性。
// 如果ProxyTargetClass為True,使用CGLIB方式代理;False,使用JdkDynamicProxy方式
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 建立切面
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
// 把建立的切面添加到ProxyFactory裡
for (Advisor advisor : advisors) {
proxyFactory.addAdvisor(advisor);
}
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 建立代理
return proxyFactory.getProxy(getProxyClassLoader());
}
1,建立切面流程
在buildAdvisors方法中,比較重要的是advisorAdapterRegistry.wrap方法的調用,這個方法是把Advice包裝成一個Advisor。
protected Advisor[] buildAdvisors(String beanName, Object[] specificInterceptors) {
// Handle prototypes correctly...
// 通過interceptorNames屬性,獲得聲明式代理方式下,指定的interceptorNames屬性裡聲明的advice或者advisor
// 在AspectJ代理方式時,應該沒有使用(因為感覺沒發現地方指定interceptorNames屬性)
Advisor[] commonInterceptors = resolveInterceptorNames();
List<Object> allInterceptors = new ArrayList<Object>();
if (specificInterceptors != null) {
allInterceptors.addAll(Arrays.asList(specificInterceptors));
if (commonInterceptors != null) {
if (this.applyCommonInterceptorsFirst) {
allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
}
else {
allInterceptors.addAll(Arrays.asList(commonInterceptors));
}
}
}
if (logger.isDebugEnabled()) {
int nrOfCommonInterceptors = (commonInterceptors != null ? commonInterceptors.length : 0);
int nrOfSpecificInterceptors = (specificInterceptors != null ? specificInterceptors.length : 0);
logger.debug("Creating implicit proxy for bean '" + beanName + "' with " + nrOfCommonInterceptors +
" common interceptors and " + nrOfSpecificInterceptors + " specific interceptors");
}
Advisor[] advisors = new Advisor[allInterceptors.size()];
for (int i = 0; i < allInterceptors.size(); i++) {
// 通過AdvisorAdapter把allInterceptors裡的元素包裝成Advisor。
// allInterceptors裡的元素不一定是Advisor類型,可能是Advice
advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
}
return advisors;
}
wrap方法是,如果參數是Advice類型,就包裝成Advisor。包裝時候是使用DefaultPointcutAdvisor進行包裝的。
包裝時候使用的是AdvisorAdapter接口。這個接口有兩個方法:
- supportsAdvice(Advice advice):判斷參數的Advice是不是目前Adapter支援的Advice。
- getInterceptor(Advisor advisor):根據參數Advice生成Interceptor。
supportsAdvice
方法裡使用的adapters屬性在DefaultAdvisorAdapterRegistry的構造函數裡就進行指派了,設定了3個Adapter:
- MethodBeforeAdviceAdapter
- AfterReturningAdviceAdapter
- ThrowsAdviceAdapter
這時在我們主要用到了supportsAdvice方法。這3個Adapter循環對Advice進行處理,如果Advice是Adapter支援的類型,就傳回一個Advisor。
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
if (adviceObject instanceof Advisor) {
return (Advisor) adviceObject;
}
if (!(adviceObject instanceof Advice)) {
throw new UnknownAdviceTypeException(adviceObject);
}
Advice advice = (Advice) adviceObject;
// 如果Advice是已經實作了MethodInterceptor接口的執行個體,就不用包裝了,
// 因為我們最終要生成的是Interceptor,現在包裝成Advisor隻是一個過程。
if (advice instanceof MethodInterceptor) {
// So well-known it doesn't even need an adapter.
return new DefaultPointcutAdvisor(advice);
}
// 循環對Advice進行判斷,如果是支援類型,就傳回包裝後的Advisor
for (AdvisorAdapter adapter : this.adapters) {
// Check that it is supported.
if (adapter.supportsAdvice(advice)) {
return new DefaultPointcutAdvisor(advice);
}
}
throw new UnknownAdviceTypeException(advice);
}
2 建立代理相關流程
buildAdvisors
方法及其子方法介紹完了,我們最後來介紹最
proxyFactory.getProxy(getProxyClassLoader())
方法的實作過程。
前在的一切都是準備資源,這個方法是利用資源生成代理的實作。我們先來看一看
getProxy
方法的内容。
這個方法裡隻有行代碼
createAopProxy().getProxy(classLoader)
。這行代碼中,首先調用了
createAopProxy
這個方法,
在
createAopProxy
方法裡又調用了
getAopProxyFactory().createAopProxy(this)
方法。
public Object getProxy(ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
我們看一下createAopProxy方法的具體内容。這個方法的實作是在DefaultAopProxyFactory類中。
這個方法的主要功能是,根據optimize、ProxyTargetClass等參數來決定生成Jdk動态代理,還是生成Cglib代理。
@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.");
}
if (targetClass.isInterface()) {
// 生成Jdk動态代理
return new JdkDynamicAopProxy(config);
}
// 成生Cglib代理
return new ObjenesisCglibAopProxy(config);
}
else {
// 生成Jdk動态代理
return new JdkDynamicAopProxy(config);
}
Jdk動态代理和Cglib代理的差別和實作方式在這裡就不具體講解了,請大家上網找一些資料。
Spring對這兩種代理做了包裝,包裝類分别是:
- JdkDynamicAopProxy
- ObjenesisCglibAopProxy類。
這兩個類的構造函數是AdvisedSupport,這個類保包含了 Spring AOP的配置和對配置的一些通路方法(例如:Advisor),還有AdvisorChainFactory對象。AdvisorChainFactory對象的功能主要是,根據在前面找到的合适的Advisor成生Interceptor,最後代理調用時實際上都是調用的Interceptor。
createAopProxy方法講完後,createAopProxy後面調用getProxy方法。這個方法不算難,主要是根據要生成代理的類型(Jdk動态代理和Cglib),把這兩種技術各自獨特的實作代理的過程給封裝了。比較複雜的邏輯是在,代理被調用時回調方法裡面。在回調方法裡面,及到了Intercceptor鍊(Interceptor包裝了Advisor)的調用,這個實作也挺巧妙的。
我們拿Jdk動态代理的回調來說明。了解Jdk動态代理的話都會知道,在實作Jdk動态代理功能,要實作InvocationHandler接口的invoke方法(這個方法是一個回調方法)。
被代理類中的方法被調用時,實際上是調用的invoke方法,我們看一看這個方法的實作。
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[]);
}
if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
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.
// 利用Adivsor,生成一個我們之前定義的Advice調用鍊。在調用被代理方法前後時,調用這個鍊。
// 在這個方法裡面,實際上調用advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice方法來實作了,
// 這個方法的作用我們在上面已經說過了,在這裡不再重複了。
// 這裡生成的鍊的對象全部都封裝成了MethodInterceptor。
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.
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
}
else {
// We need to create a method invocation...
// 這裡非常重要。生成一個方法調用的控制類,并調用proceed方法,進行鍊和被代理方法的調用
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.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);
}
}
}
上面的方法裡使用了ReflectiveMethodInvocation類,進行鍊和被代理方法的調用的控制。那麼它到底是怎麼進行控制的呢?
下面是ReflectiveMethodInvocation類Proceed方法:
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
// 首先,判斷是不是所有的interceptor(也可以想像成advisor)都被執行完了。
// 判斷的方法是看currentInterceptorIndex這個變量的值,增加到Interceptor總個數這個數值沒有,
// 如果到了,就執行被代理方法(invokeJoinpoint());如果沒到,就繼續執行Interceptor。
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - ) {
return invokeJoinpoint();
}
// 如果Interceptor沒有被全部執行完,就取出要執行的Interceptor,并執行。
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
// 如果Interceptor是PointCut類型
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
// 如果目前方法符合Interceptor的PointCut限制,就執行Interceptor
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
// 如果不符合,就跳過目前Interceptor,執行下一個Interceptor
// 這裡是遞歸執行proceed方法,currentInterceptorIndex的值一直在增加
// 當currentInterceptorIndex值達到了方法最大的界限的話,就會從遞歸最裡層的proceed方法一層層傳回來。
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
// 如果Interceptor不是PointCut類型,就直接執行Interceptor裡面的增強。
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);
}
}
看完上面的代碼,思考一下,可能會有兩個問題。
1,我們定義增加時,可以定義很多種,比如前置增加BeforeAdvice,後置增強等。在這個方法裡隻看到了調用Interceptor(也就是Advisor),是在哪裡控制這些增強的調用順序的呢?比如,先調用前置增強,再調用被代理方法,再調用後置增強等。
2,增強調用完後,是如何調用下一個增強的呢?上面的代碼中,調用完增強後,就傳回了。
上面問題的答案可以在MethodInterceptor的實作類裡找到,我們拿MethodBeforeAdviceInterceptor為例子。
從下面代碼可以看出來,當invoke方法被調用時,首先調用的是前置增強,然後再調用MethodInvocation的proceed方法,也就是我們上面介紹的proceed方法。這個MethodInvocation的引用,就是在ReflectiveMethodInvocation調用interceptor時,把自己傳了過來。在Interceptor裡調用proceed方法的意思是告訴MethodInvocation,
我(增強)執行完了,你繼續吧
,接下來是繼續執行其它增強,還是執行被代理方法,就由上面的ReflectiveMethodInvocation邏輯判斷了。
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;
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
return mi.proceed();
}
}
AfterReturningAdviceInterceptor的invoke方法代碼如下:
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
假設一共有兩個Interceptor
1, Interceptor1:前置增強
2, Interceptor2:後置增強
- 1, ReflectiveMethodInvocation:判斷Interceptor沒執行完,執行Interceptor1
- 2, Inerceptor1:執行前置增強,然後執行MethodInvocation的proceed方法。
- 3, ReflectiveMethodInvocation:判斷Interceptor沒執行完,執行Interceptor2
- 4, Interceptor2:執行MethodInvocation的proceed方法(後置增強還沒有執行)
- 5, ReflectiveMethodInvocation:判斷所有Interceptor都執行完了,執行目标方法。目标方法執行完後,回到Interceptor2調用proceed方法的地方。
- 6, Interceptor2:調用proceed傳回後,繼續調用後面的後置增強。後置增強執行完後,回到MethodInvocation調用Interceptor2的地方
- 7, ReflectiveMethodInvocation:調用Interceptor2完成傳回後,因為沒有其它(Intercetpor或目标方法)要執行,是以回到Interceptor1調用proceed方法的地方
- 8, Interceptor1:調用的proceed方法傳回後,因為沒有其它要執行的了,是以回到MethodInvocation調用Interceptor1的地方
- 9, ReflectiveMethodInvocation:調用Interceptor1完成傳回後,因為沒有其它(Intercetpor或目标方法)要執行,是以回到最初調用proceed方法的地方
ReflectiveMethodInvocation判斷還有Interceptor沒執行完,執行Interceptor1
Interceptor1執行完後,告訴ReflectiveMethodInvocation“我執行完了”,你繼續吧
ReflectiveMethodInvocation判斷還有Interceptor沒執行完,執行Interceptor2
Interceptor2執行完後,告訴ReflectiveMethodInvocation“我執行完了”,你繼續吧
ReflectiveMethodInvocation判斷Interceptor都執行完了,執行代理方法
回到Interceptor2調用執行完後,告訴ReflectiveMethodInvocation“我執行完了”,你繼續吧
在這種結構的控制下,不管在proceed裡調用Interceptor裡面的邏輯是前置增強處理,還是後置增強處理,都可以達到:
所有前置增強執行 -> 被代理方法執行 -> 所有的後置增強執行
的調用順序,是以這個設定還是挺巧妙的。
這種設計還有一個好處,因為這種設計把前置後置增強的調用順序控制,放到了各個增強用的Interceptor裡了,沒有放到proceed方法裡,是以當有新的增強類型出來的話,把調用順序控制放到新的增強的Interceptor裡就好了,不用修改現有的類,例如proceed方法。
為什麼執行代理Chain的時候,每個Chain裡的元素都要是MethodInterceptor類型的呢?
因為“Aop聯盟”定義了一套AOP的接口,而且還定義的接口的調用規則,而且還起草了AOP的一些元件和運作方式。
比如,定義了Interceptor Framework,Reflection,Metadata Handling(應該是注解處理),Class Loading Framework等。
拿我們遇到的接口舉例:
- Joinpoint:定義了proceed()等方法,proceed這個方法的作用是調用下一個interceptor。
- MethodInterceptor:定義了invoke(MethodInvocation invocation)方法。
-
MethodInvocation:實作了Joinpoint接口。根據定義來說,這個接口是一個“jointpoint(就是被攔截的方法/對象)”,什麼樣的JointPoint呢?
可以被攔截到的JointPoint。
看Spring的代碼,被攔截方法的調用和Interceptor Chain的調用都是在這裡控制的。是以可以看出Joinpoint接口是定義Advice,MethodInvocation接口是定義執行Advice的接口。在MethodInterceptor的Javadoc裡還寫了下面的說明和用例:
The user should implement the invoke(MethodInvocation) method to modify the original behavior. E.g. the following class implements a tracing interceptor (traces all the calls on the intercepted method(s)):
使用者需要實作 invoke(MethodInvocation) 方法來修改原來的行為。例如,下面類實作了一個tracing interceptor。
class TracingInterceptor implements MethodInterceptor {
Object invoke(MethodInvocation i) throws Throwable {
System.out.println("method "+i.getMethod()+" is called on "+
i.getThis()+" with args "+i.getArguments());
Object ret=i.proceed();
System.out.println("method "+i.getMethod()+" returns "+ret);
return ret;
}
}
看了一上面的代碼,是不是和上面說的MethodBeforeAdviceInterceptor還有AfterReturningAdviceInterceptor的實作方式幾乎一樣。這樣應該就可以了解Spring為什麼要這麼做了吧。
Aop聯盟的接口Javadoc如下,有興趣的可以看看。
http://aopalliance.sourceforge.net/doc/index.html