• Spring框架学习09——基于AspectJ的AOP开发


    1、基于注解开发AspectJ

    (1)AspectJ注解

    基于注解开发AspectJ要比基于XML配置开发AspectJ便捷许多,所以在实际开发中推荐使用注解方式。关于注解的相关内容如下:

    • @Aspect:用于定义一个切面,注解在切面类上;
    • @Pointcut:用于定义切入点表达式。在使用时需要定义一个切入点方法,该方法是一个返回值void且方法体为空的普通方法;
    • @Before:用于定义前置通知。在使用时通常为其指定value属性值,该值可以是已有的切入点,也可以直接定义切入点表达式;
    • @AfterReturning:用于定义后置返回通知。在使用时通常为其指定value属性值,该值可以是已有的切入点,也可以直接定义切入点表达式;
    • @Around:用于定义环绕通知。在使用时通常为其指定value属性值,该值可以是已有的切入点,也可以直接定义切入点表达式;
    • @AfterThrowing:用于定义异常通知。在使用时通常为其指定value属性值,该值可以是已有的切入点,也可以直接定义切入点表达式。另外,还有一个throwing属性用于访问目标方法抛出的异常,该属性值于异常通知方法中同名的形参一致;
    • @After:用于定义后置(最终)通知。在使用时通常为其指定value属性值,该值可以是已有的切入点,也可以直接定义切入点表达式;

    (2)切入点表达式的定义

    在通知中使用value属性定义切入点,通过execution函数,可以定义切入点的方法切入。
    语法:execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)
    例如:

    • 匹配所有类public方法 execution(public **(..))
    • 匹配指定包下所有类方法 execution(* com.imooc.dao.*(..)) 不包含子包
    • 匹配子包 execution(* com.imooc.dao..*(..)) ..*表示包、子孙包下所有类
    • 匹配指定类所有方法 execution(* com.imooc.service.UserService.*(..))
    • 匹配实现特定接口所有类方法 execution(* com.imooc.dao.GenericDAO+.*(..))
    • 匹配所有save开头的方法 execution(* save*(..))

    (3)代码实现

    添加依赖

    <!-- AOP联盟依赖 -->
    <dependency>
      <groupId>aopalliance</groupId>
      <artifactId>aopalliance</artifactId>
      <version>1.0</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>5.0.2.RELEASE</version>
    </dependency>
    <!--aspectJ相关依赖-->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.2</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>5.0.2.RELEASE</version>
    </dependency>

    创建StuDao类

    public class StuDao {
        public void save(){
            System.out.println("保存");
        }
        public String modify(){
            System.out.println("修改");
            return "modify...";
        }
        public void delete(){
            System.out.println("删除");
        }
        public void findOne(){
            System.out.println("查询单条信息");
            int i = 1/0;
        }
        public void findAll(){
            System.out.println("查询所有信息");
        }
    }

    创建切面类

    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    
    @Aspect
    public class MyAspectAnno {
    
        /**
         * 前置通知
         * @param joinPoint 用于获取切点信息
         */
        @Before(value = "execution(* com.aspectj.demo.StuDao.save(..))")
        public void before(JoinPoint joinPoint){
            System.out.println("前置通知============="+joinPoint);
        }
    
        /**
         * 后置返回通知,通过returning属性可以定义方法返回值,作为参数
         * @param result 和returning属性的值保持一致
         */
        @AfterReturning(value = "execution(* com.aspectj.demo.StuDao.modify(..))",returning = "result")
        public void afterReturing(Object result){
            System.out.println("后置返回通知=========="+result);
        }
    
        /**
         * 环绕通知
         * 如果不调用ProceedingJoinPoint的proceed方法,那么目标方法就被拦截了
         * @param joinPoint 可以调用拦截目标方法执行
         * @return 目标代理方法执行返回值
         * @throws Throwable
         */
        @Around(value = "execution(* com.aspectj.demo.StuDao.delete(..))")
        public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
            System.out.println("环绕前置通知*************");
            Object obj = joinPoint.proceed();
            System.out.println("环绕后置通知*************");
            return obj;
        }
    
        //异常通知
        @AfterThrowing(value = "execution(* com.aspectj.demo.StuDao.findOne(..))",throwing = "e")
        public void afterThrowing(Throwable e){
            System.out.println("异常通知================"+e);
        }
    
        //最终通知,无论是否出现异常,最终通知总是会被执行的
        @After(value = "execution(* com.aspectj.demo.StuDao.findAll(..))")
        public void after(){
            System.out.println("最终通知==================");
        }
    
    }

    配置applicationContext.xml文件

    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <!--开启AspectJ的注解开发,自动代理-->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
        <bean id="stuDao" class="com.aspectj.demo.StuDao"></bean>
        <bean class="com.aspectj.demo.MyAspectAnno"></bean>
    
    </beans>

    创建测试类

    @Test
    public void demo(){
    
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        StuDao stuDao = (StuDao) app.getBean("stuDao");
        stuDao.save();
        stuDao.modify();
        stuDao.delete();
        stuDao.findAll();
        stuDao.findOne();
    }

    运行结果

    (4)切点命名

    在每个通知内定义切点,会造成工作量大,不易维护,对于重复的切点,可以使用@Pointcut进行定义。
    切点方法:private void 无参数方法,方法名为切点名,当通知多个切点时,可以使用||进行连接。
    把切面类代码修改为:

    @Aspect
    public class MyAspectAnno {
    
        //前置通知
        @Before(value = "myPointcut1()")
        public void before(JoinPoint joinPoint){
            System.out.println("前置通知============="+joinPoint);
        }
    
        //后置通知
        @AfterReturning(value = "myPointcut2()",returning = "result")
        public void afterReturing(Object result){
            System.out.println("后置返回通知=========="+result);
        }
    
        //环绕通知
        @Around(value = "myPointcut3()")
        public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
            System.out.println("环绕前置通知*************");
            Object obj = joinPoint.proceed();
            System.out.println("环绕后置通知*************");
            return obj;
        }
    
        //异常通知
        @AfterThrowing(value = "myPointcut4()",throwing = "e")
        public void afterThrowing(Throwable e){
            System.out.println("异常通知================"+e);
        }
    
        //最终通知
        @After(value = "myPointcut5()")
        public void after(){
            System.out.println("最终通知==================");
        }
    
        @Pointcut(value = "execution(* com.aspectj.demo.StuDao.save(..))")
        private void myPointcut1(){}
    
        @Pointcut(value = "execution(* com.aspectj.demo.StuDao.modify(..))")
        private void myPointcut2(){}
    
        @Pointcut(value = "execution(* com.aspectj.demo.StuDao.delete(..))")
        private void myPointcut3(){}
    
        @Pointcut(value = "execution(* com.aspectj.demo.StuDao.findOne(..))")
        private void myPointcut4(){}
    
        @Pointcut(value = "execution(* com.aspectj.demo.StuDao.findAll(..))")
        private void myPointcut5(){}
    
    }

    2、基于XML配置开发AspectJ

    添加依赖

    <!-- AOP联盟依赖 -->
    <dependency>
      <groupId>aopalliance</groupId>
      <artifactId>aopalliance</artifactId>
      <version>1.0</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>5.0.2.RELEASE</version>
    </dependency>
    <!--aspectJ相关依赖-->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.2</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>5.0.2.RELEASE</version>
    </dependency>

    创建StuDao接口和实现类StuDaoImpl
    StuDao接口

    public interface StuDao {
        public void save();
        public void delete();
        public String modify();
        public void findOne();
        public void findAll();
    }

    StuDaoImpl实现类

    public class StuDaoImpl implements StuDao {
        @Override
        public void save() {
            System.out.println("保存");
        }
    
        @Override
        public String modify() {
            System.out.println("修改");
            return "modify...";
        }
    
        @Override
        public void delete() {
            System.out.println("删除");
        }
    
        @Override
        public void findOne() {
            System.out.println("查询单条记录");
            int i = 1/0;
        }
    
        @Override
        public void findAll() {
            System.out.println("查询所有记录");
        }
    }

    创建切面类

    public class MyAspectjXml {
    
        //前置通知
        public void before(){
            System.out.println("前置通知===============");
        }
    
        //后置返回通知
        public void afterReturing(Object result){
            System.out.println("后置返回通知============="+result);
        }
    
        //环绕通知
        public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
            System.out.println("环绕前置通知**************");
            Object obj = joinPoint.proceed();
            System.out.println("环绕后置通知**************");
            return obj;
        }
    
        //异常通知
        public void afterThrowing(Throwable e){
            System.out.println("异常通知=================="+e);
        }
    
        //最终通知
        public void after(){
            System.out.println("最终通知===================");
        }
    }

    配置applicationContext.xml文件

    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    
    
        <!--配置目标类-->
        <bean id="stuDao" class="com.aspectj.demo2.StuDaoImpl"></bean>
        <!--配置切面类-->
        <bean id="myAspectjXml" class="com.aspectj.demo2.MyAspectjXml"></bean>
        <!--AOP相关配置-->
        <aop:config>
            <!--配置切入点-->
            <aop:pointcut id="pointcut1" expression="execution(* com.aspectj.demo2.StuDao.save(..))"></aop:pointcut>
            <aop:pointcut id="pointcut2" expression="execution(* com.aspectj.demo2.StuDao.modify(..))"></aop:pointcut>
            <aop:pointcut id="pointcut3" expression="execution(* com.aspectj.demo2.StuDao.delete(..))"></aop:pointcut>
            <aop:pointcut id="pointcut4" expression="execution(* com.aspectj.demo2.StuDao.findOne(..))"></aop:pointcut>
            <aop:pointcut id="pointcut5" expression="execution(* com.aspectj.demo2.StuDao.findAll(..))"></aop:pointcut>
    
            <!--配置AOP的切面-->
            <aop:aspect ref="myAspectjXml">
                <!--配置前置通知-->
                <aop:before method="before" pointcut-ref="pointcut1"></aop:before>
                <!--配置后置返回通知-->
                <aop:after-returning method="afterReturing" pointcut-ref="pointcut2" returning="result"></aop:after-returning>
                <!--配置环绕通知-->
                <aop:around method="around" pointcut-ref="pointcut3"></aop:around>
                <!--配置异常通知-->
                <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4" throwing="e"></aop:after-throwing>
                <!--配置最终通知-->
                <aop:after method="after" pointcut-ref="pointcut5"></aop:after>
            </aop:aspect>
        </aop:config>
    
    </beans>

    创建测试类

    @Test
    public void demo(){
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        StuDao stuDao = (StuDao) app.getBean("stuDao");
        stuDao.save();
        stuDao.delete();
        stuDao.modify();
        stuDao.findAll();
        stuDao.findOne();
    }

    运行结果

  • 相关阅读:
    云时代架构读后感
    余额宝技术架构读后感
    shiyan
    11111
    编写hdfs文件遇到的问题
    123
    啦啦啦
    Hadoop安装
    js根据银行卡号进行判断属于哪个银行并返回银行卡类型
    git 使用
  • 原文地址:https://www.cnblogs.com/jpwz/p/10596088.html
Copyright © 2020-2023  润新知