ネストしたAspect
ひがさんの日記のまねをしてみました.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="dateTarget" class="java.util.Date"> <constructor-arg type="long"><value>0</value></constructor-arg> </bean> <bean id="date" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target"><ref bean="dateTarget"/></property> <property name="interceptorNames"><value>advisor</value></property> </bean> <bean id="advisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"> <property name="mappedNames"> <list> <value>hashCode</value> <value>getTime</value> </list> </property> <property name="advice"><ref bean="interceptor"/></property> </bean> <bean id="interceptor" class="org.springframework.aop.interceptor.DebugInterceptor"> </bean> </beans>
この時点でいやになりますね.S2に比べてなんて煩雑なんだろう.
ともかく,これでDate#hashCode()
を呼び出すと...
Debug interceptor: count=1 invocation=[Invocation: method=[public int java.util.Date.hashCode()] args=[Ljava.lang.Object;@b7b3f9] target is of class java.util.Date] Debug interceptor: next returned
ということで,S2と違ってネストした(hashCode()
から呼び出された)getTime()
のトレースは出力されません.無念だ.
このようになるのは,SpringのAOPは本当にProxyとして実装されているからです.AspectのWeavingを行うProxyFactoryBean
は,ターゲットオブジェクトはいじらずに,Aspectを適用したProxyを作成してターゲットをラップするだけなのです.
「AOPその3」でも書いたように,SpringのProxyはCGLIBによるものだけでなく,java.lang.reflect.Proxy
によるものも用意されています.両者で同じような実装にするには,こうするしかなかったのだと想像されます.
あのSpringのロジックだと(たぶん)デフォルトコンストラクタのない クラスにはAspectを適用できないんじゃないかなぁと思います。
試してみたところ,確かにデフォルトコンストラクタがないと例外が吹っ飛んできました.(;_;)
ただし,java.lang.reflect.Proxy
を使ったProxyの場合は,デフォルトコンストラクタがなくても大丈夫でした.しかし,こちらの場合はProxyで使用するinterface
を指定する必要があります.Spring的には,interface
中心の設計を推奨しているようですから,これでもいいということでしょうか?
それにしても,一見同じような昨日な機能を持っていると思われるIoCコンテナのAOP機能も,実装によって随分と差があることが分かって面白いですね.