Spring深さ解析-13、AOP作成エージェントオブジェクトの2つの方法
5056 ワード
AOPはどのようにプロキシオブジェクトを作成する方式を選択しますか?
AOPがどのように代理対象を作成するかについては、DefaultAopProxyFactoryのcreateAopProxyを見る必要があります.
今日は主に二つの方法を研究して、代理の対象を作る過程です.
JDKエージェント
JdkDynamicAopProxy
CGLOIBエージェント
CglibAopProxy:
CGLOIBはそんなに牛に強いです.なぜJDK代理が必要ですか?
CGLOIBは、インターフェースが実現されていないクラスエージェントに対して、同時にプロキシオブジェクトを実行する時の性能はJDKより高いが、プロキシオブジェクトを作成する時の性能はJDKに及ばない.
したがって、頻繁にプロキシオブジェクトを作成する必要がないシーンでは、CGLOIBを使用することができる.頻繁にプロキシオブジェクトを作成する必要がある場面では、JDKプロキシを使用するのがベストです.
JDKエージェントのinvokeとCGLOIBのinterceptについては後で詳しく話します.
AOPがどのように代理対象を作成するかについては、DefaultAopProxyFactoryのcreateAopProxyを見る必要があります.
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// ( , )
// ,
// springProxy
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.");
}
// JDK Proxy, JDK
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// CGLIB
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
どのように選択するかについてのポイントは、ターゲットクラスはあくまでもインターフェースではなく、インターフェースであれば、JDKエージェントを使用します.そうでなければ、CGLOIBエージェントです.今日は主に二つの方法を研究して、代理の対象を作る過程です.
JDKエージェント
JdkDynamicAopProxy
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
// , 、 ProxyConfig SpringProxy,Advised
Class>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// JDK , this, JdkDynamicAopProxy,
// JdkDynamicAopProxy InvocationHandler
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
JDKエージェントは、プロキシオブジェクトを生成するプロセスが簡単である.1、ProxyConfig内の配置情報に基づいて、プロキシが必要なインターフェース配列2、着信型キャリア、インターフェースおよびthisを取得してプロキシオブジェクトを作成する.これはJdkDynamicAopProxyがInvocationHandlerを実現したためである.このため、代理先のinvokeは、JdkDynamicAopProxyのinvokeに呼び出されて強化されました.CGLOIBエージェント
CglibAopProxy:
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating CGLIB proxy: " + 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, classLoader);
// Configure CGLIB Enhancer...
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 ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
//
Callback[] callbacks = getCallbacks(rootClass);
Class>[] types = new Class>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// Generate the proxy class and create a proxy instance.
//
return createProxyClassAndInstance(enhancer, callbacks);
}
catch (CodeGenerationException | IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
": Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (Throwable ex) {
// TargetSource.getTarget() failed
throw new AopConfigException("Unexpected AOP exception", ex);
}
}
CGLOIBはJDK代理牛より強いところにあります.彼は代理でインターフェースの種類を実現しただけでなく、代理でインターフェースの種類を実現できなくてもいいです.彼はコールバックの設定はコールバックの設定によって、calbackは一連のMethodInterceptorのサブクラスです.つまり、ブロックを呼び出して、プロキシを強化するのはMethodIntercepterのinterptを通じて実現する方法です.CGLOIBはそんなに牛に強いです.なぜJDK代理が必要ですか?
CGLOIBは、インターフェースが実現されていないクラスエージェントに対して、同時にプロキシオブジェクトを実行する時の性能はJDKより高いが、プロキシオブジェクトを作成する時の性能はJDKに及ばない.
したがって、頻繁にプロキシオブジェクトを作成する必要がないシーンでは、CGLOIBを使用することができる.頻繁にプロキシオブジェクトを作成する必要がある場面では、JDKプロキシを使用するのがベストです.
JDKエージェントのinvokeとCGLOIBのinterceptについては後で詳しく話します.