Spring面向切面(AOP)

AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志、事务、权限等,Struts2的拦截器设计就是基于AOP的思想。

  • AOP的基本概念
    • Aspect(切面):通常是一个类,里面可以定义切入点和通知
    • JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用。
    • Advice(通知):AOP在特定的切入点上执行的增强处理,有before、after、afterReturning、afterThrowing、around
    • Pointcut(切入点):AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以是JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类。
  • Spring AOP
    • Spring中的AOP代理离不开Spring的IOC容器,代理的生成,管理及其依赖关系都是有IOC容器负责,Spring默认使用JDK动态代理,在需要代理类而不是代理接口的时候,Spring会自动切换为使用CGLID代理。
  • 基于注解的AOP配置方式
    • 启用@Asject支持
      • 在applicationContext.xml中配置
        <aop:aspectj-autoproxy />
    • 通知类型介绍
      • Before:在目标方法被调用之前做增强处理,@Before只需要指定切入点表达式即可。
      • AfterReturning:在目标方法正常完成后做增强,@AfterReturning除了指定切入点表达式后,还可以指定一个返回值形参名returning,代表目标方法的返回值。
      • AfterThrowing:主要用来处理程序中未处理的异常,@AfterThrowing除了指定切入点表达式后,还可以指定一个throwing的返回值形参名,可以用过改形参名来访问目标方法中所抛出的异常对象。
      • After:在目标方法完成之后做增强,无论目标方法什么时候成功完成。@After可以指定一个切入点表达式。
      • Around:环绕通知,在目标方法完成前后做增强处理,环绕通知最重要的通知类型,像事务、日志等都是环绕通知。
  • 测试实例
    • Operator.java --> 切面类
      @Component
      @Aspect
      public class Operator {
      
          @Pointcut("execution(* com.lynn.learning.spring.service..*.*(..))")
          public void pointCut(){}
      
          @Before("pointCut()")
          public void doBefore(JoinPoint joinPoint){
              System.out.println("AOP Before Advice...");
          }
      
          @After("pointCut()")
          public void doAfter(JoinPoint joinPoint){
              System.out.println("AOP After Advice...");
          }
      
          @AfterReturning(pointcut="pointCut()", returning="returnVal")
          public void afterReturn(JoinPoint joinPoint, Object returnVal){
              System.out.println("AOP AfterReturning Advice:" + returnVal);
          }
      
          @AfterThrowing(pointcut="pointCut()",throwing="error")
          public void afterThrowing(JoinPoint joinPoint, Throwable error){
              System.out.println("AOP AfterThrowing Advice:" + error);
          }
      
          @Around("pointCut()")
          public Object around(ProceedingJoinPoint pjp){
              Object obj = null;
              System.out.println("AOP Around before...");
              try {
                  obj = pjp.proceed();
              } catch (Throwable e) {
                  e.printStackTrace();
              }
              System.out.println("AOP Around after...");
              return obj;
          }
      }
    • UserService.java --> 定义一些目标方法
      @Service
      public class UserService {
      
          public void add(){
              System.out.println("UserService add()");
          }
      
          public String delete(){
              System.out.println("UserService delete()");
              return "delete函数返回值";
          }
      
          public void edit(){
              System.out.println("UserService edit()");
              int i = 5/0;
          }
      }
    • applicationContext.xml
      <context:component-scan base-package="com.lynn.learning.spring"/>
      <aop:aspectj-autoproxy />
    • UserServiceTest.java
      public class UserServiceTest {
      
          @Test
          public void add() {
              ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
              UserService userService = (UserService) ctx.getBean("userService");
              userService.add();
          }
      
          @Test
          public void delete() {
              ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
              UserService userService = (UserService) ctx.getBean("userService");
              userService.delete();
          }
      
          @Test
          public void edit() {
              ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
              UserService userService = (UserService) ctx.getBean("userService");
              userService.edit();
          }
      }
    • 注意:做环绕通知的时候,调用ProceedingJoinPoint的proceed()方法才会执行目标方法,同时需要返回值,否则在AfterReturning中无法获取返回值。
  • 通知执行的优先级
    • 进入目标方法时,先织入Around,再织入Before
    • 退出目标方法时,织入Around,再织入AfterReturning,最后才织入After
  • 切入点的定义和表达式
    • 切入点表达式的定义算是整个AOP中的核心,有一套自己的规范
    • Spring AOP支持的切入点指示符:
      • @Pointcut("execution(* com.lynn.learning.spring.service..*.*(..))")
        • 第一个*表示匹配任意的方法返回值,..(两个点)表示零个或多个,上面的第一个..表示service包及其子包,第二个*表示所有类,第三个*表示所有方法,第二个..表示方法的任意参数个数
        • execution:用来匹配执行方法的连接点
      • @Pointcut("within(com.lynn.learning.spring.service*)")
        • within限定匹配方法的连接点,上面的就是表示匹配service包下的任意连接点
      • @Pointcut("this(com.lynn.learning.spring.service.UserService)")
        • this用来限定AOP代理必须是指定类型的实例,如上,指定了一个特定的实例,就是UserService
      • @Pointcut("bean(userService)")
        • bean也是非常常用的,bean可以指定IOC容器中的bean的名称。

 

 

猜你喜欢

转载自www.cnblogs.com/lynn16/p/10687106.html
今日推荐