• java


    AOP: 面向切面编程(Aspect oriented Programming)

    说白了就是把常用业务方法打包,在放在需要的位置。这个和OOP(面向对象)是不冲突的,只是为了完善面向对象编程中的一些业务逻辑问题。

    比如:

    A在运行的时候,打印日志。

    B在运行的时候,打印日志。

    传统方法:

    A运行结束位置写一个log方法。

    B运行结束位置写一个log方法。

    这样万一是个大项目,有100方法都需要打印日志。万一有改动(比如客户要求改打印格式),全部修改一遍工作量很大。

    所以为了解决这个问题,有了AOP编程思想。

    因为打印log的方法是基本通用的,所以可以专门写一个方法集中管理。然后所有目标的方法执行的时候统一调用这里的方法。把方法分配到需要的位置。

    Spring的AOP主要就是干这个的。

    步骤:

    1.  添加一个用类,集合了需要的方法

    2. 添加spring的注解(我这里是@Component),交给spring组建管理

    3. 添加aspect注解,表示这个是用来aop的类

    4. 添加对应注解和表达式用来告诉spring这些方法是在哪些类的什么时候使用

    5. 添加配置文件,开启AOP模式

    java:

    package com.itheima.service;
    
    
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.Signature;
    import org.aspectj.lang.annotation.*;
    import org.springframework.stereotype.Component;
    import com.itheima.domain.Account;
    import sun.misc.Signal;
    
    @Component
    @Aspect
    public class AopTest {
    
    
        //* * com.itheima.service.AccountService.*(..)  返回任意权限,任意返回类型,的这个类中的任意方法,参数可以是任意。根据具体需求修改
    
        @Before(value = "execution(public * com.itheima.service.AccountService.aopTest(..))")//在AccountService类的aopTest方法运行前,运行该方法
        public void beforeShowData(){
            System.out.println("目标方法准备运行【Before】");
        }
    
        @After(value = "execution(public * com.itheima.service.AccountService.*(..))")   //在AccountService类的所有方法运行后,都运行该方法
        public void afterShowData(JoinPoint joinPoint){  //使用 JoinPoint作为参数可以获得方法的详细信息
            Signature s = joinPoint.getSignature(); //获取方法签名
            System.out.println(s.getName() + "方法运行了【After】");
        }
    
        @AfterReturning(value = "execution(public void com.itheima.service.AccountService.aopTest())", returning = "result")   //在AccountService类的aopTest正常结束后,运行该方法,如果有返回结果,则返回结果存入result(这里是void所以没有- -)
        public void afterReturnShowData(Object result){
            System.out.println("目标方法正常运行完毕了【AfterReturning】");
        }
    
        @AfterThrowing(value = "execution(public void com.itheima.service.AccountService.aopTest())", throwing = "exception")   //在AccountService类的aopTest抛出异常时,运行该方法,获得异常存入exception
        public void afterThrowData(Exception exception){
            System.out.println("目标方法抛出异常【AfterThrowing】,异常信息是" + exception);
        }
    
    
    }
    package com.itheima.test;
    
    import com.itheima.service.AccountService;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class SpringTest {
    
        @Test
        public void test1() {
            ApplicationContext ac = new ClassPathXmlApplicationContext("springConfig.xml");//手动加载配置文件
            AccountService as = (AccountService)ac.getBean("accountService");
            //as.findAll(); //测试spring能否运行
    
    
            as.aopTest();
        }
    }

    配置文件中添加:

    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

    结果:

    目标方法准备运行【Before】
    aop测试。
    aopTest方法运行了【After】
    目标方法正常运行完毕了【AfterReturning】

    其他注解: 

    1. 上面的方法可以看出,如果一个方法前后都需要处理,那么需要写4次切入点表达式,很麻烦。

    @PointCut   可以用来重用方法路径(execution后面跟着的 )

    package com.itheima.service;
    
    
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.Signature;
    import org.aspectj.lang.annotation.*;
    import org.springframework.stereotype.Component;
    import com.itheima.domain.Account;
    import sun.misc.Signal;
    
    @Component
    @Aspect
    public class AopTest {
    
    
        //* * com.itheima.service.AccountService.*(..)  返回任意权限,任意返回类型,的这个类中的任意方法,参数可以是任意。根据具体需求修改
    
        //抽取可重用的切入点(目标方法方法)表达式
        //1. 声明一个空方法
        //2. 添加Pointcut注解
        //3..切入点表达式(就是本来value后面跟着的那一串),作为参数写在Pointcut注解里
        //4, 用这个空方法代替切入点表达式
    
        @Pointcut("execution(public * com.itheima.service.AccountService.aopTest(..))")
        public void targetMethod(){}
    
    
    
        //@Before(value = "execution(public * com.itheima.service.AccountService.aopTest(..))")//在AccountService类的aopTest方法运行前,运行该方法
        @Before(value = "targetMethod()")
        public void beforeShowData(){
            System.out.println("目标方法准备运行【Before】");
        }
    
        @After(value = "targetMethod()")   //在AccountService类的所有方法运行后,都运行该方法
        public void afterShowData(JoinPoint joinPoint){  //使用 JoinPoint作为参数可以获得方法的详细信息
            Signature s = joinPoint.getSignature(); //获取方法签名
            System.out.println(s.getName() + "方法运行了【After】");
        }
    
        @AfterReturning(value = "targetMethod()", returning = "result")   //在AccountService类的aopTest正常结束后,运行该方法,如果有返回结果,则返回结果存入result(这里是void所以没有- -)
        public void afterReturnShowData(Object result){
            System.out.println("目标方法正常运行完毕了【AfterReturning】");
        }
    
        @AfterThrowing(value = "targetMethod()", throwing = "exception")   //在AccountService类的aopTest抛出异常时,运行该方法,获得异常存入exception
        public void afterThrowData(Exception exception){
            System.out.println("目标方法抛出异常【AfterThrowing】,异常信息是" + exception);
        }
    
    }

    2. 除了Before,After,AfterRunning,AfterThrowing,还有一个 @Round,可以同时实现前面4中注解的作用。

    spring主要利用了反射的invoke来代理执行方法, 从而实现AOP功能。round可以看做invoke本身。

    package com.itheima.service;
    
    
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.Signature;
    import org.aspectj.lang.annotation.*;
    import org.springframework.stereotype.Component;
    import com.itheima.domain.Account;
    import sun.misc.Signal;
    
    @Component
    @Aspect
    public class AopTest {
    
    
        //* * com.itheima.service.AccountService.*(..)  返回任意权限,任意返回类型,的这个类中的任意方法,参数可以是任意。根据具体需求修改
    
        //抽取可重用的切入点(目标方法方法)表达式
        //1. 声明一个空方法
        //2. 添加Pointcut注解
        //3..切入点表达式(就是本来value后面跟着的那一串),作为参数写在Pointcut注解里
        //4, 用这个空方法代替切入点表达式
    
        @Pointcut("execution(public * com.itheima.service.AccountService.aopTest(..))")
        public void targetMethod(){}
    
    
    
        //@Before(value = "execution(public * com.itheima.service.AccountService.aopTest(..))")//在AccountService类的aopTest方法运行前,运行该方法
        @Before(value = "targetMethod()")
        public void beforeShowData(){
            System.out.println("目标方法准备运行【Before】");
        }
    
        @After(value = "targetMethod()")   //在AccountService类的所有方法运行后,都运行该方法
        public void afterShowData(JoinPoint joinPoint){  //使用 JoinPoint作为参数可以获得方法的详细信息
            Signature s = joinPoint.getSignature(); //获取方法签名
            System.out.println(s.getName() + "方法运行了【After】");
        }
    
        @AfterReturning(value = "targetMethod()", returning = "result")   //在AccountService类的aopTest正常结束后,运行该方法,如果有返回结果,则返回结果存入result(这里是void所以没有- -)
        public void afterReturnShowData(Object result){
            System.out.println("目标方法正常运行完毕了【AfterReturning】");
        }
    
        @AfterThrowing(value = "targetMethod()", throwing = "exception")   //在AccountService类的aopTest抛出异常时,运行该方法,获得异常存入exception
        public void afterThrowData(Exception exception){
            System.out.println("目标方法抛出异常【AfterThrowing】,异常信息是" + exception);
        }
    
        @Around(value = "targetMethod()") //环绕方法,可以综合以上4中方法的功能
        public void aroundData(ProceedingJoinPoint joinPoint){ //ProceedingJoinPoint 是 JoinPoint 的子类
            Object[] oArr = joinPoint.getArgs(); //获得参数
    
            try {
                System.out.println("Around的before, 方法开始执行");
                joinPoint.proceed(oArr);   //spring使用这个变成代理类来执行目标方法(目标方法本身就不执行了,改用这个执行),可以理解为,把执行方法的那段代码抠出来,换成了这个try catch。这句就是执行方法。
                System.out.println("Around的AfterReturning, 方法正常运行完毕");
            } catch (Throwable throwable) {
                System.out.println("Around的AfterThrowing, 方法抛出异常");
                throwable.printStackTrace();
            }finally {
                System.out.println("Around的After, 方法执行完毕");
            }
    
        }
    
    }

    结果:

    Around的before, 方法开始执行
    目标方法准备运行【Before】
    aop测试。
    Around的AfterReturning, 方法正常运行完毕
    Around的After, 方法执行完毕
    aopTest方法运行了【After】
    目标方法正常运行完毕了【AfterReturning】

    可以看出:

    1. around 执行顺序优先于 其他方法  (因为Around是直接代替了目标方法,而其他方法是检测目标方法的执行过程然后添加。)

    2. around 的after 在  AfterReturning 之前,这是比较正常的, 而其他4种如果全写,after 在  AfterReturning 之后, 执行顺序有问题(Spring的自身bug - -)

  • 相关阅读:
    SQLServer之删除用户自定义数据库用户
    Oracle expdp/impdp导出导入命令及数据库备份
    ORACLE EXP/IMP的使用详解
    《JAVA与模式》之抽象工厂模式
    Oracle中的Temporary tablespace的作用
    Oracle常用函数笔记
    java Map及Map.Entry详解
    LinkedHashMap和HashMap的比较使用
    win7 64系统安装oracle客户端使用PL/SQL Developer工具
    PL/SQL 创建视图语法
  • 原文地址:https://www.cnblogs.com/clamp7724/p/11922469.html
Copyright © 2020-2023  润新知