实验二 Spring AOP
一、 实验目的
1、了解 AOP 的概念和作用;
2、理解 AOP 中的相关术语;
3、了解 Spring 中两种动态代理方式的区别;
4、掌握基于 XML 和注解的 AspectJ 开发。
二、 实验内容
1、按图所示的类图结构,设计接口及其实现类,并完成另外两附加要求:(1)
日志功能:在程序执行期间追踪正在发生的活动(打印出调用的方法,以及参数
的参数值);(2)验证功能:希望计算器只能处理正数的运算,当有负数参与运
算时,给出提示说明。
分别使用基于 XML 和注解的 AspectJ 实现上述功能(创建两个项目)。
public interface ArithmeticCalculator {
public int add(int i,int j);
public int sub(int i,int j);
public int mul(int i,int j);
public int div(int i,int j);}
(1)AeithmeticCalculator 接口:
(2)ArithmeticCalculatorImpl 类:
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
public int add(int i, int j) {
return i+j;
}
public int sub(int i, int j) {
return i-j;
}
public int mul(int i, int j) {
return i*j;
}
public int div(int i, int j) {
return i/j;
}
}
1、基于 xml 的 Aspectj 的编程
1) 切面类:Aspectj
public class Aspect {
public void log(JoinPoint joinPoint, Object result) {
printNum(joinPoint.getArgs());
System.out.println("运行结果为:"+result+"\n");
}
public Object
Throwable {
Around(ProceedingJoinPoint
proceedingJoinPoint)
throws
System.out.println("正在执行的目标方法为:"
+proceedingJoinPoint.getSignature().getName());
if (check(proceedingJoinPoint.getArgs())) {
Object obj = proceedingJoinPoint.proceed();
log(proceedingJoinPoint, obj);}
return -1;
else
return proceedingJoinPoint.proceed();
}
}
2) 打印出参数为负数的方法
public void printFushu(Object[] paramValue) {
System.out.print("输入的参数中有负数: [");
for(int i=0;i
3) 打印出输入参数的方法:
public void printNum(Object[] paramValue) {
System.out.print("输入的参数为:");
for(int i=0;i
new
String xmlPath =
"com/olive/exp2/application.xml";
=
applicationContext
ApplicationContext
ClassPathXmlApplicationContext(xmlPath);
// 1 从 spring 容器获得内容
ArithmeticCalculator arithmeticCalculator =
(ArithmeticCalculator) applicationContext.getBean("arithmeticCalculator");
// 2 执行方法
System.out.println("基于 xml 的 Aspectj:");
arithmeticCalculator.add(9, 5);
arithmeticCalculator.sub(-4, -2);
arithmeticCalculator.mul(2, 3);
arithmeticCalculator.div(24, 5);
6) 测试方法:
public void xmlTest() {
}
运行结果:
2、基于注解的 Aspectj 编程:
还是使用上面的的 AeithmeticCalculator 接口和 ArithmeticCalculatorImpl 类,但是
与基于 xml 注解的不同的是我们需要加上两个注解来给 xml 配置文件扫描。
1) 在接口实现类加入的注解:
@Service
@Repository("arithmeticCalculator")
2) 切面类 AspectJ:
使用的 log(proceedingJoinPoint, obj),printFushu(Object[] paramValue)
printNum(Object[] paramValue) 、check(Object[] paramValue)
都是相同的,故在这里不再重复
public class AspectJ {
@Pointcut("execution(* com.olive.exp2_1.*.*(..))")
private void myPointCut(){}
private Object[] paramvalue;
@Around("myPointCut()")
public Object myAround(ProceedingJoinPoint proceedingJoinPoint)
throws
Throwable {
System.out.println("正在执行的目标方法为:"
+proceedingJoinPoint.getSignature().getName());
if (check(proceedingJoinPoint.getArgs())) {
Object obj = proceedingJoinPoint.proceed();
log(proceedingJoinPoint, obj);
}
else {
return -1;
}
return proceedingJoinPoint.proceed();
}
}
3) Xml 文件的配置:此时只需加入两条语句即可:
4) 测试类:
public class AspectjTest {
@Test
public void xmlTest() {
String xmlPath ="com/olive/exp2_1/application.xml";
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext(xmlPath);
ArithmeticCalculator arithmeticCalculator =
(ArithmeticCalculator) applicationContext.getBean("arithmeticCalculator");
System.out.println("基于注解的 Aspectj:");
arithmeticCalculator.add(9, 5);
arithmeticCalculator.sub(-4, -2);
arithmeticCalculator.mul(2, 3);
arithmeticCalculator.div(24, 5);
}
}
运行结果:
三、实验小结
通过本次实验,了解了 AOP 的概念和作用以及 Spring 中两种动态代理方式
的区别;理解了 AOP 中的相关术语;掌握了基于 XML 和注解的 AspectJ 开发。
如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理实现 AOP ;如果
目标对象实现了接口,可以强制使用 CGLIB 实现 AOP ;如果目标对象没有实现
了接口,必须采用 CGLIB 库,spring 会自动在 JDK 动态代理和 CGLIB 之间转换。
JDK 动态代理只能对实现了接口的类生成代理,而不能针对类;CGLIB 是针对类
实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,因为是继承,所
以该类或方法最好不要声明成 final 。