初见Spring之AOP编程

来源:互联网 发布:microsoft办公软件 编辑:程序博客网 时间:2024/05/17 08:59

初见Spring之AOP编程

    Spring其中一个主要特性就是支持AOP编程,AOP编程可以将多个类或者方法中的重复逻辑抽取出来,提高了代码重用性和可维护性质,AOP编程是对面向对象编程的延伸和补充。本文不介绍AOP编程的概念,主要描述Spring对AOP编程的支持。

    Spring对AOP编程提供了两种支持,第一种是Spring AOP也就是Spring自己实现的AOP编程,第二中是AspectJ,Spring的核心库集成了AspectJ,AspectJ也是Spring建议使用的AOP框架,本文主要介绍Spring对AspectJ的支持。

    一丶Spring AOP编程基本概念

    AOP编程主要涉及如下几个基本的概念:

    (1)pointcut(切入点),通俗的来说就是待增强的方法,严格指向待增强方法的位置。

    (2)adavice(通知),通知就是增强的方法,对目标对象增强代码的实现都是写在通知中,AspectJ中提供了五种通知:

    1.before(前置通知):该通知在切入点之前执行。

    2.after-returning(后置通知):该通知在切入点方法执行完之后执行,如果切入点方法抛出了异常,该通知不会执行。

    3.around(环绕通知):该通知在切入点方法执行前后执行

    4.after-throwing(异常通知):在切入点方法抛出异常之后执行该通知

    5.after(最终通知):在切入点方法执行完毕后指向,假如切入点方法抛出了异常该方法照样执行

    (3) Aspect(切面):从编程的角度来看,切面就是所有增强方法的集合,在切面里面定义和实现了各种增强方法。

    二丶基于XML的AspectJ AOP编程

    Spring提供两种方法对AspectJ的支持,第一个便是利用xml配置的方法来完成AspectJ AOP编程,下面举例在说明这个方法。

    定义一个Teacher类和一个切面类,Teacher类代表待增强的对象,切面类里面实现由所有的通知,下面来探讨下Spring基于XML的方法如何实现AOP编程。

    Teacher类: 

public class TeacherDaoImpl implements TeacherDao{    @Override    publicvoid login() {       // TODO Auto-generated method stub       System.out.println("teacher登录完成");    }}

    切面类:

 publicclass TeacherAspect{    /**     * @param point 保存有切入点信息     */    publicvoidbeforeNotification(JoinPoint point){       System.out.println("权限验证");    }    /**     * @param point 保存切入点信息     * @param returnValue 切点点方法的返回值     */    publicvoid afterNotification(JoinPointpoint,Object returnValue){       System.out.print("登录成功跳转到首页");    }    /**     * @param point 环绕通知对应的特殊切入点,可以调用增强对象的方法     * @throws Throwable 执行切点方法时抛出的异常信息     */    publicObject AroundrNotification(ProceedingJoinPoint point) throws Throwable{       System.out.println("权限验证");       Object object  = point.proceed();       System.out.println("登录成功,跳转到首页");       returnobject;    }    /**     * @param point     * @param e 目标方法抛出异常     */    publicvoidafterThrowingNotification(JoinPoint point,Throwable e){       System.out.println("登录失败");    }    /**     * @param point 切入点信息     */    publicvoid finalNotification(JoinPointpoint){       System.out.println("清除登录痕迹");;    } }

测试代码:

public class MainAspectJ {    publicstatic void main(String [] args){       ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");       TeacherDao teacherDao = (TeacherDao)context.getBean("teacherDao");       teacherDao.login();    }}

Spring配置文件:

<!--配置增强对象-->    <bean name="teacherDao" class="AspectJ.TeacherDaoImpl"/>    <!--配置切面  -->    <bean name="teacherAspect"class="AspectJ.TeacherAspect"/>    <!--AspecJ AOP配置核心-->    <aop:config>       <aop:aspect ref="teacherAspect">           <aop:pointcut id="teacherPoint"expression="execution(* AspectJ.*.*(..))"/>           <aop:before method="beforeNotification"pointcut-ref="teacherPoint"/>           <aop:after-returning method="beforeNotification"pointcut-ref="teacherPoint" returning="returnValue"/>           <aop:after-throwing method="afterThrowingNotification" throwing="e"pointcut-ref="teacherPoint"/>           <aop:after method="finalNotification"pointcut-ref="teacherPoint"/>       </aop:aspect>    </aop:config>

        

图1 前置通知以及后置通知

    结合Spring的配置文件和图1的结果可以看到,Spring完成对目标对象的增强,可以看见after通知执行了,after-throwing通知并没有执行,after-throwing通知只有下发生异常的时候执行,after通知无论是否发生异常都执行。

    对Teacher类做如下修改来验证上述结论(其他代码内容不变)

public class TeacherDaoImpl implements TeacherDao{    @Override    publicvoid login() {       // TODO Auto-generated method stub       int i=1/0;       System.out.println("teacher登录完成");    }}

             

 图2 发生异常时候执行情况

从图2的运行结果可以看出来,发生异常的时候,after-throwing通知会执行,但是after-returning通知不会执行,final通知会执行

三丶基于注解的AOP编程

     通过上述的流程可以发现基于xml的AOP编程需要编写繁杂的xml文件,所以提供基于注解编写AOP的方法。下面通过一个和上述相似的例子来介绍基于注解的

    ManDaoImpl类:被增强对象

@Repository("man")public class ManDaoImpl implements ManDao{    @Override    publicvoid login() {       // TODO Auto-generated method stub    }}

    ManDaoAspectJ:切面对象

@Aspect@Componentpublic class ManDaoAspect {    //定义一个切入点@Pointcut("execution(* AspectJ.*.*(..))")    privatevoid mepointCut(){}       @Before(value="mepointCut()")    publicvoid befoeNotification(JoinPointpoint){       System.out.println("登录校验");    }    @AfterReturning(value="mepointCut()",returning="result")    publicvoid afterNotification(JoinPointpoint,Object result){       System.out.print("登录成功");    }    @Around(value="mepointCut()")    publicObject roundNotification(ProceedingJoinPoint point) throws Throwable{       System.out.println("权限校验");       Object object = point.proceed();       System.out.println("登录成功");       returnobject;    }    @AfterThrowing(value="mepointCut()",throwing="e")    publicvoid AfterThrowing(JoinPoint point,Throwablee){       System.out.println("登录失败");    }    @After(value="mepointCut()")    publicvoid finalNotification(JoinPointpoint){       System.out.println("清除登录痕迹");    }}

    测试代码对象:

publicclass MainAspectJ {    publicstatic void main(String [] args){       ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");       //TeacherDao teacherDao =(TeacherDao)context.getBean("teacherDao");       //teacherDao.login();       ManDao manDao= (ManDao)context.getBean("man");       manDao.login();    }}

Spring配置文件写法:

 <!-- 指定需要扫描的包,使注解生效 -->      <context:component-scan base-package="AspectJ"/>      <!--AOP注解生效-->      <aop:aspectj-autoproxy/>

测试结果:

           

                图3基于注解的AOP测试结果

    从上述这个基于注解配置AOP的例子中,我们可以观察到基于注解配置AOP和基于xml配置AOP在通知配置,切面配置,切入点配置方面是完全是一一对应的,但是基于注解的AOP编程显然比基于XML的AOP编程更为简洁。这里特别需要注意基于注解额AOP编程在配置文件中,必须介绍扫描注解以及配置AOP注解生效。

原创粉丝点击