首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

SpringAOP嵌套调用的解决方法

2012-10-07 
SpringAOP嵌套调用的解决办法SpringAOP嵌套调用的解决办法 Spring AOP在同一个类里自身方法相互调用时无法

SpringAOP嵌套调用的解决办法
SpringAOP嵌套调用的解决办法



Spring AOP在同一个类里自身方法相互调用时无法拦截。比如下面的代码:

Java代码

public class SomeServiceImpl implements SomeService  
{  
 
    public void someMethod()  
    {  
        someInnerMethod();  
        //foo...  
    }  
 
    public void someInnerMethod()  
    {  
        //bar...  
    }  
}
public class SomeServiceImpl implements SomeService

{



    public void someMethod()

    {

        someInnerMethod();

        //foo...

    }



    public void someInnerMethod()

    {

        //bar...

    }

}


两个方法经过AOP代理,执行时都实现系统日志记录。单独使用someInnerMethod时,没有任何问题。但someMethod就有问题了。someMethod里调用的someInnerMethod方法是原始的,未经过AOP增强的。我们期望调用一次someMethod会记录下两条系统日志,分别是someInnerMethod和someMethod的,但实际上只能记录下someMethod的日志,也就是只有一条。在配置事务时也可能会出现问题,比如someMethod方法是REQUIRED,someInnerMethod方法是REQUIRES_NEW,someInnerMethod的配置将不起作用,与someMethod方法会使用同一个事务,不会按照所配置的打开新事务。
由于java这个静态类型语言限制,最后想到个曲线救国的办法,出现这种特殊情况时,不要直接调用自身方法,而通过AOP代理后的对象。在实现里保留一个AOP代理对象的引用,调用时通过这个代理即可。比如:

Java代码

//从beanFactory取得AOP代理后的对象  
SomeService someServiceProxy = (SomeService)beanFactory.getBean("someService");   
 
//把AOP代理后的对象设置进去  
someServiceProxy.setSelf(someServiceProxy);   
 
//在someMethod里面调用self的someInnerMethod,这样就正确了  
someServiceProxy.someMethod();
//从beanFactory取得AOP代理后的对象

SomeService someServiceProxy = (SomeService)beanFactory.getBean("someService");



//把AOP代理后的对象设置进去

someServiceProxy.setSelf(someServiceProxy);



//在someMethod里面调用self的someInnerMethod,这样就正确了

someServiceProxy.someMethod();


但这个代理对象还要我们手动set进来,幸好SpringBeanFactory有BeanPostProcessor扩展,在bean初始化前后会统一传递给BeanPostProcess处理,繁琐的事情就可以交给程序了,代码如下,首先定义一个BeanSelfAware接口,实现了此接口的程序表明需要注入代理后的对象到自身。

Java代码

public class SomeServiceImpl implements SomeService,BeanSelfAware  
 
{  
 
    private SomeService self;//AOP增强后的代理对象  
 
   
 
    //实现BeanSelfAware接口  
 
    public void setSelf(Object proxyBean)  
 
    {  
 
        this.self = (SomeService)proxyBean  
 
    }  
 
   
 
    public void someMethod()  
 
    {  
 
        someInnerMethod();//注意这句,通过self这个对象,而不<SPAN class=hilite2>是</SPAN>直接调用的  
 
        //foo...  
 
    }  
 
    public void someInnerMethod()  
 
    {  
 
        //bar...  
 
    }  
 
}
public class SomeServiceImpl implements SomeService,BeanSelfAware



{



    private SomeService self;//AOP增强后的代理对象







    //实现BeanSelfAware接口



    public void setSelf(Object proxyBean)



    {



        this.self = (SomeService)proxyBean



    }







    public void someMethod()



    {



        someInnerMethod();//注意这句,通过self这个对象,而不是直接调用的



        //foo...



    }



    public void someInnerMethod()



    {



        //bar...



    }



}


再定义一个BeanPostProcessor,beanFactory中的每个Bean初始化完毕后,调用所有BeanSelfAware的setSelf方法,把自身的代理对象注入自身……

Java代码

public class InjectBeanSelfProcessor implements BeanPostProcessor  
{  
   
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException  
    {  
        if(bean instanceof BeanSelfAware)  
        {  
            System.out.println("inject proxy:" + bean.getClass());  
            BeanSelfAware myBean = (BeanSelfAware)bean;  
            myBean.setSelf(bean);  
            return myBean;  
        }  
        return bean;  
    }  
   
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException  
    {  
        return bean;  
    }  
}
public class InjectBeanSelfProcessor implements BeanPostProcessor

{



    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException

    {

        if(bean instanceof BeanSelfAware)

        {

            System.out.println("inject proxy:" + bean.getClass());

            BeanSelfAware myBean = (BeanSelfAware)bean;

            myBean.setSelf(bean);

            return myBean;

        }

        return bean;

    }



    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException

    {

        return bean;

    }

}


最后,在BeanFactory配置中组合起来,只需要把BeanPostProcesser加进去就可以了,比平常多一行配置而已。

Java代码

<!-- 注入代理后的bean到bean自身的BeanPostProcessor... -->  
<bean />   
 
<bean id="someService" />  
    </property>  
    <property name="interceptorNames">  
        <list>  
            <value>someAdvisor</value>  
        </list>  
    </property>  
</bean>  
 
<!-- 调用spring的<SPAN class=hilite1>DebugInterceptor</SPAN>记录日志,以确定方法<SPAN class=hilite2>是</SPAN>否被AOP增强 -->  
<bean id="<SPAN class=hilite1>debugInterceptor</SPAN>" />  
 
<bean id="someAdvisor" />  
    </property>  
    <property name="patterns">  
        <list>  
            <value>.*someMethod</value>  
            <value>.*someInnerMethod</value>  
        </list>  
    </property>  
</bean>
    <!-- 注入代理后的bean到bean自身的BeanPostProcessor... -->

    <bean />



    <bean id="someService" />

        </property>

        <property name="interceptorNames">

            <list>

                <value>someAdvisor</value>

            </list>

        </property>

    </bean>



    <!-- 调用spring的DebugInterceptor记录日志,以确定方法是否被AOP增强 -->

    <bean id="debugInterceptor" />



    <bean id="someAdvisor" />

        </property>

        <property name="patterns">

            <list>

                <value>.*someMethod</value>

                <value>.*someInnerMethod</value>

            </list>

        </property>

    </bean>


这里的someService#someInnerMethod就表现出预期的行为了,无论怎样,它都是经过AOP代理的,执行时都会输出日志信息。
用XmlBeanFactory进行测试需要注意,所有的BeanPostProcessor并不会自动生效,需要执行以下代码:

Java代码

XmlBeanFactory factory = new XmlBeanFactory(...);  
InjectBeanSelfProcessor postProcessor = new InjectBeanSelfProcessor();  
factory.addBeanPostProcessor(postProcessor);
XmlBeanFactory factory = new XmlBeanFactory(...);

InjectBeanSelfProcessor postProcessor = new InjectBeanSelfProcessor();

factory.addBeanPostProcessor(postProcessor);



热点排行