Spring技術內幕:Spring AOP的實現原理(三)
生成SingleTon代理對象在getSingleTonInstance方法中完畢,這種方法時ProxyFactoryBean生成AopProxy對象的入口。代理對象會封裝對target目標對象的調用。也就是說針對target對象的方法調用行為會被這裏生成的代理對象所攔截。
詳細的生成過程是首先讀取ProxyFactoryBean配置,為生成代理對象做好準備。Spring通過AopProxy類來詳細生成代理對象。對於getSingleTonInstance方法中生成代理對象的步驟例如以下:
/**
* 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.
// 依據AOP框架來推斷須要代理的接口
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);
// 這裏會使用ProxyFactoryBean來生成須要的proxy對象
this.singletonInstance = getProxy(createAopProxy());
}
return this.singletonInstance;
}
/**
* Return the proxy object to expose.
* <p>The default implementation uses a [email protected] getProxy} call with
* the factory‘s bean class loader. Can be overridden to specify a
* custom class loader.
* @param aopProxy the prepared AopProxy instance to get the proxy from
* @return the proxy object to expose
* @see AopProxy#getProxy(ClassLoader)
*/
protected Object getProxy(AopProxy aopProxy) {
return aopProxy.getProxy(this.proxyClassLoader);
}
這裏出現了AopProxy對象類型,Spring利用AOPProxy接口類把AOP代理對象的實現與框架其它部分有效隔離開來。
AopProxy接口有兩個子類實現,一個Cglib2AopProxy,還有一個是JdkDynamicProxy。
詳細代理對象的生成是在ProxyFactoryBean的基類AdvisedSupport中實現,借助AopProxyFactory完畢,這個對象要麽從JDK中生成,要麽借助CGLIB獲得。
以下看看ProxyCreatorSupport中是怎樣生成代理對象的。
/**
* Subclasses should call this to get a new AOP proxy. They should <b>not</b>
* create an AOP proxy with [email protected] this} as an argument.
*/
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
// 通過AopProxyFactory取得AopProxy,這個AopProxyFactory是在初始化函數中定義的,使用的是DefaultAopProxyFactory
return getAopProxyFactory().createAopProxy(this);
}
AopProxy代理對象的生成有兩種方式。假設目標對象是接口類使用JDK來生成,否則Spring會使用CGLIB來生成目標的代理對象。
以下看看在DefaultAopProxyFactory是怎樣生成AopProxy目標代理對象的:
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);
}
return CglibProxyFactory.createCglibProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
在AopProxy代理對象的生成過程中。首先要從AdviseSupport對象中取得配置的目標對象。AOP完畢的是切面應用對目標應用對象的增強。假設這裏沒有配置目標對象會直接拋出異常。一般而言,默認方式是使用JDK來產生AopProxy代理對象,但假設配置的目標對象不是接口類的實現,會使用CGLIB來產生AopProxy代理對象;在使用CGLIB來產生AopProxy代理對象時,由於CGLIB是第三方類庫,本身不在JDK基類庫中,全部須要在classPath中正確配置,以便可以載入和利用。在Spring中。使用JDK和CGLIB來生成AopProxy代理對象的工作,是由JdkDynamicAopProxy和CglibProxyFactory來完畢。
4、JDK生成AopProxy對象(接口實現類)
通過上面我們已經知道生成AopProxy對象有兩種方式,以下看下類圖:
我們先看下JdkDynamicAopProxy是怎樣生成AopProxy對象的:
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// 調用JDK生成Proxy
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
5、CGLIB生成AopProxy對象(非接口實現類)
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating CGLIB 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 (ClassUtils.isCglibProxyClass(rootClass)) {
proxySuperClass = rootClass.getSuperclass();
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
// Validate the class, writing log messages as necessary.
validateClassIfNecessary(proxySuperClass);
// Configure CGLIB Enhancer...
// 來自advised的IOC配置。比方使用AOP的DynamicAdvisedInterceptor
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new MemorySafeUndeclaredThrowableStrategy(UndeclaredThrowableException.class));
enhancer.setInterceptDuringConstruction(false);
// 通過設置DynamicAdvisedInterceptor攔截器來完畢AOP功能,getCallBacks方法例如以下:
// Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised)
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
enhancer.setCallbacks(callbacks);
// 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() failed
throw new AopConfigException("Unexpected AOP exception", ex);
}
}
四、Spring AOP攔截器調用的實現
1、設計原理
在Spring AOP通過JDK的Proxy方式或CGLIB方式生成代理對象的時候,相關的攔截器已經配置到代理對象中去了,攔截器在代理對象中起作用是通過對這些方法的回調來完畢的。
假設使用JDK的Proxy來生成代理對象,那麽須要InvocationHandler來設置攔截器回調,而假設使用CGLIB來生成代理對象。通過DynamicAdvisedInterceptor來完畢回調。
2、JdkDynamicAopProxy的invoke攔截
在JDKDynamicAopProxy生成代理對象時,他的AopProxy代理對象生成調用:
Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
this指的是InvocationHandler對象,InvocationHandler是JDK定義反射類的一個接口。這個接口定義了invoke方法,此方法為回調方法。
通過invoke的詳細實現。來完畢對目標對象方法調用的攔截器或者功能增強工作。
在這種方法中。包括一個完整的攔截器鏈對目標對象的攔截過程。比方獲取攔截器鏈中的攔截器進行配置。逐個執行攔截器鏈裏的攔截器增強,知道最後的目標對象方法的執行。以下看下invoke的源代碼
/**
* Implementation of [email protected] InvocationHandler.invoke}.
* <p>Callers will see exactly the exception thrown by the target,
* unless a hook method throws an exception.
*/
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[0]);
}
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.
// 獲得定義好的攔截器
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.
// 假設沒有攔截器直接調用target的相應方法
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...
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);
}
}
}
3、CglibAopProxy的intercept攔截器
使用CglibAopProxy生成AopProxy對象時候。對於AOP攔截器調用。回調的是DynamicAdvisedInterceptor對象生成的。
回調的方法時intercept,以下看看回調方法的源代碼:
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Class<?> targetClass = null;
Object target = null;
try {
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 = getTarget();
if (target != null) {
targetClass = target.getClass();
}
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// 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...
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null) {
releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
Spring技術內幕:Spring AOP的實現原理(三)