Springテクノロジーインサイダー3 Spring AOPの実現
30884 ワード
Aspectj:ソースコードとバイトコードレベルの編機で、ユーザーはJavaとは異なる新しい言語を使用する必要があります.AspectWerkz:AOPフレームワークは、バイトコードダイナミック編機とXML構成を使用します.JBoss-AOP:インターセプタとメタデータに基づくAOPフレームワークは、JBossアプリケーションサーバ上で実行されます.およびAOPで使用されるいくつかの関連技術実装.BCEL:javaバイトコード操作クラスライブラリ.Javassist:Javaバイトコード操作クラスライブラリ、JBossのサブプロジェクト.3つの織り込み方式:コンパイル期間織り込み、クラスロード期間織り込み、運転期間織り込み.コンパイル期間織り込みとは、Javaコンパイル期間に特殊なコンパイラを採用し、切面をJavaクラスに織り込むことである.一方、クラスロード期間織り込みとは、特殊なクラスローダを通じて、クラスバイトコードがJVMにロードされたときに、切断面を織り込むことを指す.ランタイム織り込みは、CGLibツールまたはJDKダイナミックエージェントを使用して面を切り取る織り込みです.AspectJはコンパイル期織り込みとクラスロード期織り込みの方式を採用して切面を織り込み、言語級のAOP実現であり、完備したAOPサポートを提供した.AspectJ言語でフェースを定義し、コンパイル期間またはクラスロード期間にJavaクラスにフェースを織り込みます. Spring AOPの実装は、他の特性の実装と同様に、Spring自体が提供するAOP実装を使用できるほか、業界の優れたAOPソリューションAspectjをカプセル化して使用を提供しています.Advice通知:Adviceは接続点で何をするかを定義し、切断面の強化に織り込みインタフェースを提供します.AdviceはAOP連盟が定義したインタフェースであり、org.aopalliance.aop.Adviceである.Spring AOP実装では、この統合インタフェースを使用し、このインタフェースを通じて、AOPカットに織り込み機能を強化するために多くの細分化と拡張を行い、例えば、BeforeAdvice、AfterAdvice、ThrowsAdviceなどのより具体的な通知タイプを提供した.BeforeAdviceはまたサブインタフェースMethodBeforeAdviceを進化させ、beforeには具体的な意味は言うまでもない方法がある.AfterAdvice演算子インタフェースAfterReturningAdviceには、afterReturningメソッドがあります.ThrowsAdviceはインタフェースメソッドを指定していませんが、AfterAdviceから継承されていることがわかります.Pointcut接点:Pointcutは、強化する必要があるメソッドの集合を定義します.Pointcutはメソッド呼び出しを強化する必要があるかどうかを判断するためにMethodMatcherを返します.いずれかの実装JdkRegexpMethodPointcutは,正規表現によってメソッド名のマッチングを完了する機能を果たす.さらにJdkRegexpMethodPointcutはMethodMatcherインタフェースも実現している.JdkRegexpMethodPointcutでは、AbstractRegexpMethodPointcutにおける抽象メソッドmatchesが実装され、jdkの正規表現でマッチングが完了します.Advisor通知器:ターゲットの接面設計Adviceと注目点設計Pointcutを完了した後、オブジェクトを結合する必要があります.DefaultPointcutAdvisor-public DefaultPointcutAdvisor(Pointcut pointcut,Advice advice){this.pointcut=pointcut;setAdvice;クラスにはTruePointcutの単一のデフォルト値があり、trueを返します.上記のいくつかのクラスの実装は、基本的には「データ形式の定義」に属しているため、非常に簡単です.AOP紹介 通知(Advice):通知は、フェースが何であるか、およびいつ使用されるかを定義します.切断面で完了する作業を説明するだけでなく、通知はこの作業をいつ実行するかの問題を解決します. 接続点(Joinpoint):接続点は、プログラムの実行中に切断面を挿入できる点です.この点は、メソッドが呼び出されたとき、例外が投げ出されたとき、フィールドが編集されたときでもよい.フェースコードは、これらの点をプログラムの一般的なプロセスに挿入することで、新しい動作を追加することができます. 切り込みポイント(Poincut):切り込みポイントは、切面通知の接続ポイントの範囲を狭めることができます.通知がうどんの「何」と「いつ」を定義している場合、切り込みポイントは「どこ」を定義します. 接面(Aspect):接面は通知と切り込み点の組合せです. 導入(Introduction):導入により、既存のクラスに新しいメソッドまたは属性を追加できます. ターゲット(Target):通知されたオブジェクト. プロキシ(Proxy):ターゲットオブジェクトに通知を適用した後に作成されるオブジェクトです. 織り込み(Weaving):ターゲットオブジェクトにフェースを適用して新しいエージェントオブジェクトを作成するプロセスです.コンパイル時、クラスロード時、実行時.
Spring AOP実装で使用されるコアテクノロジーは動的エージェントである.JDKの動的プロキシ特性により、Java Reflection APIによって実行される任意のJavaオブジェクトのプロキシオブジェクトを作成できます.逆にSpring AOPはApsectJを統合している.このエージェントオブジェクトは、JDKのproxyを使用してもよいし、サードパーティのクラスジェネレータCGLIBを使用してもよい.インタフェースorg.springframework.beans.factory.FactoryBean:beanの作成のためのファクトリとして、T getObject()、ClassgetobjectType()、boolean isSingleton()から、beanとして作成したエージェントオブジェクトとして返すことができることがわかります.まずFactoryBeanは私たちのメインインタフェースで、この定義は私たちが必要とする結果ですが、以下はこのインタフェースをめぐってリソースや「アルゴリズム」などの操作を含むいくつかの列インタフェースを定義し、最終的に私たちのインタフェースが望んでいるものを得ます.リソース関連Aware-----インタフェースorg.springframework.beans.factory.Aware:このインタフェースはメソッドを定義していませんが、スーパークラスインタフェースとして存在します.Marker superinterface indicating that a bean is eligible to be notified by the Spring container of a particular framework object through a callback-style method. インタフェースorg.springframework.beans.factory.BeanFactoryAware:Awareを継承する方法void setBeanFactory(BeanFactory beanFactory)は、BeanFactoryのコールバック注入を定義します.インタフェースorg.springframework.beans.factory.BeanClassLoaderAware:Awareメソッドvoid setBeanClassLoader(ClassLoader classLoader)を継承し、ClassLoaderのコールバック注入を定義します.インタフェースorg.springframework.aop.TargetClassAware:Awareから継承されていません.上のAwareはbean関連です.これはaop関連です.メソッドを定義するClassgetTargetClass()は、ターゲットクラスが取得します.私たちが構成している ------------------------------------------------------------------------------インタフェースorg.springframework.aop.framework.Advised:名前と同じように、Advisedがやりたいリソース管理です.org.springframework.aop.framework.ProxyConfig:一部のIDの保存、一貫性の保証.org.springframework.aop.framework.AdvisedSupport:各種構成リソースの管理を含むAdvisedの実装サポートクラス.このクラスを呼び出すパラメータ命名定義のAdvisedSupport configから、このクラスがリソースのスナップショットクラスであることがわかります.org.springframework.aop.framework.ProxyCreatorSupport:Base class for proxy factories.Provides convenient access to a configurable AopProxyFactory.真の作成はAopProxyの2つで実現され、AopProxyの実現に対する判断提供はAopProxyFactoryであり、本クラスはAopProxyFactoryの提供である(AopProxyの実現ではなく提供である)./** * Create a new ProxyCreatorSupport instance.*/public ProxyCreatorSupport(){this.aopProxyFactory=new DefaultAopProxyFactory()最終的な作成:AopProxy----------------------インタフェースorg.springframework.aop.framework.AopProxy:Delegate interface for a configured AOP proxy,allowing for the creation of actual proxy objects. 2つのメソッドObject getProxy()、Object getProxy(ClassLoader classLoader).AopProxyの2つの重要な実装Cglib 2 AopProxy、JdkDynamicAopProxyは、私たちが最終的にAOPを生成した後のオブジェクトの場所でもあります.インタフェースorg.springframework.aop.framework.AopProxyFactory:AopProxyリソースを作成する必要がある場所を整理し、どのAopProxy実装タイプを返すかを判断する場所でもあります.org.springframework.aop.framework.DefaultAopProxyFactory:AopProxyFactoryの唯一のデフォルト実装.今後,AopProxyの下位実装方式を単独で取り入れたいなら,ここから着手することができる.org.springframework.aop.framework.ProxyFactoryBean:最終出口
設計原理:ProxyFactoryBeanでは、プライマリエージェントオブジェクトの生成プロセスがカプセル化されています.この生成過程では,JDKのProxyとCGLIBの2つの生成方式を用いることができる.AOPアプリケーションを完了するクラス、例えばAspectJProxyFactory、ProxyFactory、ProxyFactoryBeanは、同じクラスの継承システムの下で、ProxyConfig、AdvisedSupport、ProxyCreatorSupportのサブクラスです.共通ベースクラスとしてProxyConfigは、ProxyFactoryBeanのようなサブクラスに構成属性を提供するデータベースクラスと見なすことができる.別のベースクラスAdvisedSupportの実装では、AOPの通知と通知器に関する操作がカプセル化されており、これらの操作は異なるAOPのエージェントオブジェクトの生成に対して同じであるが、具体的なAOPエージェントオブジェクトの作成に対して、AdvisedSupportは彼を彼のサブクラスたちに渡して完成する.ProxyCreatorSupportでは、そのサブクラスがAOPエージェントオブジェクトを作成する補助クラスと見なすことができます.ProxyFactoryBeanの使用: プロキシ(Proxy):ターゲットオブジェクトに通知を適用して作成されるオブジェクトです. ProxyFactoryBeanエージェントを使用してフェースされたオブジェクト.
これらのcallbackコールバックでは、AOPに対して実装されており、DynamicAdvisedInterceptorによって行われ、コールバックエントリはinterceptメソッドである.
AOPの実装部分はインフラストラクチャ設備とAOP運転支援の2つの部分から構成されていると見なすことができ,ここでのAopProxyエージェントの生成は,AOPインフラストラクチャの建設過程と見なすことができる.
この準備プロセスにより、エージェントオブジェクト、ブロッカーなどの呼び出される部門を準備し、AOP実行中にこれらのインフラストラクチャの使用を待つ.
アプリケーション出発AOPアプリケーションについては、AOPフレームワークの実行とAOPインフラストラクチャの使用に関連します.
これらの動的な動作部分は,前述したブロッキングコール入口から始まり,原理は種々の実装スキームである.
Spring AOP実装で使用されるコアテクノロジーは動的エージェントである.JDKの動的プロキシ特性により、Java Reflection APIによって実行される任意のJavaオブジェクトのプロキシオブジェクトを作成できます.逆にSpring AOPはApsectJを統合している.このエージェントオブジェクトは、JDKのproxyを使用してもよいし、サードパーティのクラスジェネレータCGLIBを使用してもよい.インタフェースorg.springframework.beans.factory.FactoryBean
設計原理:ProxyFactoryBeanでは、プライマリエージェントオブジェクトの生成プロセスがカプセル化されています.この生成過程では,JDKのProxyとCGLIBの2つの生成方式を用いることができる.AOPアプリケーションを完了するクラス、例えばAspectJProxyFactory、ProxyFactory、ProxyFactoryBeanは、同じクラスの継承システムの下で、ProxyConfig、AdvisedSupport、ProxyCreatorSupportのサブクラスです.共通ベースクラスとしてProxyConfigは、ProxyFactoryBeanのようなサブクラスに構成属性を提供するデータベースクラスと見なすことができる.別のベースクラスAdvisedSupportの実装では、AOPの通知と通知器に関する操作がカプセル化されており、これらの操作は異なるAOPのエージェントオブジェクトの生成に対して同じであるが、具体的なAOPエージェントオブジェクトの作成に対して、AdvisedSupportは彼を彼のサブクラスたちに渡して完成する.ProxyCreatorSupportでは、そのサブクラスがAOPエージェントオブジェクトを作成する補助クラスと見なすことができます.ProxyFactoryBeanの使用: プロキシ(Proxy):ターゲットオブジェクトに通知を適用して作成されるオブジェクトです. ProxyFactoryBeanエージェントを使用してフェースされたオブジェクト.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="audience" class="cn.partner4java.springidol.Audience"/>
<!-- (Advice): -->
<bean id="advice1" class="cn.partner4java.springidol.AudienceAdvice">
<property name="audience" ref="audience"></property>
</bean>
<bean id="advice2" class="cn.partner4java.springidol.AudienceAroundAdvice">
<property name="audience" ref="audience"></property>
</bean>
<!-- (Poincut): -->
<bean id="performancePointcut1" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="pattern" value=".*perform"></property>
</bean>
<!-- AspectJ -->
<bean id="performancePointcut2" class="org.springframework.aop.aspectj.AspectJExpressionPointcut">
<property name="expression" value="execution(* Performer+.perform(..))"></property>
</bean>
<!-- (Aspect): ( )-->
<bean id="audienceAdvisor1" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="advice" ref="advice1"></property>
<property name="pointcut" ref="performancePointcut1"></property>
</bean>
<bean id="audienceAdvisor2" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="advice1"></property>
<property name="pattern" value=".*perform"></property>
</bean>
<!-- ProxyFactoryBean -->
<bean id="performer" class="cn.partner4java.springidol.PerformerBean"></bean>
<bean id="duke" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="performer"></property>
<property name="interceptorNames" value="audienceAdvisor1"></property>
<property name="proxyInterfaces" value="cn.partner4java.springidol.Performer"></property>
</bean>
</beans>
:
package cn.partner4java.springidol;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class HelloWorld {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"/META-INF/spring/springido.xml");
Performer performer = (Performer) ctx.getBean("duke");
performer.perform();
}
}
ProxyFactoryBean AopProxy :
/**
* Return a proxy. Invoked when clients obtain beans from this factory bean.
* Create an instance of the AOP proxy to be returned by this factory.
* The instance will be cached for a singleton, and create on each call to
* <code>getObject()</code> for a proxy.
* @return a fresh AOP proxy reflecting the current state of this factory
*/
public Object getObject() throws BeansException {
//
initializeAdvisorChain();
// singleton prototype , proxy
if (isSingleton()) {
return getSingletonInstance();
}
else {
if (this.targetName == null) {
logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
"Enable prototype proxies by setting the 'targetName' property.");
}
return newPrototypeInstance();
}
}
ProxyFactoryBean AOP JDK CGLIB Proxy 。
FactoryBean , getObject 。
/**
* Create the advisor (interceptor) chain. Aadvisors that are sourced
* from a BeanFactory will be refreshed each time a new prototype instance
* is added. Interceptors added programmatically through the factory API
* are unaffected by such changes.
*/
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
if (this.advisorChainInitialized) {
return;
}
if (!ObjectUtils.isEmpty(this.interceptorNames)) {
if (this.beanFactory == null) {
throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
"- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
}
// Globals can't be last unless we specified a targetSource using the property...
if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
throw new AopConfigException("Target required after globals");
}
// Advisor , interceptorNames
// Materialize interceptor chain from bean names.
for (String name : this.interceptorNames) {
if (logger.isTraceEnabled()) {
logger.trace("Configuring advisor or advice '" + name + "'");
}
if (name.endsWith(GLOBAL_SUFFIX)) {
if (!(this.beanFactory instanceof ListableBeanFactory)) {
throw new AopConfigException(
"Can only use global advisors or interceptors with a ListableBeanFactory");
}
addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
}
else {
// , advice, Bean singleton prototype
// If we get here, we need to add a named interceptor.
// We must check if it's a singleton or prototype.
Object advice;
if (this.singleton || this.beanFactory.isSingleton(name)) {
// Add the real Advisor/Advice to the chain.
advice = this.beanFactory.getBean(name);
}
else {
// It's a prototype Advice or Advisor: replace with a prototype.
// Avoid unnecessary creation of prototype bean just for advisor chain initialization.
advice = new PrototypePlaceholderAdvisor(name);
}
addAdvisorOnChainCreation(advice, name);
}
}
}
this.advisorChainInitialized = true;
}
Singleton getSingletonInstance() , ProxyFactoryBean AopProxy 。
/**
* 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()) {
// AOP
// 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);
// ProxyFactory Proxy
this.singletonInstance = getProxy(createAopProxy());
}
return this.singletonInstance;
}
/**
* Return the proxy object to expose.
* <p>The default implementation uses a <code>getProxy</code> 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)
*/
// createAopProxy AopProxy
protected Object getProxy(AopProxy aopProxy) {
return aopProxy.getProxy(this.proxyClassLoader);
}
AOP , ,Cglib2AopProxy JdkDynamicAopProxy。
, ProxyFactoryBean AdvisedSupport AopProxyFactory 。
ProxyCreatorSupport:
/**
* Subclasses should call this to get a new AOP proxy. They should <b>not</b>
* create an AOP proxy with <code>this</code> as an argument.
*/
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
// AopProxyFactory AopProxy, AopProxyFactory , DefaultAopProxyFactory
return getAopProxyFactory().createAopProxy(this);
}
, Spring CglibProxyFactory JdkDynamicAopProxy 。
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.");
}
// targetClass , JDK Proxy
if (targetClass.isInterface()) {
return new JdkDynamicAopProxy(config);
}
if (!cglibAvailable) {
throw new AopConfigException(
"Cannot proxy target class because CGLIB2 is not available. " +
"Add CGLIB to the class path or specify proxy interfaces.");
}
// Proxy, CGLIB
return CglibProxyFactory.createCglibProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
JDK AopProxy :
JdkDynamicAopProxy--getProxy
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);
//
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
CGLIB AopProxy :
Cglib2AopProxy--getProxy
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating CGLIB2 proxy: target source is " + this.advised.getTargetSource());
}
// advised IoC target
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);
//
// CGLIB Enhancer, Enhancer CGLIB
// Configure CGLIB Enhancer...
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
// Enhancer , ,
// advised IoC , AOP DynamicAdvisedInterceptor
enhancer.setSuperclass(proxySuperClass);
enhancer.setStrategy(new UndeclaredThrowableStrategy(UndeclaredThrowableException.class));
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setInterceptDuringConstruction(false);
Callback[] callbacks = getCallbacks(rootClass);
enhancer.setCallbacks(callbacks);
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
Class[] types = new Class[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
enhancer.setCallbackTypes(types);
// Enhancer
// 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);
}
}
これらのcallbackコールバックでは、AOPに対して実装されており、DynamicAdvisedInterceptorによって行われ、コールバックエントリはinterceptメソッドである.
AOPの実装部分はインフラストラクチャ設備とAOP運転支援の2つの部分から構成されていると見なすことができ,ここでのAopProxyエージェントの生成は,AOPインフラストラクチャの建設過程と見なすことができる.
この準備プロセスにより、エージェントオブジェクト、ブロッカーなどの呼び出される部門を準備し、AOP実行中にこれらのインフラストラクチャの使用を待つ.
アプリケーション出発AOPアプリケーションについては、AOPフレームワークの実行とAOPインフラストラクチャの使用に関連します.
これらの動的な動作部分は,前述したブロッキングコール入口から始まり,原理は種々の実装スキームである.
Spring AOP JDK Proxy CGLIB , , 。
AopProxy AOP :
JdkDynamicAopProxy invoke :
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable :
/**
* Implementation of <code>InvocationHandler.invoke</code>.
* <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)) {
// Object :equals
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// Object :hashCode
// 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);
// , target
// 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);
}
// ,
// ReflectiveMethodInvocation
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.
if (retVal != null && retVal == target && method.getReturnType().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;
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
Cglib2AopProxy intercept :
final class Cglib2AopProxy implements AopProxy, Serializable:
(private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable :)
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 <code>null</code>. 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();
}
// advised AOP
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// AOP , target
// 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 {
// CglibMethodInvocation advice
// We need to create a method invocation...
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = massageReturnTypeIfNecessary(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null) {
releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
:
, 。 JDK , AopUtils.invokeJoinpointUsingReflection(target, method, args) 。
/**
* Invoke the given target via reflection, as part of an AOP method invocation.
* @param target the target object
* @param method the method to invoke
* @param args the arguments for the method
* @return the invocation result, if any
* @throws Throwable if thrown by the target method
* @throws org.springframework.aop.AopInvocationException in case of a reflection error
*/
public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)
throws Throwable {
// target
// Use reflection to invoke the method.
try {
ReflectionUtils.makeAccessible(method);
return method.invoke(target, args);
}
catch (InvocationTargetException ex) {
// Invoked method threw a checked exception.
// We must rethrow it. The client won't see the interceptor.
throw ex.getTargetException();
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
method + "] on target [" + target + "]", ex);
}
catch (IllegalAccessException ex) {
throw new AopInvocationException("Could not access method [" + method + "]", ex);
}
}
AOP :
AOP :org.springframework.aop.framework.ReflectiveMethodInvocation--proceed()
// , , 。
public Object proceed() throws Throwable {
// -1 ,
// , target ,
// , AopUtils.invokeJoinpointUsingReflection
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// , , Pointcut ,
// advice
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
//
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// , process ,
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// interceptor, interceptor
// 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);
}
}
:
AopProxy , ReflectiveMethodInvocation proceed 。
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
interceptorOrInterceptionAdvice , 。
JdkDynamicAopProxy invoke
// Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
:
AdvisedSupport
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) {
// methodCache, map cache, , DefaultAdvisorChainFactory
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
return cached;
}
advisorChainFactory , 。
DefaultAdvisorChainFactory , 。
ProxyFactoryBean getObject advisor , XML advisor 。
Object advice;
// prototype
if (this.singleton || this.beanFactory.isSingleton(name)) {
// advice , beanFactory , interceptor BeanFactory, getBean 。
advice = this.beanFactory.getBean(name);
}
else {
// It's a prototype Advice or Advisor: replace with a prototype.
// Avoid unnecessary creation of prototype bean just for advisor chain initialization.
advice = new PrototypePlaceholderAdvisor(name);
}
addAdvisorOnChainCreation(advice, name);
advisor IoC 。
DefaultListableBeanFactory AbstractAutowireCapableBeanFactory initializeBean , bean BeanFactoryAware, 。
Advice :