基于注解spring AOP ,简单实现

        AspectJ允许使用注解定义切面、切入点和增强处理,而spring框架则可识别并根据这些注解来生成AOP的代理。spring只是使用了和AspectJ5一样的注解。但并没有使用AspectJ的编译器或织入器(编译时增强.class文件),底层依然使用spring AOP的动态代理。(运行时生成代理增加类,代理类=增强处理+目标对象方法)

一、简单的spring AOP实现实例

            前期准备:

                将jar包:aspectjweaver.jar、aspectjrt.jar 、aopalliance.jar放入lib目录下

            1)、定义普通bean、切面类 。切面类中定义@Before的增强处理

                包路径:com.spring.aspect.log.LogAspect.java

                      @Aspect

                     public class LogAspect {

                               //将com.spring.test1包下的所有类的所有方法,织入Before增强通知

                             @Before("execution(* com.spring.test1.*.*(..))")

                             public void log(){

                                           System.out.println("打日志");

                                }

                         }

                      com.spring.test1下有以下两个bean:Person、Axe,这两个bean将被织入前置通知

                             @Component

                             public class Person {

                                          @Autowired

                                          public Axe axe;

                                          public void printAxe(){

                                                        System.out.println(axe.chop());

                                             }

                                 }

                        @Component

                         public class Axe {

                                    public String chop(){

                                            return "这是axe方法";

                                     }

                             }

            2)、 在spring配置文件中,spring-config.xml下增加如下配置:

                       <!-- 扫描bean组件 -->

                      <context:annotation-config />

                      <!-- 启动@AspectJ支持 -->

                      <aop:aspectj-autoproxy/>

                     <!-- 添加bean组件、切面的扫描包 -->

                     <context:component-scan base-package="com.spring.test1,com.spring.aspect.log">

                     <context:include-filter type="annotation"

                                    expression="org.aspectj.lang.annotation.Aspect"/>

                     </context:component-scan>

        执行main方法:

           public class GetSpringBeanByxml {

             /**

              * @param args

             */

             public static void main(String[] args) throws Exception{

              // TODO Auto-generated method stub

                        ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config.xml");

     

                        Person person  =ctx.getBean("person",Person.class);

                        person.printAxe();

                  }

              }

                  运行结果如下:

                          打日志

                          打日志

                          这是axe方法

-------------------------------------------------------------------------------------------------------------------------

二、定义切入点

       定义切入点实质就是为切入点起一个名称。可以在多个增强处理方法上重复使用该名称。

       切入点采用一个普遍的方法(方法体通常为空)来定义,切入点方法的返回值必须为void,并且用@PointCut来注释。如下:(修改一 中的logAspect()方法)

    @Aspect

     public class LogAspect {

        //定义切入点

        @PointCut("execution(* com.spring.test1.*.*(..))")

          public  void addLog(){}

         //使用切入点

          @Before(pointcut="addLog()")

           public void log(){

                      System.out.println("打日志");

            }

      }

一旦程序定义了切入点后,程序就可以重复使用该切入点,甚至可以在其它切面类、其它包的切面类中使用该切入点,至于能否在其它切面类、其它包切面类中使用该切入点,取决于改切入点方法前的访问控制符。例如上面addlog()方法的访问控制符为public,则意味可以在任何其它切面类中访问该切入点,如果为private,则只能在改切面中使用该切入点。

 在其它切面类中使用该切入点方法如下:

        @Aspect

     public class TransAspect {

         //使用切入点

          @Before(pointcut="LogAspect.addLog()")

           public void log(){

                      System.out.println("打日志");

            }

      }

-----------------------------------------------------------------------------------------------------------------------------

三、AOP增强处理注解:

  @After("execution(* org......*.*(..))") 增强处理不管目标方法如何结束(包括正常结束和异常结束)都织入

  @AfterReturning(returning="rvt“, "execution(* org......*.*(..))")只有目标方法正常结束才被织入 returning是只目标方法的返回类型。rvt为object,只有目标方法为object类型,才会被织入。Object rvt可做于增强处理方法的形参。来获取目标方法的返回值。

   @AfterThrowing(throwing="ex" ,"execution(* org......*.*(..))")处理目前方法抛异常的情况。throwing=NullPointer-Exception,则只处理nullPointException异常的方法

    @Around

            @Around可以决定目标方法什么时候执行,如何执行,甚至阻止目标方法的执行。改变目标方法的返回值。但通常需要在线程安全的情况下使用。@Around增强处理方法的第一个形参必须是ProceedingJoinPoint类型,调用ProceedingJoinPoint的proceed()方法,目标方法才会被执行,否则目标方法不会被执行。proceed()方法有一个参数object[]数组,该数组的值被传入目标方法作为目标方法的实参。

            例:

     @Aspect

     public class TxAspect{

            @Around("execution(* com.spring.test1.*.*(..))")

            public Object  processTx(ProceedingJoinPoint jp){

                System.out.println("执行目标方法开始之前,模拟开始事务。。。。”)

                //获取目标方法的原始参数

                  Object[]  args=jp.getArgs();

                   if(args!=null &&args.length>1){

                         //修改目标参数第一参数的值

                          arg[0] = “增强的前缀”+arg[0];

                    }

                  //以改变后的参数取执行目标方法,并保存目标方法的返回值

                  Object rvt = jp.proceed(args);

                   System.out.println("执行目标方法开始之前,模拟结束事务。。。。”)

                 if(rvt != null && rvt instanceOf Integer)

                         rvt = (Integer)rvt* (Integer)rvt;

                   return rvt;

       }

   

------------------------------------------------------

四、访问目标方法的参数:

  修改如下方法,使其访问目标方法的参数:

 @Aspect

     public class LogAspect {

          @Before("execution(* com.spring.test1.*.*(..))")

           public void log(){

                      System.out.println("打日志");

            }

      }

  第一种方式:修改为:

         @Aspect

     public class LogAspect {

          @Before("execution(* com.spring.test1.*.*(..))")

           public void log(JoinPoint jp){

                      System.out.println("打日志");

                      System.out.println(“被织入增强处理的目标方法为:” + jp.getSignature().getName());

                      System.out.println(“被织入增强处理的目标方法参数为:” + jp.getArgs());

            }

      }

 第二种方式,修改为:

     @Aspect

     public class LogAspect {

          @Before("execution(* com.spring.test1.*.*(..))  && args(arg0,arg1)")

           public void log(String arg0,String  arg1){

                      System.out.println("打日志");

                      System.out.println(“目标方法第一个参数为:” + arg0);

                      System.out.println(“目标方法第二个参数为:” + arg1);

            }

      }

   第二种方式,在切入点加&& args(arg0,arg1)部分,意味可以在增强处理方法中指定两个形参,定义这两个形参时,类型可以随意指定,一旦指定了类型,则会限制目标方法。例如此处指定了两个string类型的参数,这就意味着目前方法必须带有两个string类型的参数。

--------------------------------------

五、增强处理的织入顺序

          在不同的切面里两个增强处理需要在同一连接点被织入时,spring AOP将随机的顺序来织入这两个增强处理。如果指定不同切面的增强处理的优先级,有如下两种方式:

   1)让切面类实现org.springframework.core.Ordered接口。实现改接口的intgetOrder()方法。改方法返回值越小优先级越高。

   2)直接使用@Order注解来修改切面类。使用@order注解时指定一个int型的value属性。改属性值越小,优先级越高。

      

猜你喜欢

转载自collegeyuan.iteye.com/blog/2272466