• 【Spring】Spring的AspectJ的AOP


    Spring学习笔记(10)Spring的AspectJ的AOP

    在Spring中使用AspectJ实现AOP

    • AspectJ 是一个面向切面的框架, 它扩展了 Java 语言。 AspectJ 定义了 AOP 语法所以它有一个专门的编译器用来生成遵守 Java 字节编码规范的 Class 文件。
    • AspectJ 是一个基于 Java 语言的 AOP 框架
    • Spring2.0 以后新增了对 AspectJ 切点表达式支持
    • @AspectJ 是 AspectJ1.5 新增功能, 通过 JDK5 注解技术, 允许直接在 Bean 类中定义切面
    • 新版本 Spring 框架, 建议使用 AspectJ 方式来开发 AOP

    AspectJ 表达式

    那些类允许增强的表达式

    语法:execution(表达式)
    execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)
    [*代表方法的返回值为任意类型] [*代表所有方法] [..代表任意参数类型]

    • execution(* cn.itcast.spring3.demo1.dao.*(..)) —只检索当前包

    • execution(* cn.itcast.spring3.demo1.dao..*(..)) —检索包及当前包的子包.

    • execution(* cn.itcast.dao.GenericDAO+.*(..)) —检索 GenericDAO 及子类

    • 匹配所有类 public 方法 execution(public * *(..))

    • 匹配指定包下所有类方法 execution(* cn.itcast.dao.*(..)) 不包含子包

    • execution(* cn.itcast.dao..*(..)) ..*表示包、 子孙包下所有类

    • 匹配指定类所有方法 execution(*cn.itcast.service.UserService.*(..))

    • 匹配实现特定接口所有类方法execution(*cn.itcast.dao.GenericDAO+.*(..))

    • 匹配所有 save 开头的方法 execution(* save*(..))

    AspectJ 增强

    @Before 前置通知, 相当于 BeforeAdvice
    @AfterReturning 后置通知, 相当于 AfterReturningAdvice
    @Around 环绕通知, 相当于 MethodInterceptor
    @AfterThrowing 抛出通知, 相当于 ThrowAdvice
    @After 最终 final 通知, 不管是否异常, 该通知都会执行
    @DeclareParents 引介通知, 相当于 IntroductionInterceptor

    基于注解

    1.引入jar包

    • pom.xml
    <dependency>
          <groupId>junitgroupId>
          <artifactId>junitartifactId>
          <version>4.12version>
          <scope>testscope>
        dependency>
    
        <dependency>
          <groupId>org.springframeworkgroupId>
          <artifactId>spring-contextartifactId>
          <version>${spring.version}version>
        dependency>
    
        <dependency>
          <groupId>org.springframeworkgroupId>
          <artifactId>spring-testartifactId>
          <version>${spring.version}version>
        dependency>
        
        <dependency>
          <groupId>org.aspectjgroupId>
          <artifactId>aspectjweaverartifactId>
          <version>1.9.4version>
        dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    2.编写增强的类

    • UserDao
    @Repository(value = "userDao") //注解的方式,spring管理对象的创建
    public class UserDao {
        public void add(){
            System.out.println("添加用户");
        }
        public void addInfo(){
            System.out.println("添加用户信息");
        }
        public void update(){
            System.out.println("更新用户");
        }
        public void delete(){
            System.out.println("删除用户");
        }
        public void find(){
            System.out.println("查找用户");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    3.使用AspectJ注解形式

    • MyAspectJ
    @Component // 注解的方式,spring管理对象的创建
    @Aspect  // 用来定义且切面
    public class MyAspectJ {
        /**
         * 前置通知
         * 对UserDao里面的以add方法进行增强
         * @param joinPoint
         */
        @Before("execution(* club.krislin.Dao.UserDao.add*(..))")
        public void before(JoinPoint joinPoint){
            //打印的是切点信息
            System.out.println(joinPoint);
            System.out.println("前置增强");
        }
    
        /**
         * 后置通知
         * 对update开头的方法进行增强
         * @param returnValue
         */
        @AfterReturning(value = "execution(* club.krislin.Dao.UserDao.update*(..))",returning = "returnValue") // 接受返回值,方法的返回值为任意类型
        public void after(Object returnValue){
            System.out.println("后置通知");
            System.out.println("方法的返回值为:"+returnValue);
        }
    
        /**
         * 环绕通知增强
         * 对以find开头的方法进行增强
         * @param proceedingJoinPoint
         * @return
         * @throws Throwable
         */
        @Around(value = "execution(* club.krislin.Dao.UserDao.find*(..))")
        public Object arount(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            System.out.println("环绕通知增强-----前");
            // 执行目标方法
            Object obj = proceedingJoinPoint.proceed();
            System.out.println("环绕通知增强-----后");
            return obj;
        }
    
        /**
         * 异常通知增强
         * 对以find开头的方法进行增强
         * @param e
         */
        @AfterThrowing(value = "execution(* club.krislin.Dao.UserDao.find(..))",throwing = "e")
        public void afterThrowing(Throwable e){
            System.out.println("出现异常"+e.getMessage());
        }
    
        @After(value = "execution(* club.krislin.Dao.UserDao.find(..))")
        public void after(){
            System.out.println("最终通知");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    4.配置applicationContext.xml

    
        <aop:aspectj-autoproxy>aop:aspectj-autoproxy>
    
        <context:component-scan base-package="club.krislin">context:component-scan>
    
    • 1
    • 2
    • 3
    • 4

    5.测试

    • UserDaoTest
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = "classpath:applicationContext.xml")
    public class UserDaoTest {
        @Resource(name = "userDao")
        private UserDao userDao;
    
        @Test
        public void testUserDao(){
            userDao.add();
            userDao.addInfo();
            userDao.delete();
            userDao.find();
            userDao.update();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    基于xml

    1.编写被增强的类

    • UserDao
    public class UserDao {
        public void add(){
            System.out.println("添加用户");
        }
        public void addInfo(){
            System.out.println("添加用户信息");
        }
        public void update(){
            System.out.println("更新用户");
        }
        public void delete(){
            System.out.println("删除用户");
        }
        public void find(){
            System.out.println("查找用户");
            //int i = 1;
            //int n = i/0;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2.编写增强的类

    • MyAspectJ
    public class MyAspectJ {
        /**
         * 前置通知
         * @param joinPoint
         */
        public void before(JoinPoint joinPoint){
            //打印的是切点信息
            System.out.println(joinPoint);
            System.out.println("前置增强");
        }
    
        /**
         * 后置通知
         * @param returnValue
         */
           public void after(Object returnValue){
            System.out.println("后置通知");
            System.out.println("方法的返回值为:"+returnValue);
        }
    
        /**
         * 环绕通知增强
         * @param proceedingJoinPoint
         * @return
         * @throws Throwable
         */
        public Object arount(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            System.out.println("环绕通知增强-----前");
            // 执行目标方法
            Object obj = proceedingJoinPoint.proceed();
            System.out.println("环绕通知增强-----后");
            return obj;
        }
    
        /**
         * 异常通知增强
         * @param e
         */
        public void afterThrowing(Throwable e){
            System.out.println("出现异常"+e.getMessage());
        }
    
        /**
         * 最终通知增强
         */
        public void after(){
            System.out.println("最终通知");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    3配置applicationContext.xml

    
        <bean name="userDao" class="club.krislin.Dao.UserDao">bean>
        
        <bean name="myAspectJ" class="club.krislin.MyAspectJ">bean>
    
        
        <aop:config>
            
            <aop:pointcut expression="execution(* club.krislin.Dao.UserDao.add*(..))" id="myPointcut"/>
    
            <aop:pointcut expression="execution(* club.krislin.Dao.UserDao.add(..))" id="myPointcut1"/>
    
            <aop:aspect ref="myAspectJ">
                
                <aop:before method="before" pointcut-ref="myPointcut"/>
            aop:aspect>
            <aop:aspect ref="myAspectJ">
                
                <aop:after-returning method="after" pointcut-ref="myPointcut" returning="returnValue"/>
            aop:aspect>
            <aop:aspect ref="myAspectJ">
                
                <aop:around method="arount" pointcut-ref="myPointcut"/>
            aop:aspect>
            <aop:aspect ref="myAspectJ">
                
                <aop:after-throwing method="afterThrowing" pointcut-ref="myPointcut" throwing="e"/>
            aop:aspect>
            <aop:aspect ref="myAspectJ">
                
                <aop:after method="after" pointcut-ref="myPointcut1"/>
            aop:aspect>
        aop:config>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    4.测试

    • UsetDaoTest
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = "classpath:applicationContext.xml")
    public class UserDaoTest {
        @Resource(name = "userDao")
        private UserDao userDao;
    
        @Test
        public void testUserDao(){
            userDao.add();
            userDao.addInfo();
            userDao.delete();
            userDao.update();
            userDao.find();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    xml方式的AOP配置步骤

    1.配置被增强的类和通知(即增强方法)

    2.使用aop:config声明aop配置

    aop:config 用于声明开始aop的配置

    <aop:config>
        
    aop:config>
    
    • 1
    • 2
    • 3

    3.使用aop:aspect配置切面

    aop:aspect 用于配置切面
    属性: id:给切面提供一个唯一的表示
    ref:引用配置好的通知类bean的id

    <aop:aspect id="txAdvice" ref="txManager">
        
    aop:aspect>
    
    • 1
    • 2
    • 3

    4.使用aop:pointcut配置切入点表达式

    aop:pointcut 用于配置切入点表达式.就是指定对哪些类的哪些方法进行增强
    属性: expression:由于定义切入表达式
    id:用于给切入点表达式提供唯一的标识

    <aop:pointcut expression="execution(* club.krislin.Dao.UserDao.add*(..))" id="myPointcut"/>
    
    • 1

    5.使用aop:xxx配置对应的通知类型

    aop:before 用于配置前置通知.指定增强的方法在切入点方法之前执行
    属性: method:用于指定通知类中的增强方法名称
    pointcut-ref:用于指定切入点表达式的引用
    pointcut:用于指定切入点表达式
    执行时间: 切入点方法执行之前

    <aop:before method="before" pointcut-ref="myPointcut"/>
    
    • 1

    aop:after-returning 用于配置后置通知
    属性: method:用于指定通知类中的增强方法名称
    pointcut-ref:用于指定切入点表达式的引用
    pointcut:用于指定切入点表达式
    returning:后置通知返回值
    执行时间:切入点方法正常执行之后,它和异常通知只能有一个执行

     <aop:after-returning method="after" pointcut-ref="myPointcut" returning="returnValue"/>
    
    • 1

    aop:after-throwing 用于配置异常通知
    属性: method:用于指定通知类中的增强方法名称
    pointcut-ref:用于指定切入点表达式的引用
    pointcut:用于指定切入点表达式
    throwing:指定抛出的异常
    执行时间:切入点方法执行异常后执行,它和后置通知只能有一个执行

    <aop:after-throwing method="afterThrowing" pointcut-ref="myPointcut" throwing="e"/>
    
    • 1

    aop:after: 用于配置最终通知
    属性: method:用于指定通知类中的增强方法名称
    pointcut-ref:用于指定切入点表达式的引用
    pointcut:用于指定切入点表达式
    执行时间:无论切入点方法执行时是否异常,它都会在后面执行

    <aop:after method="after" pointcut-ref="myPointcut1"/>
    
    • 1

    aop:around 用于配置环绕通知
    属性: method:用于指定通知类中的增强方法名称
    pointcut-ref:用于指定切入点表达式的引用
    pointcut:用于指定切入点表达式

    <aop:around method="arount" pointcut-ref="myPointcut"/>
    
    • 1

    Advisor 和 Aspect 的区别?(都叫切面)

    • Advisor:Spring 传统意义上的切面:支持一个切点和一个通知的组合.
    • Aspect:可以支持多个切点和多个通知的组合.
  • 相关阅读:
    WMS仓库信息系统仓库信息Service模块
    Go for循环中的defer
    软件测试Triangle练习题
    java算法day5
    Headscale组网教程
    一键自动化博客发布工具,用过的人都说好(oschina篇)
    MyBatisPlus(七)——通用枚举、代码生成器、多数据源、MyBatisX
    redis 哨兵
    栈、栈帧、AAPCS的一些粗浅理解(通俗易懂)
    Ubuntu - 安装 、配置 Redis 远程连接和密码
  • 原文地址:https://blog.csdn.net/u013301892/article/details/127943711