接触AOP的概念已经有2年了,但是这是头一次真正想在项目中应用AOP,计划使用Spring 2.0的@AspectJ的方式来实现,开发环境是JDK 1.6.0。经过1天多的学习和试验,还没有配置成功。具体情况的描述如下:项目应用需求如下:
1. 已经存在一个遗留系统
2. 要求遗留系统的部分模块(主要是开放给普通用户的模块)的文本信息提交都必须经过敏感词过滤,如果包含系统定义的敏感词,则不允许发布我的实现思路如下:
1. 写一个对敏感词进行检查的类,其中主要的方法就是对一个对象的所有String类型字段进行检查
2. 利用AspectJ的Annotation切入点定义的方式,对包含特定Annotation的方法进行统一的检查(遍历检查方法中传入的各个参数)具体实现的类:Class IllegalInputValidator:敏感词检查工具类
具体代码略去,经过测试可以正常使用Class IllegalCheckAdvise:切面定义类import java.lang.reflect.InvocationTargetException;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect; 
import org.aspectj.lang.annotation.Before; 
import hep.exception.IllegalWordException;
@Aspect //通过该注解将该类标识为一个切面 
public class IllegalCheckAdvise {


@Before("@annotation(hep.annotation.NeedIllegalCheck)")  
public void checkAllArgs(JoinPoint jp) throws IllegalWordException{  
         System.out.println("Logging before " + jp.getSignature().getName());
        Object[] args=jp.getArgs();
        if(args!=null){
         for(Object o:args){
         try {
if(IllegalInputValidator.checkObject(o)){
throw new IllegalWordException("Illegal word check failed. Object="+o.toString());
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
         }
        }
     }   }
@Interface NeedIllegalCheck:注释类,用于标明一个方法需要做敏感词过滤的检查
package hep.annotation;
import org.aspectj.apache.bcel.classfile.ConstantPool;
import org.aspectj.apache.bcel.classfile.annotation.Annotation;
import java.lang.annotation.Documented;  
import java.lang.annotation.ElementType;  
import java.lang.annotation.Retention;  
import java.lang.annotation.RetentionPolicy;  
import java.lang.annotation.Target;  /**
 * 注释类,用于标注一个方法需要经过敏感词过滤
 * 
 */
@Target({ElementType.METHOD})  
@Retention(RetentionPolicy.RUNTIME)  
@Documented 
public @interface NeedIllegalCheck{}
Web.xml中加上对Spring配置文件的加载:  <servlet>
    <servlet-name>context</servlet-name>
    <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
WEB-INF目录下增加Spring配置文件applicationContext.xml,内容如下:<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">     <!-- 启用注解,Spring Annotation需使用 -->  
     <context:annotation-config/>  
     <!-- 使用AspectJ方式 -->  
     <aop:aspectj-autoproxy proxy-target-class="true"/>  
       
     <!-- advisor using aspectJ -->  
     <bean class="hep.platform.IllegalCheckAdvise" />     <!-- target class bean -->
     <bean id="lcDAO" class="hep.persist.lc.LcDAO"/>     
</beans>
业务类LcDAO中的一个方法加入Annotation: /**
 * 需要经过敏感词过滤的测试方法
 * @param obj
 */
@NeedIllegalCheck
public void persist(Lc obj){
DAO.getInstance().save(obj);
}
然后在action中写相应的逻辑调用这个方法,但是定义的前置增强并没有被触发,既没有在后台输出任何信息,也没有抛出任何异常(我特意加入了不允许出现在文本中的敏感词),包含敏感词的对象直接就存到数据库中去了我的问题是:
1. 这种需求是否适合用AOP实现?这种实现方式是不是合适?
2. 我上面的步骤是不是漏了什么?以至于AOP机制完全没有起作用。我看Spring的AOP文档看得实在是头晕太晦涩了。以上的代码基本上是按照网上的一些demo配的,心里没底。希望有经验的兄弟姐妹提供一点帮助,谢谢:)

解决方案 »

  1.   

    啊。。不能编辑。。把代码重新整一下放回帖里吧Class IllegalInputValidator:敏感词检查工具类 
    具体代码略去,经过测试可以正常使用 Class IllegalCheckAdvise:切面定义类 import java.lang.reflect.InvocationTargetException; import org.aspectj.lang.JoinPoint; 
    import org.aspectj.lang.annotation.Aspect; 
    import org.aspectj.lang.annotation.Before; 
    import hep.exception.IllegalWordException; 
    @Aspect //通过该注解将该类标识为一个切面 
    public class IllegalCheckAdvise { 
    @Before("@annotation(hep.annotation.NeedIllegalCheck)")  
    public void checkAllArgs(JoinPoint jp) throws IllegalWordException{  
            System.out.println("Logging before " + jp.getSignature().getName()); 
            Object[] args=jp.getArgs(); 
            if(args!=null){ 
            for(Object o:args){ 
            try { 
    if(IllegalInputValidator.checkObject(o)){ 
    throw new IllegalWordException("Illegal word check failed. Object="+o.toString()); 

    } catch (IllegalArgumentException e) { 
    e.printStackTrace(); 
    } catch (IllegalAccessException e) { 
    e.printStackTrace(); 
    } catch (InvocationTargetException e) { 
    e.printStackTrace(); 

            } 
            } 
        }  } 
     @Interface NeedIllegalCheck:注释类,用于标明一个方法需要做敏感词过滤的检查 
    package hep.annotation; 
    import org.aspectj.apache.bcel.classfile.ConstantPool; 
    import org.aspectj.apache.bcel.classfile.annotation.Annotation; 
    import java.lang.annotation.Documented;  
    import java.lang.annotation.ElementType;  
    import java.lang.annotation.Retention;  
    import java.lang.annotation.RetentionPolicy;  
    import java.lang.annotation.Target;  /** 
    * 注释类,用于标注一个方法需要经过敏感词过滤 

    */ 
    @Target({ElementType.METHOD})  
    @Retention(RetentionPolicy.RUNTIME)  
    @Documented 
    public @interface NeedIllegalCheck{ } 
     Web.xml中加上对Spring配置文件的加载:   <servlet> 
        <servlet-name>context </servlet-name> 
        <servlet-class>org.springframework.web.context.ContextLoaderServlet </servlet-class> 
        <load-on-startup>1 </load-on-startup> 
      </servlet> 
     WEB-INF目录下增加Spring配置文件applicationContext.xml,内容如下: <?xml version="1.0" encoding="UTF-8"?> 
    <beans xmlns="http://www.springframework.org/schema/beans" 
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
          xsi:schemaLocation=" 
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">     <!-- 启用注解,Spring Annotation需使用 -->  
        <context:annotation-config/>  
        <!-- 使用AspectJ方式 -->  
        <aop:aspectj-autoproxy proxy-target-class="true"/>  
          
        <!-- advisor using aspectJ -->  
        <bean class="hep.platform.IllegalCheckAdvise" />     <!-- target class bean --> 
        <bean id="lcDAO" class="hep.persist.lc.LcDAO"/>    
    </beans> 
     业务类LcDAO中的一个方法加入Annotation: /** 
    * 需要经过敏感词过滤的测试方法 
    * @param obj 
    */ 
    @NeedIllegalCheck 
    public void persist(Lc obj){ 
    DAO.getInstance().save(obj); 

     
      

  2.   

    1.这个需求合适
    2.建议checkAllArgs这个方法先简单点,就写个 System.out.println("Logging before“) 看看能不能打印出来public @interface NeedIllegalCheck{ }  定义annotations时至少需要一个value吧,配置没问题的
      

  3.   

    你的Action是什么action?Struts1有三种,其中MappingDispatchAction、DispatchAction两个Spring AOP是拦不住的,去看我的博客有一文分析:
    http://howsun.blog.sohu.com/106725713.html
      

  4.   

    annotation接口可以为空的,这个应该没问题
      

  5.   

    我并不是拦截action中的方法,而是action调用的DAO的方法,也会有问题嘛?
      

  6.   

    试过把Action改为普通的Action,而不是DispatchAction还是不行。
    如果action中的代码为:ServletContext servletContext = request.getSession().getServletContext();
    ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext);

    LcDAO lcDAO = (LcDAO) ctx.getBean("lcDAO");
    lcDAO.persist(lc);
    则可以拦截,如果改为:LcDAO.getInstance().persist(lc);则AOP失效很是郁闷
      

  7.   

    LZ,你这句话LcDAO.getInstance().persist(lc);肯定拦截不到啊,你配置只能只直接是LcDao的方法吧,嵌套就不符合pointcut了吧。
      

  8.   

    楼上的意思我不太明白,还没有来得及深入了解spring的内部机制。
    我的配置中声明了LcDAO这个bean的静态工厂方法,然后我用这个静态工厂方法创建实例,Spring应该能够捕获到吧?
    请指教
      

  9.   

    补充一下,昨天我已经把spring配置文件中对LcDAO的创建方法改为了静态工厂方法的方式:
    <bean id="lcDAO" class="hep.persist.lc.LcDAO" factory-method="getInstance"/>   
      

  10.   

    你不妨试试:LcDao lcDao = LcDAO.getInstance();
                             lcDao.persist(c);
      

  11.   

    试过了,不行。
    是不是需要在applicationContext.xml中把LcAction也注册为Spring管理的bean?
      

  12.   

    看楼主的代码,没太看明白,又看了一下楼主的回复我怎么没找找执行通知的切面呢,我没用过楼主生命切面的方法传递参数也可以通过args来传递,
    @Before("@annotation(hep.annotation.NeedIllegalCheck)")  
    这里应该加入切面吧,我回头再看看spring文档,呵呵
    例如@Before("execution(* test.Bean11.*(..)) &&"+"args(user,..)")  
      

  13.   

    不太明白楼上的意思。。
    @Before("@annotation(hep.annotation.NeedIllegalCheck)")  
    public void checkAllArgs(JoinPoint jp) throws IllegalWordException{  
    这个应该就是执行通知的切面方法啊
      

  14.   

    @Before("execution(* xxx.yyy.YourService.persist(..)) &&"+"args(obj,..)")  
    public void checkAllArgs(Lc obj) throws IllegalWordException{  
            obj...............
    public void persist(Lc obj){
    DAO.getInstance().save(obj);

    这样可否满足你的要求
      

  15.   

    maim方法成功了,现在是想在web环境里实现吧?
      

  16.   


    我们并不是所有的service类的persist方法都需要经过这样的检查,而是在需要检查的方法前加注释。。
      

  17.   


    在web环境中用applicationContext的getBean()去做也能实现
    但是直接用LcDAO.getInstance().persist()就拦截不到
      

  18.   


    你这样就用了LcDAO里面两个方法吧
      

  19.   

    如果用@annotation,应该定义一下切入点吧
    在任意的并且标注了NeedIllegalCheck注释的方法下执行
    @Before("execution( * *(..)&& "+@annotation(hep.annotation.NeedIllegalCheck)") 
    public void checkAllArgs(JoinPoint jp) throws IllegalWordException{  
    测试一下吧
      

  20.   

    楼上,现在不是切入点的问题了,如果用context.getBean()来获取DAO对象,可以顺利切入
    现在关键是在action中,如果不用context自带的方法来获得对象,而是用LcDao.getInstance()的方法来获得对象的话,advice就不会执行但是如果所有的地方都要用这种侵入式的编码方式修改的话,AOP就意义不大了,和在各个方法里添加检查的逻辑相比没有优势,甚至还要更麻烦一些。。
      

  21.   

    基本上 大多数情况下
    主要就只用到了AOP的
    事务管理
    其他的用得不多