初见Spring之AOP编程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_30322803/article/details/78465743

初见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
@Component
public 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注解生效。

阅读更多

没有更多推荐了,返回首页