ネストした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機能も,実装によって随分と差があることが分かって面白いですね.