Springソースコード解析(五):Spring AOP取得Proxy
次に、SpringのAOPの関連コードのいくつかを見てみます.Proxyはどうやって入手できますか?まず、AOPとSpring AOPの基本概念を見てみましょう.
Advice:
リンクポイントで何をするかを通知します.Spingにおいて、彼は主にSpringが注入を呼び出すための追加的な行動を説明します.Springが提供する通知の種類は以下の通りです.
before advice、AfterReturningAdvice、ThrowAdvice、MethodBefore Advice、これらはすべてSpring AOPで定義されているインターフェースクラスで、具体的な動作はユーザープログラムが完成する必要があります.
Pointcut:
アドヴィスがどの接続点に適用すべきかを決定する点、すなわち追加の処理を挿入する必要がある場所の集合、例えば、あるアドヴィスをターゲットとする方法のセット.Spring pointcutは典型的には標示方法を意味しており、pointcutとして呼び出される方法のセットを選択することができ、Springは具体的な接点を提供してユーザに使用される.例えば、正規表現の接点JdkRegexpMethodPoint cutは、正規表現によって方法名をマッチングする.それはAbstractJdkRegexpMethodPointcutにおけるMethodMatchインターフェースの実現を使用してpointcut機能を完成する.
追加の動作設計(advice)と追加の動作挿入点の設計(pointcut)を完成すると、それらを結びつける対象が必要です.これは通知器-advisorです.どの通知をどこで適用すべきかを定義します.Advisorの実現は、Default Point Advisorの二つの属性adviceとpoint cutがあります.
続いて、ProxyFactoryBeanを通じて、私たちの代理先と各方面の行動を配置します.ProxyFactoryBeanにはinterceptorNamesがあります.定義された通知器-advisorを配置します.ここの名前はinterceptNamesといいますが、実際にはadvisorを配置するところです.eanはFactoryBeanです.ProxyFactoryBeanではgetObject()を通じて直接代理先を得ることができます.
Advice:
リンクポイントで何をするかを通知します.Spingにおいて、彼は主にSpringが注入を呼び出すための追加的な行動を説明します.Springが提供する通知の種類は以下の通りです.
before advice、AfterReturningAdvice、ThrowAdvice、MethodBefore Advice、これらはすべてSpring AOPで定義されているインターフェースクラスで、具体的な動作はユーザープログラムが完成する必要があります.
Pointcut:
アドヴィスがどの接続点に適用すべきかを決定する点、すなわち追加の処理を挿入する必要がある場所の集合、例えば、あるアドヴィスをターゲットとする方法のセット.Spring pointcutは典型的には標示方法を意味しており、pointcutとして呼び出される方法のセットを選択することができ、Springは具体的な接点を提供してユーザに使用される.例えば、正規表現の接点JdkRegexpMethodPoint cutは、正規表現によって方法名をマッチングする.それはAbstractJdkRegexpMethodPointcutにおけるMethodMatchインターフェースの実現を使用してpointcut機能を完成する.
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;
}
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;
}
JDKRegexpMethodPoint cutではJDKの正規表現マッチングによってpointcutの最終的な決定を完了します.protected boolean matches(String pattern, int patternIndex) {
Matcher matcher = this.compiledPatterns[patternIndex].matcher(pattern);
return matcher.matches();
}
protected boolean matches(String pattern, int patternIndex) {
Matcher matcher = this.compiledPatterns[patternIndex].matcher(pattern);
return matcher.matches();
}
アドバイザー:追加の動作設計(advice)と追加の動作挿入点の設計(pointcut)を完成すると、それらを結びつける対象が必要です.これは通知器-advisorです.どの通知をどこで適用すべきかを定義します.Advisorの実現は、Default Point Advisorの二つの属性adviceとpoint cutがあります.
続いて、ProxyFactoryBeanを通じて、私たちの代理先と各方面の行動を配置します.ProxyFactoryBeanにはinterceptorNamesがあります.定義された通知器-advisorを配置します.ここの名前はinterceptNamesといいますが、実際にはadvisorを配置するところです.eanはFactoryBeanです.ProxyFactoryBeanではgetObject()を通じて直接代理先を得ることができます.
public Object getObject() throws BeansException {
//
initializeAdvisorChain();
if (isSingleton()) {
// Proxy
return getSingletonInstance();
}
else {
.......
// Prototype Proxy
return newPrototypeInstance();
}
}
public Object getObject() throws BeansException {
//
initializeAdvisorChain();
if (isSingleton()) {
// Proxy
return getSingletonInstance();
}
else {
.......
// Prototype Proxy
return newPrototypeInstance();
}
}
どのようにして単品の代理対象を生成するかを見てみます.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);
}
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の父はAdviedSupportであり、SpringはAopProxyインターフェースを使ってAOPエージェントの実現とフレームの他の部分を分離しています.Advied Supportではこのような方式でAopProxyを取得します.もちろんここではAopProxyFactoryの助けが必要です.希望のエージェント:protected synchronized AopProxy createAopProxy() {
if (!this.isActive) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
protected synchronized AopProxy createAopProxy() {
if (!this.isActive) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
ProxyConfigで使用するAopProxyFactoryを定義しました.// DefaultAopProxyFactory Spring AopProxy ,
// JDK Cglib 。
private transient AopProxyFactory aopProxyFactory = new DefaultAopProxyFactory();
// DefaultAopProxyFactory Spring AopProxy ,
// JDK Cglib 。
private transient AopProxyFactory aopProxyFactory = new DefaultAopProxyFactory();
この中でDefault AopProxyFactoryではAopProxyが生成されます.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);
}
}
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類とCglib 2 AopProxy両方が実現するのはAopProxyのインターフェースです.JdkDynamicAopProxy実現において、Proxyはどのように生成されたのかを見ることができます.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);
}
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を包装した後、Proxy FactoryBeanを通じてその方法に対する呼び出しを受けてProxyにブロックされました.Proxy FactoryBeanのgetObject()方法で得られたのは、実はProxyです.私たちのtargetオブジェクトはすでにパッケージされています.Proxy FactoryBeanという工場benにとって、その生産の対象はパッケージの対象となります.