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);
} }

运行结果:

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

(二)基于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]);
}
}
}
}
}

主方法检测类同上。

运行结果:

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

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

上一篇:JAVA Spring 事物 ( 已转账为例 ) 基于 AOP 注解


下一篇:[九度OJ]1008.最短路径问题