• Spring学习之旅(七)基于XML配置与基于AspectJ注解配置的AOP编程比较


    本篇博文用一个稍复杂点的案例来对比一下基于XML配置与基于AspectJ注解配置的AOP编程的不同。

    相关引入包等Spring  AOP编程准备,请参考小编的其他博文,这里不再赘述。

    案例要求:

    写一个简单的实现四则运算的计算器。

    加入AOP功能:日志功能;检测参数中是否有负数的功能。

    废话不多说了,直接上代码:

    (一)基于XML配置:

    定义了一个接口类:

    package com.edu.aop;
    
    public interface ArithmeticCalculator {
    
        int add(int i,int j);
        int sub(int i,int j);
        int mul(int i,int j);
        int div(int i,int j);
    }

    实现类:

    package com.edu.aop;
    
    public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
    
        @Override
        public int add(int i, int j) {
            return i+j;
        }
    
        @Override
        public int sub(int i, int j) {
            return i-j;
        }
    
        @Override
        public int mul(int i, int j) {
            return i*j;
        }
    
        @Override
        public int div(int i, int j) {
            return i/j;
        }
    
    }

    日志切片类:

    package com.edu.aop;
    
    import java.util.Arrays;
    
    import org.aspectj.lang.JoinPoint;
    
    public class LoggingAspect {
    /**
     * 日志切面类
     */
        
        public void beforeMethod(JoinPoint joinPoint){
            //获取方法名
            String methodName=joinPoint.getSignature().getName();
            //获取方法实参值列表
            Object[] args=joinPoint.getArgs();
            System.out.println("The method "+methodName+" begin with "+Arrays.asList(args));
        }
        
        public void afterMethod(JoinPoint joinPoint){
            String methodName=joinPoint.getSignature().getName();
            System.out.println("The method "+methodName+" ends");
        }
    }

    检测参数中是否有负数的切片类:

    package com.edu.aop;
    
    import java.util.Arrays;
    
    import org.aspectj.lang.JoinPoint;
    
    public class ValidationAspect {
    
        public void validationArgs(JoinPoint joinPoint){
            String methodName=joinPoint.getSignature().getName();
            Object[] args=joinPoint.getArgs();
            System.out.println("待验证参数:"+Arrays.asList(args));
            if(args!=null&&args.length>0){
                for(int i=0;i<args.length;++i){
                    if(((Integer)args[i]).intValue()<0){
                        System.out.println("警告:方法"+methodName+"()第"+(i+1)+"个参数为负数:"+args[i]);
                    }
                }
            }
        }
    }

    xml配置文件applicationContext.xml:

    <?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: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 -->
    <bean id="arithmetic" class="com.edu.aop.ArithmeticCalculatorImpl"></bean>
    
    <!-- 分别将切面类声明配置成一个bean -->
    <bean id="logging" class="com.edu.aop.LoggingAspect"></bean>
    <bean id="validation" class="com.edu.aop.ValidationAspect"></bean>
    
    <aop:config>
    <!-- 配置日志切片类 -->
    <aop:aspect ref="logging" order="2">
    <!-- 配置前置通知 及前置通知的切入点-->
    <aop:before method="beforeMethod" pointcut="execution(* com.edu.aop.ArithmeticCalculatorImpl.*(..))"></aop:before>
    <!-- 配置后置通知及后置通知的切入点 -->
    <aop:after method="afterMethod" pointcut="execution(* com.edu.aop.ArithmeticCalculatorImpl.*(..))"></aop:after>
    </aop:aspect>
    
    <!-- 配置检测参数切片类 -->
    <aop:aspect ref="validation" order="1">
    <!-- 配置前置通知 及前置通知的切入点-->
    <aop:before method="validationArgs" pointcut="execution(* com.edu.aop.ArithmeticCalculatorImpl.*(..))"></aop:before>
    </aop:aspect>
    </aop:config>
    </beans>

    主方法检测类:

    package com.edu.aop;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class Main {
    
        public static void main(String[] args) {
    
            ApplicationContext act=new ClassPathXmlApplicationContext("applicationContext.xml");
            ArithmeticCalculator arithmetic=(ArithmeticCalculator)act.getBean("arithmetic");
            int result=arithmetic.add(10, 20);
            System.out.println("result:"+result);
            result=arithmetic.div(-36, 4);
            System.out.println("result:"+result);
        }
    
    }

    运行结果:

    (二)基于AspectJ注解配置的AOP编程:

    直接上代码:

    接口类定义同上。

    xml配置文件applicationContext.xml:

    <?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:aop="http://www.springframework.org/schema/aop"
        xmlns:context="http://www.springframework.org/schema/context"
        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
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">
    
    <!-- 自动扫描的包,实现对注解Bean的管理 -->
    <context:component-scan base-package="com.edu.aop"></context:component-scan>
    <!-- 使Aspect的注解起作用,从而实现:自动为匹配的类生成代理 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    </beans>

    接口实现类:

    package com.edu.aop;
    
    import org.springframework.stereotype.Component;
    
    //@Component 注解Bean,并设定其名称为arithmetic
    @Component("arithmetic")
    public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
    
        @Override
        public int add(int i, int j) {
            return i+j;
        }
    
        @Override
        public int sub(int i, int j) {
            return i-j;
        }
    
        @Override
        public int mul(int i, int j) {
            return i*j;
        }
    
        @Override
        public int div(int i, int j) {
            return i/j;
        }
    
    }

    日志切片类:

    package com.edu.aop;
    
    import java.util.Arrays;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    
    //注释声明切面,切面的名称为默认名称(loggingAspect)(即类名首字母小写)
    @Order(2)        //注释切面的优先级别,数字越小,级别越高
    @Aspect            //@Aspect 注解声明该Bean是个切面
    @Component        //@Component 注解Bean,默认名称为loggingAspect
    public class LoggingAspect {
    /**
     * 日志切面类
     */
        //注释“前置通知”及其切入点
        @Before("execution(public int com.edu.aop.ArithmeticCalculator.add(int,int))")
        public void beforeMethod(JoinPoint joinPoint){
            //获取方法名
            String methodName=joinPoint.getSignature().getName();
            //获取方法实参值列表
            Object[] args=joinPoint.getArgs();
            System.out.println("The method "+methodName+" begin with "+Arrays.asList(args));
        }
        
        //注解“后置通知”及其切入点
        @After("execution(* com.edu.aop.ArithmeticCalculator.*(..))")
        public void afterMethod(JoinPoint joinPoint){
            String methodName=joinPoint.getSignature().getName();
            System.out.println("The method "+methodName+" ends");
        }
    }

    检测参数中是否有负数的切片类:

    package com.edu.aop;
    
    import java.util.Arrays;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    
    //注释声明切面,切面的名称为默认名称(loggingAspect)(即类名首字母小写)
    @Order(1)    //注解切面的优先级别,数字越小,级别越高
    @Aspect        //注解为一个切面
    @Component    //注解为一个Bean组件,默认名称为validationAspect
    public class ValidationAspect {
    
        //注解为前置通知,并注解其切入点表达式
        @Before("execution(* com.edu.aop.ArithmeticCalculator.*(..))")
        public void validationArgs(JoinPoint joinPoint){
            String methodName=joinPoint.getSignature().getName();
            Object[] args=joinPoint.getArgs();
            System.out.println("待验证参数:"+Arrays.asList(args));
            if(args!=null&&args.length>0){
                for(int i=0;i<args.length;++i){
                    if(((Integer)args[i]).intValue()<0){
                        System.out.println("警告:方法"+methodName+"()第"+(i+1)+"个参数为负数:"+args[i]);
                    }
                }
            }
        }
    }

    主方法检测类同上。

    运行结果:

    由以上案例的两个版本,可以看到两种AOP编程方式在设计思想和设计过程基本一致,只不过,“基于XML的AOP编程”是将配置Bean、切面、通知等操作放在了配置文件中。而“基于AspectJ的AOP编程”则是将这些配置信息放在了源码中,只在配置文件中配置了“AspectJ的注解支持”(即空的<aop:aspectj-autoproxy>元素)和自动扫描的包的支持。

  • 相关阅读:
    BZOJ4569: [Scoi2016]萌萌哒
    BZOJ4566: [Haoi2016]找相同字符
    BZOJ4556: [Tjoi2016&Heoi2016]字符串
    BZOJ4545: DQS的trie
    BZOJ4458: GTY的OJ
    Codeforces Beta Round #19E. Fairy
    不确定性推理
    朴素贝叶斯
    对抗搜索
    struct
  • 原文地址:https://www.cnblogs.com/dudududu/p/8487750.html
Copyright © 2020-2023  润新知