spring中AOP编程

来源:互联网 发布:web前端性能优化方法 编辑:程序博客网 时间:2024/05/29 02:49

1.为什么会有AOP?

开发人员在编写应用程序时,通常包含两种代码:一种是和业务系统有关系的代码,一种是和业务系统关系不大的代码,例如日志,事务处理,权限处理等等。以前的程序中,这两种代码是写在一起的。这样一来,程序中到处充满着相同或类似的代码,不利于维护。而Aop的目标就是使这两种代码分离解耦,这样程序员就能专心于业务的处理,而且达到维护和重用的目的.

2.AOP思想。

 拿日志记录这个例子来看。每个方法都需要进行日志记录,不使用Aop的时候,每个方法中都要包含日志记录的代码,这样就会产生重复,而且日志记录和业务代码紧紧耦合,不利于维护。使用AOP的思想,可以把日志看成是一个切面,所有需要日志记录的方法都要经过这个切面。这样就可以把日志记录的代码封装,当方法经过切面的时候执行,这样就实现了代码重用。

3.AOP术语

Aspect(切面):

将散落于各个业务逻辑之中的Cross-cutting concerns收集起来,设计成各个独立可重用的对象,这些对象称为Aspect

例:动态代理中的LogHandler就是一个Aspect

Advice(增强):在特定的连接点上执行的动作,执行的这个动作就相当于对原始对象的功能做了增强。

Aspect对Cross-cutting concerns(横切关注点)的具体实现称为Advice。

Advice中包括了Cross-cutting concerns的行为或所要提供的服务

例:在动态代理的示例中代理类的invoke()就是Advice的具体实例

Joinpoint(连接点):

Advice在应用程序执行时加入业务流程的点或时机称为Joinpoint,具体来说就是Advice在应用程序中被执行的时机

Spring只支持方法的Joinpoint,执行时机可能是某个方法被执行之前或之后

Pointcut(切入点):切入点就是一系列连接点的集合。

Pointcut定义了感兴趣的Joinpoint,当调用的方法符合Pointcut表示式时,将Advice织入应用程序上提供服务

在Spring中,您可以在定义文件或Annotation中编写Pointcut,说明哪些Advice要应用至方法的前后

Target(目标对象):真正执行业务逻辑的对象

一个Advice被应用的对象或目标对象,也就是被代理的类

例:在动态代理的示例中HelloSpeaker就是LogHandler中Advice的Target

Weave(织入):将切面整合到程序的执行流程中

Advice被应用至对象之上的过程称为织入,在AOP中织入的方式有几个时间点:

编译时期

类加载时期

执行时期

4.编写第一个AOP程序

 案例分析,创建一个婚介所类,该婚介所为客户介绍对象时,模拟替客户挑选对象,替客户送花表白,替客户筹办婚礼等过程。

 1)首先编写切面的代码:

public class MyAspect {

  public void before(){

     System.out.println("先挑选对象");

  }

  

  public Object around(ProceedingJoinPointjoinpoint)throws Throwable{

 

     Object result =  joinpoint.proceed();

     System.out.println("约会,请吃饭,送花....");

     return result;

  }

  public void handleException(RuntimeException run){

     System.out.println("女的把男的暴打一顿");

     System.out.println("异常信息:"+run.getMessage());

  }

  public void getReturn(Object obj){

     if(obj ==null){

        System.out.println("约会失败!");

     }else{

        System.out.println("约会成功!");

     }

  }

  public void after(){

     System.out.println("这次相亲流程结束了。。");

  }

 

}

2)编写业务处理代码。针对接口的编程。

public class ZhangSanService implementsIMeetWoman {

 

  @Override

  publicObject meetWoman() {

     try{

       System.out.println("张三选择了一个合适的女生");

          RuntimeException re = newRuntimeException();

          throw re;

         

     }catch(RuntimeExceptionex){

       throwex;

     }

     finally{

       returnnew Object();

     }

    

 

    

  }

 

}

3)编写切面和业务的bean对象,在配置前引入aop的命名空间:

xmlns:aop="http://www.springframework.org/schema/aop"

<!-- 配置切面类 -->

<beanid="myAspect"class="com.gxa.bj.util.MyAspect"></bean>

<!-- 配置业务类 -->

<beanid="zhangsan"class="com.gxa.bj.service.ZhangSanService"></bean>

4)配置AOP增强


代码:

<aop:config>

  <aop:aspectid="myadvice"ref="myAspect">

       <!-- 首先配置切面的表达式 -->

       <aop:pointcutexpression="execution(* com..*.*Service.*(..))" id="mypoint"/>

       <!-- before增强 -->

       <aop:beforemethod="before" pointcut-ref="mypoint"/>

       <aop:aroundmethod="around"pointcut-ref="mypoint"/>

       <aop:after-throwingmethod="handleException"pointcut-ref="mypoint"throwing="run"/>

       <aop:after-returningmethod="getReturn"pointcut-ref="mypoint"returning="obj"/>

       <aop:aftermethod="after"pointcut-ref="mypoint"/>

  </aop:aspect>

</aop:config>

5)在程序中调用(注意,动态代理针对的是接口编程)。


程序调用:

ApplicationContext appcontext = new ClassPathXmlApplicationContext("applicationContext.xml");

       IMeetWoman zhangsan =(IMeetWoman)appcontext.getBean("zhangsan");

      zhangsan.meetWoman();

 

关于切面表达式的说明:

1.方法签名定义切入点举例:

  1)execution(public **(..)) 

      匹配所有目标类的public方法,其中第一个*表示返回类型,第二个*表示方法名,其中..表示任意类型和个数的参数。

  2)execution(* find*(..)):匹配所有目标类以find为前缀的方法。

2.通过类定义切入点

   execution(* com.gxa.bj.service.ZhangSanService.*(..))

   匹配该业务类下所有的方法。

3.通过类包定义切入点

   execution(* com.gxa.bj.service.*(..):匹配该包下所有的的类和方法

   execution(* com.gxa.bj.service..*(..):匹配该包下,子孙包下所有类的方法。注意:如果..出现在类名中,后面必须跟上*

4.通过方法形参定义切入点。

  execution(* meet(String,int)):匹配所有包的meet方法,且参数为String 类和int类型的

0 0
原创粉丝点击