关于一次aop的经验

公司最近要求在某些程序出异常的时候,发封邮件至某个coder,用来及时检查问题所在,要求详细知道哪个类,哪个方法出的异常,出的什么异常等,而且不修改以前的程序代码!

于是想到了spring的AOP.想到了其中的ThrowsAdvice接口,这是用来再程序出了异常之后拦截,而后添加功能的.

本以为很简单,于是简单些了下测试类,[b]测试的业务类没有实现接口,就是一个java类[/b],本身应用了spring的申明事务.步骤如下:

1.先写一个pojo的advice通知:
public class Advice  {
public void throwing(Exception ex){
System.out.println("pojo的afterThrowing...exception:"+ex.getMessage());
}
}



2.spring配置文件,把通知应用到pointcut中:
<bean id="adviceBean" class="com.zhangwei.struts.Advice"></bean>  
<!-- 利用spring AOP的配置元素定义一个通知 -->
<aop:config >

<!-- 引用刚才定义的一个纯粹的POJO切面Bean -->
<aop:aspect ref="adviceBean">
<!-- 定义一个命名切点,必点切点定义的重复,expression用于配置匹配规则,(返回类型 返回类.方法(参数设置) -->
<aop:pointcut id="todo" expression="execution(* com.zhangwei.struts.Bo.*(..)) " />
<!-- 方法跑出异常后通知 -->
<aop:after-throwing pointcut-ref="todo" method="throwing" throwing="ex"/>
</aop:aspect>
</aop:config>


之后运行,发现错了,原因在于我的测试业务类没有实现某一接口,因为事务管理用了AOP,我的advice又用了AOP,事务管理时我的业务类成了proxy,应用我的advice时,proxy无法类型转换至业务类,报错.后来又了解决方式,就是指定proxyTargetClass的值为true,强制使用cglib生成子类,代码如下:
<aop:config proxy-target-class="true">    

<!-- 引用刚才定义的一个纯粹的POJO切面Bean -->
<aop:aspect ref="adviceBean">
<!-- 定义一个命名切点,必点切点定义的重复,expression用于配置匹配规则,(返回类型 返回类.方法(参数设置) -->
<aop:pointcut id="todo" expression="execution(* com.zhangwei.struts.Bo.*(..)) " />
<!-- 方法前通知 -->
<aop:after-throwing pointcut-ref="todo" method="throwing" throwing="ex"/>
</aop:aspect>
</aop:config>


<bean id="txProxyTemplate" abstract="true"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="proxyTargetClass">
<value>true</value>
</property>
<property name="transactionManager" ref="transactionManager" />
<property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="remove*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="login*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>


但是这样做的后果就是拦截器重复拦截,因为2个AOP功能,2个子类,同时起作用,就拦截了2次.解决方案:把我的业务类换成接口,方法调用改成接口调用.

本以为可以了,但是发现advice的method,target参数无法得到,配置如下:
  <aop:after-throwing pointcut-ref="todo" method="throwing"  throwing="ex"/> 

无法给通知传参,只能得到一个exception类型的参数,得不到method,target等参数,琢磨了2小时,没有解决,头昏脑胀!

休息一小时,继续琢磨,得到正确解决方式:
1.写一个依赖于spring的advice:
public class Advisor implements ThrowsAdvice {
public void afterThrowing(Method method, Object[] args, Object target,
Exception ex) {
System.out.println("传统经典aop的afterThrowing2...");
System.out.println("methodName:"+method.getName());
System.out.println("traget:"+target.getClass().getInterfaces()[0].getName());
}
}


2.重新写配置文件:
<!-- 定义一个依赖于spring的通知 -->  
<bean id="advice" class="com.zhangwei.struts.Advisor"></bean>
<aop:config >
<!-- 定义AOP的切入点 -->
<aop:pointcut id="todo" expression="execution(* com.zhangwei.struts.Bo.*(..)) " />
<!-- 定义建议者,需要通知以及切入点2个元素 -->
<aop:advisor advice-ref="advice" pointcut-ref="todo"/>
</aop:config>


解决问题!

************************************************************************************************

可是由于公司项目业务层是java类,又不能修改以前的代码,只能采用链式加AOP的方式去做了:
 <bean id="login" class="com.zhangwei.struts.BoLogin">   
<property name="daoLogin">
<ref bean="daoLogin" />
</property>
</bean>

<!-- 定义一个依赖于spring的通知 -->

<bean id="advice" class="com.zhangwei.struts.Advisor"></bean>
<bean id="memberAopAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="mappedName" value="*" />
<property name="advice" ref="advice" />
</bean>

<!-- 第一层代理 -->
<bean id="loginProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--启用CGLib,代理的不再是接口-->
<property name="proxyTargetClass">
<value>true</value>
</property>
<property name="target">
<ref bean="login"/>
</property>
<property name="interceptorNames">
<value>memberAopAdvisor</value>
</property>
</bean>


<!-- 第二层代理对第一层代理继续代理 -->
<bean id="boLogin"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!--启用CGLib,代理的不再是接口-->
<property name="proxyTargetClass">
<value>true</value>
</property>
<property name="target">
<ref bean="loginProxy"/>
</property>
<property name="transactionManager" ref="transactionManager" />
<property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="remove*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="login*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>


程序中最后调用"boLogin"这个spring Bean 就没有问题了.
Ok!解决!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值