zoukankan      html  css  js  c++  java
  • 6.spring:AOP(注解)

     spring Aop

     AOP面向切面编程,与OOP面向对象编程相辅相成

    AOP中最基本的单元是切面

    问题:
    代码混乱:越来越多的业务需求(日志&验证)加入后,原有的业务方法急剧膨胀,每个方法在处理核心代码的同时还必须兼顾其他的多个关注点
    代码分散,以日志为例,知识为了满足这一单一的需求,就不得不在代码块中里多次调用重复的日志代码,如果日志发生变化,必须修改所有的模块

    简介:
    AOP:面向切面编程,是一种新的方法,式传统OOP面向对象编程的补充
    AOP主要编程对象是切面,而切面模块化横切的关注点

    在应用AOP编程时,仍需要定义公共的功能,但可以明确定义的功能在哪,以什么方式应用,并且不必修改影响的类,这样横切关注点就被模块化到特殊的
    对象(切面)里

    AOP的好处:
    ->每个事物逻辑位于一个位置,代码不分散,便于维护
    ->业务模块化更简洁,只包含核心的业务代码

    AOP术语:
    切面(Aspect):横切关注点被模块化的特殊对象
    通知(Advice):切换必须完成的工作
    目标(Target):被通知的对象
    代理(Proxy):向目标对象应用的通知之后创建的对象
    连接点(Joinpoint):程序执行的特定位置
    切点(pointcut):每个类都有若干个连接点,
    AOP即使通过定位到特定的连接点

    每次做方法的时候,都在执行之前和之后都有相关的打印操作!
    AtithmeticCalculator.java
    public interface AtithmeticCalculator {
        int add(int i,int j);
        int sub(int i,int j);
        int mul(int i,int j);
        int div(int i,int j);
    }

     AtithmeticCalculatorImp.java

    接口中方法的实现。

    @Component
    public class AtithmeticCalculatorImp implements AtithmeticCalculator{
        public int add(int i, int j) {
            int res = i + j;
            return res;
        }
        public int sub(int i, int j) {
            int res = i - j;
            return res;
        }
        public int mul(int i, int j) {
            int res = i * j;
            return res;
        }
        public int div(int i, int j) {
            int res = i / j;
            return res;
        }
    }
    LoggionAspect.java
    切面类
    //把这个类升级称为一个切面:返给到IOC容器中---->在声明为一个注解
    @Order(2) @Aspect @Component public class LoggionAspect { @Before("execution(public * com.MrChengsc.AOP.AtithmeticCalculator.*(..))") public void beforeMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); Object [] args = joinPoint.getArgs(); System.out.println("The method " + methodName + " begins with " + Arrays.asList(args)); } /** * 在方法执行之后执行的代码. 无论该方法是否出现异常 */ @After("execution(public * com.MrChengsc.AOP.AtithmeticCalculator.*(..))") public void afterMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method " + methodName + " ends"); } /** * 在方法法正常结束受执行的代码 * 返回通知是可以访问到方法的返回值的! */ @AfterReturning(value="execution(public * com.MrChengsc.AOP.AtithmeticCalculator.*(..))", returning="result") public void afterReturning(JoinPoint joinPoint, Object result){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method " + methodName + " ends with " + result); } /** * 在目标方法出现异常时会执行的代码. * 可以访问到异常对象; 且可以指定在出现特定异常时在执行通知代码 */ @AfterThrowing(value="execution(public * com.MrChengsc.AOP.AtithmeticCalculator.*(..))",throwing="e") public void afterThrowing(JoinPoint joinPoint, Exception e){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method " + methodName + " occurs excetion:" + e); } //环绕通知 //需要携带ProceedingJoinPoint这个类型的参数 //环绕通知类似动态代理的全类名:ProceedingJoinPoint可以绝对是否执行目标方法 //必须要有返回值,返回值即为目标方法的返回值 // @Around("execution(public * com.MrChengsc.AOP.AtithmeticCalculator.*(..))") // public Object aroundMethod(ProceedingJoinPoint proceedingJoinPoint){ // System.out.println("@Around"); // //返回值 // Object result = null; // //前置通知 // String methodName = proceedingJoinPoint.getSignature().getName(); // try { // //前置通知 // System.out.println("The methodName:" + methodName + " _The args :" + Arrays.asList(proceedingJoinPoint.getArgs())); // //执行目标方法 // result = proceedingJoinPoint.proceed(); // //后置通知 // System.out.println("End result:" + result); // } catch (Throwable e) { // //e.printStackTrace(); // //异常通知 // System.out.println("Exception:" + e); // } // //后置通知 // System.out.println("End..."); // //返回值 // return result; // } }
    LoggionAspect2.java
    切面类2
    //把这个类升级称为一个切面:返给到IOC容器中---->在声明为一个注解
    @Order(1)
    @Aspect
    @Component
    public class LoggionAspect2 {
        
        //定义一个方法用于切点表达式
        //一般的该方法不需要填入其他的代码
        @Pointcut("execution(public * com.MrChengsc.AOP.AtithmeticCalculator.*(..))")
        public void declareJointPointExpression(){    }
        
    @Before(
    "declareJointPointExpression()") public void beforeMethod1(JoinPoint joinPoint){ System.out.println("--->beforeMethod1"); String methodName = joinPoint.getSignature().getName(); Object [] args = joinPoint.getArgs(); System.out.println("The method " + methodName + " begins with " + Arrays.asList(args)); System.out.println("--->beforeMethod1"); } /** * 在方法执行之后执行的代码. 无论该方法是否出现异常 */ @After("declareJointPointExpression()") public void afterMethod1(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method " + methodName + " ends"); } /** * 在方法法正常结束受执行的代码 * 返回通知是可以访问到方法的返回值的! */ @AfterReturning(value="declareJointPointExpression())", returning="result") public void afterReturning1(JoinPoint joinPoint, Object result){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method " + methodName + " ends with " + result); } /** * 在目标方法出现异常时会执行的代码. * 可以访问到异常对象; 且可以指定在出现特定异常时在执行通知代码 */ @AfterThrowing(value="declareJointPointExpression()",throwing="e") public void afterThrowing1(JoinPoint joinPoint, Exception e){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method " + methodName + " occurs excetion:" + e); } //环绕通知 //需要携带ProceedingJoinPoint这个类型的参数 //环绕通知类似动态代理的全类名:ProceedingJoinPoint可以绝对是否执行目标方法 //必须要有返回值,返回值即为目标方法的返回值 // @Around("execution(public * com.MrChengsc.AOP.AtithmeticCalculator.*(..))") // public Object aroundMethod(ProceedingJoinPoint proceedingJoinPoint){ // System.out.println("@Around"); // //返回值 // Object result = null; // //前置通知 // String methodName = proceedingJoinPoint.getSignature().getName(); // try { // //前置通知 // System.out.println("The methodName:" + methodName + " _The args :" + Arrays.asList(proceedingJoinPoint.getArgs())); // //执行目标方法 // result = proceedingJoinPoint.proceed(); // //后置通知 // System.out.println("End result:" + result); // } catch (Throwable e) { // //e.printStackTrace(); // //异常通知 // System.out.println("Exception:" + e); // } // //后置通知 // System.out.println("End..."); // //返回值 // return result; // } }

     applicationContext.xml

    <!-- 配置自动扫描的包 -->
    <context:component-scan base-package="com.MrChengsc.AOP"></context:component-scan>
    <!-- 前置通知,使切面里的注解起作用 -->
    <!-- 使AspectJ注解起作用:自动为匹配的类生成代理效果 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

     main:

        public static void main(String[] args) {
    //        AtithmeticCalculator atithmeticCalculator = null;
    //        atithmeticCalculator = new AtithmeticCalculatorImp();
    //        
    //        atithmeticCalculator.add(1, 3);
    //        System.out.println("---");
    //        atithmeticCalculator.sub(3, 1);
    //        System.out.println("---");
    //        atithmeticCalculator.mul(1, 3);
    //        System.out.println("---");
    //        atithmeticCalculator.div(10, 2);
    //        System.out.println("---");
            
            
            ApplicationContext ctx = new 
                    ClassPathXmlApplicationContext("AOPContext.xml");
            //强制的类型使用接口的类型
            AtithmeticCalculator atithmeticCalculator = (AtithmeticCalculator) ctx.getBean(AtithmeticCalculator.class);
            
            int res = atithmeticCalculator.add(3, 6);
            System.out.println("res:" + res);
            System.out.println("-----");
    //        int res1 = atithmeticCalculator.mul(2, 3);
    //        System.out.println("res1:" + res1);
            
            //异常代码的测试
    //        int res2 = atithmeticCalculator.div(10, 0);
    //        System.out.println("res2:" + res2);
            
            
        }

    执行的顺序以及结果:

    --->beforeMethod1
    The method add begins with [3, 6]
    --->beforeMethod1
    The method add begins with [3, 6]
    The method add ends
    The method add ends with 9
    The method add ends
    The method add ends with 9
    res:9
    -----

    注:

    1.首先需要在xml文件中进行包的扫描<context:component-scan>

    2.使切面的注解起作用:<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

    3.使用@Component在要进行处理的类、切面类上

    4.使用@Aspect进行标注切面类

    5.使用 @Before()在方法上作为前置通知

    6. 使用@After()在方法上作为后置通知,无论该方法是否出现异常

    7. 使用@AfterReturning(value="",returning=""),正常结束后那倒返回值

    8.使用 @AfterThrowing(value="",throwing=""),在执行发生异常时,那倒异常信息

    9.使用@Around()作为环绕通知,使用比较少

    10.使用@Pointcut()放在空方法上,作为切点表达式,引用切点直接使用方法名

    11.使用@Order(1)放在类上指定切面的优先级,数值越小优先级越高

    12.@After("execution(public * com.MrChengsc.AOP.AtithmeticCalculator.*(..))")

       *:代表所有,任意的

      ..:代表任意的形参

    AOP的实现都有这个符号!

  • 相关阅读:
    HDOJ 5414 CRB and String 模拟
    Python标准库:内置函数all(iterable)
    Can not find a java.io.InputStream with the name [downloadFile] in the invocation stack.
    关于TabLayout+ViewPager组合实现多页面滑动
    互联网产品经理应该具备的技能(需求篇)
    【Android】利用自己定义View的重绘实现拖动移动,获取组件的尺寸
    mybatis自己主动生成mapper,dao,映射文件
    Java解析注解
    如日中天的Uber到底是用什么开发语言做到的?
    [Swift]LeetCode1002. 查找常用字符 | Find Common Characters
  • 原文地址:https://www.cnblogs.com/Mrchengs/p/10093490.html
Copyright © 2011-2022 走看看