zoukankan      html  css  js  c++  java
  • 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();
    }

    运行结果

  • 相关阅读:
    hi.baidu.com 百度流量统计
    Autofac is designed to track and dispose of resources for you.
    IIS Manager could not load type for module provider 'SharedConfig' that is declared in administration.config
    How to create and manage configuration backups in Internet Information Services 7.0
    定制swagger的UI
    NSwag在asp.net web api中的使用,基于Global.asax
    NSwag Tutorial: Integrate the NSwag toolchain into your ASP.NET Web API project
    JS变量对象详解
    JS执行上下文(执行环境)详细图解
    JS内存空间详细图解
  • 原文地址:https://www.cnblogs.com/jpwz/p/10596088.html
Copyright © 2011-2022 走看看