• AOP in Spring


    AOP in Spring

    是不是已经对包裹在每个业务周围的异常处理、事务管理、性能监控、日志记录等重复出现的代码感到厌倦,那么是时候轮到AOP出场了。不得不承认程序员的惰性有时候会是一件好事(毕竟提高生产率的终极目标是增加休息时间)。有一个统计类的项目,业务过程相当复杂,从输入参数到输出结果,中间会产生大量的临时数据。客户的要求是程序需要记录下每一个中间过程的临时数据,这样方便验证统计过程是否正确。客户以前是程序员,非常迷信封闭式开发并固执地要求了解开发中的每个细节。AOP在他写代码的年代还没有,所以项目组专门为他写了一个演示程序。

      定义一个Aspect类,其中包括切入点表达式和四个通知(@Before、@After、@AfterReturning、@AfterThrowing),并且该类由@Component注入到Spring容器中。

    复制代码
    package com.mmh.aop;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.AfterThrowing;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.springframework.stereotype.Component;
    
    @Component
    @Aspect
    public class Aspector {
    
        private static final String pointCut = "execution(* com.mmh.business.*.*(..))";
    
        @Before(pointCut)
        public void before(JoinPoint joinPoint) {
            System.out.println(joinPoint.getSignature().getName() + ": 开始执行");
        }
    
        @After(pointCut)
        public void after(JoinPoint joinPoint) {
            System.out.println(joinPoint.getSignature().getName() + ": 结束执行");
        }
    
        @AfterReturning(pointcut = pointCut, returning = "result")
        public void logAfterReturning(JoinPoint joinPoint, Object result) {
            System.out.println(joinPoint.getSignature().getName() + " 执行结果: "
                    + result);
        }
    
        @AfterThrowing(pointcut = pointCut, throwing = "error")
        public void logAfterThrowing(JoinPoint joinPoint, Throwable error) {
            System.out.println(joinPoint.getSignature().getName() + " 抛出异常: "
                    + error);
        }
    }
    复制代码

      定义一个模拟业务计算的Calculate类以及两个子业务类,Add和Divide。在实际的商业化项目中最好做这样的分解,努力保持一个类、函数和模块只完成一个任务(Single Responsibility Principle的宗旨)。这样在需求发生变化或算法出现问题时,修改代码的成本会相对较低。

    复制代码
    package com.mmh.business;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    @Component("Calculate")
    public class Calculate {
    
        @Autowired
        private Add addMethod;
        
        @Autowired
        private Divide divideMethod;
        
        public int calculate(int a, int b) {
            return divideMethod.divide(addMethod.add(a, b), b);
        }
    }
    复制代码
    复制代码
    package com.mmh.business;
    
    import org.springframework.stereotype.Component;
    
    @Component("Add")
    public class Add {
        
        public int add(int a, int b) {
            return a + b;
        }
    }
    复制代码
    复制代码
    package com.mmh.business;
    
    import org.springframework.stereotype.Component;
    
    @Component("Divide")
    public class Divide {
    
        public int divide(int a, int b) {
            return a / b;
        }
    }
    复制代码

      写一个简单的测试类让程序运行起来。在程序的输出中可以清楚地看到各个子业务执行情况,这就满足了客户的需求。

    复制代码
    package com.mmh.test;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import com.mmh.business.Calculate;
    
    public class Test {
    
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext(
                    "appContext.xml");
    
            Calculate p = (Calculate) context.getBean("Calculate");
            p.calculate(1, 2);
        }
    }
    // 运行结果:
    /**
    * calculate: 开始执行
    * add: 开始执行
    * add: 结束执行
    * add 执行结果: 3
    * divide: 开始执行
    * divide: 结束执行
    * divide 执行结果: 1
    * calculate: 结束执行
    * calculate 执行结果: 1
    */
    复制代码

      最后还是要把Spring配置好,让它为我们提供优秀的服务。因为在这个演示程序中使用的是注解的方式向Spring容器中注入Bean,也用注解的方式配置AOP,所以配置文件相当简单。这种简单的方式是否在任何应用场景中都适用呢?当然不是,这种方式缺乏灵活性,需求变化时,开发人员必须要修改代码以及编译代码。

    复制代码
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           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/context
               http://www.springframework.org/schema/context/spring-context.xsd
               http://www.springframework.org/schema/aop
               http://www.springframework.org/schema/aop/spring-aop.xsd">
               
        <context:component-scan base-package="com.mmh" />
        
        <aop:aspectj-autoproxy />
    
    </beans>
    复制代码
  • 相关阅读:
    C语言 gets
    Android、iOS和Windows Phone中的推送技术
    Android的init过程(二):初始化语言(init.rc)解析
    Java向前引用容易出错的地方
    kears库中对样本图片resize的原理(target_size)
    gis python地理处理工具案例教程-字段多值批量替换综合案例
    arcpy地理处理工具案例教程-批量字段值替换
    arcpy地理处理工具案例教程-将满足条件的要素的字段值进行替换
    Keras split train test set when using ImageDataGenerator
    坐标转换7参数计算工具——arcgis 地理处理工具案例教程
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3222357.html
Copyright © 2020-2023  润新知