stone2083

活用Srping AOP

总有那么一些代码,在测试环境下,是不能轻易被调用的。
比如:
1)发送系统任务邮件到客户邮箱,可能一不小心,就把测试邮件发送给了真实客户的邮箱里;
2)调用跨公司的系统接口,而对方系统没有测试环境,每调用一次接口,就会在对方系统产生垃圾数据;
3)调用的代码可能需要大量的cpu运算,占用大量的内存空间,消耗大量的资源;
等等。。。

为了解决这样的需求,
1)在代码中,到处充斥着这样的代码:
1 if(在测试环境下) {
2     打印日志;
3 else {
4     调用真实的业务逻辑;
5 }
于是乎,需要到处维护这样的代码,一旦增加此类需求,就需要编写同样的代码

2)部分懒惰的程序员,连这样的if...else...也不愿意写,仅仅在注释中说明下在测试环境中调用方法的危害性。
于是,在测试阶段,一旦和测试部门沟通不足,导致代码还是经常被调用到,如果是在作压力,性能测试,那么危害性可想而已。
曾发生过,压力测试某个功能,结果把大量的测试邮件,发送给了客户,影响很差。


那么,如何解决这样的需求场景呢?
没错,采用proxy模式,可以搞定。考虑到现在很多企业都使用Spring作为IOC容器,本文就简单介绍,如何采用spring aop来解决问题。

以发送邮件的需求作为虚拟场景。
现在有个Service,专门负责邮件的发送。
1. MyService.java
1 public class MyService {
2     public void sendMailSafely() {
3     System.out.println("send mail successfully.");
4     }
5 }

如果这个sendMailSafely被客户端调用,那么毫无疑问,邮件不管任何环境下,都会被成功发送。
需要有个方法拦截器,对这个方法做拦截。
2. MyInterceptor.java
 1 public class MyInterceptor implements MethodInterceptor {
 2 
 3     private boolean isProduction = false;
 4 
 5     @Override
 6     public Object invoke(MethodInvocation invocation) throws Throwable {
 7     if (!isProduction) {
 8         System.out.println("is production environment.do nothing");
 9         return null;
10     }
11     return invocation.proceed();
12     }
13 
14     public void setProduction(boolean isProduction) {
15     this.isProduction = isProduction;
16     }
17 
18 }
这个拦截器,根据配置文件的参数isProduction判断是否在正式环境,如果是在测试环境,对方法做拦截,仅仅打印log,不真实调用业务逻辑。

如何让sendMailSafely()方法被此拦截器做拦截,所以通过spring配置文件,配置一个advisor,通知对以Safely结尾的方法做拦截
3.  application.xml
 1 <bean id="safetyAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" scope="singleton">
 2     <property name="advice">
 3       <ref local="myInterceptor" />
 4     </property>
 5     <property name="patterns">
 6       <list>
 7         <value>.*Safely</value>
 8       </list>
 9     </property>
10   </bean>

附上application.xml的全部内容
 1 <beans default-autowire="byName">
 2 
 3   <!-- service实例 -->
 4   <bean id="myService" class="cn.zeroall.javalab.aop.MyService" scope="singleton" />
 5 
 6   <!-- 方法拦截器 -->
 7   <bean id="myInterceptor" class="cn.zeroall.javalab.aop.MyInterceptor" scope="singleton">
 8     <property name="production" value="false" />
 9   </bean>
10 
11   <!-- 通知者 -->
12   <bean id="safetyAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" scope="singleton">
13     <property name="advice">
14       <ref local="myInterceptor" />
15     </property>
16     <property name="patterns">
17       <list>
18         <value>.*Safely</value>
19       </list>
20     </property>
21   </bean>
22 
23   <!-- myService代理类 -->
24   <bean id="safetyService" class="org.springframework.aop.framework.ProxyFactoryBean" scope="singleton">
25     <property name="interceptorNames">
26       <list>
27         <value>safetyAdvisor</value>
28       </list>
29     </property>
30     <property name="targetName" value="myService" />
31   </bean>
32 
33 </beans>


写一个Client类来做演示。
4. Client.java
 1 public class Client {
 2 
 3     private ApplicationContext ctx = new ClassPathXmlApplicationContext(
 4         "cn/zeroall/javalab/aop/application.xml");;
 5 
 6     public static void main(String[] args) {
 7         Client c = new Client();
 8         c.sendMail();
 9         c.sendMailSafety();
10     }
11 
12     public void sendMail() {
13         MyService myService = (MyService) ctx.getBean("myService");
14         myService.sendMailSafely();
15     }
16 
17     public void sendMailSafety() {
18         MyService myService = (MyService) ctx.getBean("safetyService");
19         myService.sendMailSafely();
20     }
21 
22 }
大家可以看看最终输出的结果内容。

一直来,我都不会滥用AOP,尤其反感使用AOP来写业务逻辑内容,但是对于这类非业务逻辑需求,采用spring aop技术那是刚刚好啊。

最后,附上全部代码文件(使用maven构建)。
演示代码

posted on 2008-06-01 15:21 stone2083 阅读(499) 评论(0)  编辑  收藏 所属分类: java


只有注册用户登录后才能发表评论。


网站导航: