栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring AOP详解

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring AOP详解

AOP 1 介绍
  • AOP:面向切面编程
  • 什么是AOP ? 使用代理技术,在不修改代码的基础上,对已有方法进行增强。
2 入门案例
  • 目标类:Dog

    package com.czxy.demo15_aop.domain;
    
    import org.aspectj.lang.annotation.Before;
    import org.springframework.stereotype.Component;
    
    import javax.annotation.PostConstruct;
    import javax.annotation.PreDestroy;
    
    
    @Component
    public class Dog {
    
        public void eat() {
            System.out.println(" aop dog 正在吃...");
        }
    
    }
    
    
  • 配置类:

    package com.czxy.demo15_aop.config;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    
    @Configuration
    @ComponentScan(basePackages = {"com.czxy.demo15_aop.domain","com.czxy.demo15_aop.aop"})
    public class Demo15Configuration {
    
    }
    
    
  • 测试类

    package com.czxy.demo15_aop;
    
    import com.czxy.demo15_aop.config.Demo15Configuration;
    import com.czxy.demo15_aop.domain.Dog;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringRunner;
    
    import javax.annotation.Resource;
    
    @RunWith(SpringRunner.class)
    @ContextConfiguration(classes = Demo15Configuration.class)
    public class TestDemo15 {
        @Resource
        private Dog dog;
    
        @Test
        public void testDemo15() {
            dog.eat();
        }
    }
    
    
  • 修改配置类,开启AOP编程

@EnableAspectJAutoProxy         //开启AOP
  • 编写切面类 MyAspect,对目标类的方法进行增强

    package com.czxy.demo15_aop.aop;
    
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.springframework.stereotype.Component;
    
    
    @Component	//将当前类,添加到spring容器中
    @Aspect     //切面编程注解
    public class MyAspect {
    
        // 切入点表达式: 方法签名
        // @注解("execution(返回值类型  包名.类名.方法名(参数类型))")
        @Before("execution(void com.czxy.demo15_aop.domain.Dog.eat())")
        public void init() {
            System.out.println(" 15 初始化");
        }
    }
    
    
3 入门案例2
  • 目标类:

    package com.czxy.demo16_aop.dao;
    
    import org.springframework.stereotype.Repository;
    
    
    @Repository
    public class UserDao {
    
        public void insertUser() {
            System.out.println("添加");
        }
    
        public void updateUser() {
            System.out.println("更新");
        }
    }
    
    
  • 配置类

    package com.czxy.demo16_aop.config;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.EnableAspectJAutoProxy;
    
    @Configuration
    @ComponentScan(basePackages = {"com.czxy.demo16_aop"})
    @EnableAspectJAutoProxy         //开启AOP
    public class Demo16Configuration {
    
    }
    
    
  • 测试类

    package com.czxy.demo16_aop;
    
    import com.czxy.demo15_aop.config.Demo15Configuration;
    import com.czxy.demo15_aop.domain.Dog;
    import com.czxy.demo16_aop.config.Demo16Configuration;
    import com.czxy.demo16_aop.dao.UserDao;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringRunner;
    
    import javax.annotation.Resource;
    
    
    @RunWith(SpringRunner.class)
    @ContextConfiguration(classes = Demo16Configuration.class)
    public class TestDemo16 {
        @Resource
        private UserDao userDao;
    
        @Test
        public void testDemo15() {
            userDao.insertUser();
            System.out.println("----------");
            userDao.updateUser();
        }
    }
    
    
  • 切面类

    package com.czxy.demo16_aop.aop;
    
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.springframework.stereotype.Component;
    
    
    @Component
    @Aspect
    public class MyAspect {
    
        @Before("execution(void com.czxy.demo16_aop.dao.UserDao.*User())")
        public void start() {
            System.out.println("开启事务");
        }
    
        @After("execution(void com.czxy.demo16_aop.dao.UserDao.*User())")
        public void commit() {
            System.out.println("提交事务");
        }
    }
    
    
4相关术语
  • 目标类:需要被增强的类、代理的目标对象。
  • 连接点:目标类可能被增强的每一个方法。
  • 切入点:特殊的连接点,已经被增强了。
  • 通知/增强:增强的方法
5 切入点表达式
  • 作用:将通知/增强作用于具体切入点

  • 基本格式:

    指示符(表达式)
    
    1.指示符分类:
    【execution】:用于匹配方法执行的连接点;
    within:用于匹配指定类型内的方法执行;
    this:用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配;
    target:用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;
    args:用于匹配当前执行的方法传入的参数为指定类型的执行方法;
    @within:用于匹配所以持有指定注解类型内的方法;
    @target:用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解;
    @args:用于匹配当前执行的方法传入的参数持有指定注解的执行;
    @annotation:用于匹配当前执行方法持有指定注解的方法;
    
    2.表示式格式:
    execution([修饰符] 返回值类型 包名.类名.方法名(参数类型列表) [throws 异常])
    	返回值:
    		* 表示返回任意值
    	包名:
    		com.czxy.user.dao	具体包名
    		com.czxy.*.dao		任意模块的dao
            com.czxy.*sys.dao	固定后缀的包
            com.czxy.user.dao..	任意子包 (dao.impl包)
        类名
        	UserDao				具体类名
        	*Dao				固定后缀
        	User*				固定前缀
        	*					任意
        方法:
        	findAll				具体方法名
        	find*				固定前缀
        	*All				固定后缀
        	*					任意
        (参数类型列表):
        	()					无参
        	(int)				第一个整形参数
        	(int,int)			两个参数都是整形
        	(*)					任意一个参数
        	(..)				参数任意
        	
    
    // 完整的实例代码
    * * com.czxy.service..User*.select*(..)
    
    // 常见的写法
    * com.czxy.service..*.*(..)
    
    6 通知类型
    • spring通知共5个分类:前置通知、后置通知、环绕通知、抛出异常通知、最终通知

      try{
          // 前置通知、环绕通知
          // 目标类的方法
          // 后置通知、环绕通知
      } catch() {
          // 抛出异常通知
      } finally {
          // 最终通知
      }
      
      //前置通知 @Before
      //后置通知 @AfterReturning
      //环绕通知 @Around
      //抛出异常通知 @AfterThrowing
      //最终通知 @After
      
    6.1 前置通知
        @Before("execution(* com.czxy.demo16_aop.dao..*.*(..))")
        public void myBeforeAdvice() {
            System.out.println("开启事务");
        }
    
    6.2 后置通知
    // 返回值:类型 变量名
    //		类型,必须是Object
    //      变量名,需要通过returning设置,且提供对应的方法参数
    @AfterReturning(value="切入点表达式", returning = "返回值变量名")
    public void 方法名(Object 返回值变量名) {
        
    }
    
        @AfterReturning(value="execution(* com.czxy.demo16_aop.dao..*.*(..))", returning = "obj")
        public void myAfterReturningAdvice(JoinPoint joinPoint, Object obj) {
            System.out.println("目标类:" + joinPoint.getTarget());
            System.out.println("方法名:" + joinPoint.getSignature().getName());
            System.out.println("返回值:" + obj);
            System.out.println("提交事务");
        }
    
    6.3 环绕通知
        // 环绕通知:必须手动执行目标方法(连接点) ProceedingJoinPoint 可执行连接点
        @Around("myPointcut()")
        public Object myAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            System.out.println("环绕前2");
            // 执行目标
            Object proceed = proceedingJoinPoint.proceed();
    
            System.out.println("环绕后2");
    
            return proceed;
        }
    
    6.4 异常通知
        // 异常通知,可以获得异常具体信息,异常类型(Throwable) 异常变量名
        @AfterThrowing(value="execution(* com.czxy.demo16_aop.dao..*.*(..))",throwing = "e")
        public void myAfterThrowingAdvice(Throwable e) {
            System.out.println("异常通知:" + e.getMessage());
        }
    
    6.5 最终通知
        @After("execution(* com.czxy.demo16_aop.dao..*.*(..))")
        public void myAfterAdvice() {
            System.out.println("释放资源");
        }
    
    6.6 抽取切入点
    使用 @Pointcut 抽取切入点,通过 方法名 进行引用。
    
    package com.czxy.demo16_aop.aop;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.springframework.stereotype.Component;
    
    
    @Component
    @Aspect
    public class MyAspect2 {
        // 抽取公共切入点表达式
        @Pointcut("execution(* com.czxy.demo16_aop.dao..*.*(..))")
        private void myPointcut() {
    
        }
    
        // 前置通知
    //    @Before("myPointcut()")
        public void myBeforeAdvice() {
            System.out.println("开启事务2");
        }
    //     后置通知
    //    @AfterReturning(value="myPointcut()", returning = "obj")
        public void myAfterReturningAdvice(JoinPoint joinPoint, Object obj) {
            System.out.println("目标类2:" + joinPoint.getTarget());
            System.out.println("方法名2:" + joinPoint.getSignature().getName());
            System.out.println("返回值2:" + obj);
            System.out.println("提交事务2");
        }
    
        // 环绕通知:必须手动执行目标方法(连接点) ProceedingJoinPoint 可执行连接点
        @Around("myPointcut()")
        public Object myAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            System.out.println("环绕前2");
            // 执行目标
            Object proceed = proceedingJoinPoint.proceed();
    
            System.out.println("环绕后2");
    
            return proceed;
        }
    
        // 异常通知,可以获得异常具体信息,异常类型(Throwable) 异常变量名
        @AfterThrowing(value="myPointcut()",throwing = "e")
        public void myAfterThrowingAdvice(Throwable e) {
            System.out.println("异常通知2:" + e.getMessage());
        }
    
        @After("myPointcut()")
        public void myAfterAdvice() {
            System.out.println("释放资源2");
        }
    }
    
    
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/325172.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号