之前,aop是通过注解的方式,在resources文件夹下定义了applicationContext.xml配置文件:
- "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.zhoulz">context:component-scan>
-
-
- <aop:aspectj-autoproxy>aop:aspectj-autoproxy>
-
-
- beans>
下面介绍aop的xml配置文件的方式:
同样在resources文件夹下定义了aop.xml配置文件:
- "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 id="logUtil" class="com.zhoulz.util.LogUtil" >bean>
- <bean id="securityUtil" class="com.zhoulz.util.SecurityUtil">bean>
-
-
-
- <bean id="myCalculator" class="com.zhoulz.service.MyCalculator">bean>
-
-
-
- <aop:config>
-
- <aop:pointcut id="globalPoint" expression="execution(public Integer com.zhoulz.service.MyCalculator.*(..))"/>
-
-
- <aop:aspect ref="logUtil">
-
-
- <aop:pointcut id="myPoint" expression="execution(public Integer com.zhoulz.service.MyCalculator.*(..))"/>
-
-
-
-
- <aop:before method="start" pointcut-ref="myPoint">aop:before>
-
- <aop:after method="logFinally" pointcut-ref="myPoint">aop:after>
- <aop:after-returning method="stop" pointcut-ref="myPoint" returning="result">aop:after-returning>
- <aop:after-throwing method="logException" pointcut-ref="myPoint" throwing="e">aop:after-throwing>
- <aop:around method="around" pointcut-ref="myPoint">aop:around>
- aop:aspect>
-
-
- <aop:aspect ref="securityUtil">
- <aop:before method="start" pointcut-ref="myPoint">aop:before>
- <aop:after method="logFinally" pointcut-ref="myPoint">aop:after>
- <aop:after-returning method="stop" pointcut-ref="myPoint" returning="result">aop:after-returning>
- <aop:after-throwing method="logException" pointcut-ref="globalPoint" throwing="e">aop:after-throwing>
- <aop:around method="around" pointcut-ref="globalPoint">aop:around>
- aop:aspect>
-
- aop:config>
-
- beans>
代码示例: —— 注意,相关注解已取消
参考:11 - Spring AOP介绍与使用2 - 简单配置_哆啦A梦的_梦的博客-CSDN博客
基本相同。
Calculator接口:
- package com.zhoulz.service;
-
- import org.springframework.stereotype.Service;
- //@Service
- public interface Calculator {
-
- public Integer add(Integer i,Integer j) throws NoSuchMethodException;
- public Integer sub(Integer i,Integer j) throws NoSuchMethodException;
- public Integer mul(Integer i,Integer j) throws NoSuchMethodException;
- public Integer div(Integer i,Integer j) throws NoSuchMethodException;
- }
MyCalculator 类:
- package com.zhoulz.service;
-
- import com.zhoulz.util.LogUtil;
- import org.springframework.stereotype.Service;
-
- import java.lang.reflect.Method;
-
- //@Service
- public class MyCalculator /*implements Calculator */{
-
- public Integer add(Integer i, Integer j) throws NoSuchMethodException {
- //现在,想添加日志的输出功能,怎么做?
- //最简单的做法:在每行代码里面都做一个最基本的输出 —— 但是这样做效率太低了
- //System.out.prIntegerln("add方法开始执行,参数是:" + i + "----" + j );
- //改进: —— 定义一个LogUtil类(包含start()方法和stop()方法)
-
- //通过反射
- /*Method add = MyCalculator.class.getMethod("add", Integer.class, Integer.class);
- //然后add传入到下面的方法中 —— 下面的都同理
- LogUtil.start(add,i,j);*/
- Integer result = i + j;
- //System.out.prIntegerln("add方法执行结束,结果是:" + result);
- //LogUtil.stop(add,result);
- return result;
- }
-
- public Integer sub(Integer i, Integer j) throws NoSuchMethodException {
- //System.out.prIntegerln("sub方法开始执行,参数是:" + i + "----" + j );
- /*Method sub = MyCalculator.class.getMethod("sub", Integer.class, Integer.class);
- LogUtil.start(sub,i,j);*/
- Integer result = i - j;
- //System.out.prIntegerln("sub方法执行结束,结果是:" + result);
- //LogUtil.stop(sub,result);
- return result;
- }
-
- public Integer mul(Integer i, Integer j) throws NoSuchMethodException {
- //System.out.prIntegerln("mul方法开始执行,参数是:" + i + "----" + j );
- //Method mul = MyCalculator.class.getMethod("mul", Integer.class, Integer.class);
- //LogUtil.start(mul,i,j);
- Integer result = i * j;
- //System.out.prIntegerln("mul方法执行结束,结果是:" + result);
- //LogUtil.stop(mul,result);
- return result;
- }
-
- public Integer div(Integer i, Integer j) throws NoSuchMethodException {
- //System.out.prIntegerln("div方法开始执行,参数是:" + i + "----" + j );
- //Method div = MyCalculator.class.getMethod("div", Integer.class, Integer.class);
- //LogUtil.start(div,i,j);
- Integer result = i / j;
- //System.out.prIntegerln("div方法执行结束,结果是:" + result);
- //LogUtil.stop(div,result);
- return result;
- }
-
- //再加一个方法
- public Integer show(Integer i, Double j){
- System.out.println("show ........");
- return i;
- }
-
- }
util文件夹下,两个切面类:LogUtil、SecurityUtil
- package com.zhoulz.util;
-
- import com.zhoulz.service.Calculator;
- import org.aspectj.lang.JoinPoint;
- import org.aspectj.lang.ProceedingJoinPoint;
- import org.aspectj.lang.Signature;
- import org.aspectj.lang.annotation.*;
- import org.springframework.core.annotation.Order;
- import org.springframework.stereotype.Component;
-
- import java.lang.reflect.Method;
-
- import java.util.Arrays;
-
- //@Aspect
- //@Component
- //@Order(200)
- public class LogUtil {
-
- //如果有多个匹配的表达式相同,能否做抽象?可以
- // : 定义一个没有返回值的空方法,给该方法添加@Pointcut注解,后续在使用(匹配表达式)的时候直接调用该方法名称
- // 此处的方法只是起一个声明的作用,能够供内部的其他通知方法进行调用
- @Pointcut("execution(public Integer com.zhoulz.service.MyCalculator.*(Integer,*))")
- public void myPointCut(){} // —— 然后后面用的时候直接写:myPointCut() 即可
- //还可以定义多个
- @Pointcut("execution(* *(..))")
- public void myPointCut2(){}
-
-
- @Before("execution(public Integer com.zhoulz.service.M*Calculator.*(Integer,*))")
- //public static void start(Method method,Object ... args){ //原来的写法 //方法里面暂时不用传入参数
- public static void start(JoinPoint joinPoint){
- //获取方法签名
- Signature signature = joinPoint.getSignature();
- //获取方法参数信息
- Object[] args = joinPoint.getArgs();
- //获取方法名称
- //System.out.println(signature.getName());
- System.out.println("Log----"+signature.getName()+"方法开始执行,参数是:" +Arrays.asList(args));
- }
-
- //@AfterReturning(value = "execution(public Integer com.zhoulz.service.MyCalculator.*(Integer,*))",returning = "result")
- //匹配表达式进行了抽象,见上面的 myPointCut()方法
- @AfterReturning(value = "myPointCut()",returning = "result")
- public static void stop(JoinPoint joinPoint,Object result){ // —— 怎么加结果result?:上面的通知注解要改动
- Signature signature = joinPoint.getSignature();
- System.out.println("Log----"+signature.getName()+"方法执行结束,结果是:" +result);
- }
-
- @AfterThrowing(value = "myPointCut()",throwing = "e")
- public static void logException(JoinPoint joinPoint,Exception e){
- Signature signature = joinPoint.getSignature();
- System.out.println("Log----"+signature.getName()+"方法抛出异常:" + e.getMessage());
- }
-
- @After("myPointCut2()")
- public static void logFinally(JoinPoint joinPoint){
- Signature signature = joinPoint.getSignature();
- System.out.println("Log----"+signature.getName()+"方法执行结束。。。。over");
- }
-
- //环绕通知 —— 把上面4个通知任意拿过来执行
- @Around("myPointCut2()")
- public Object around(ProceedingJoinPoint pjp) throws Throwable { //需要传参
- Signature signature = pjp.getSignature();
- Object[] args = pjp.getArgs();
-
- Object result = null;
- try {
- System.out.println("Log----"+"环绕通知start:"+signature.getName()+"方法开始执行,参数为:"+ Arrays.asList(args));
- //通过反射的方式调用目标的方法,相当于执行method.invoke(),可以自己修改结果值
- result = pjp.proceed(args);
- //result = 100;
- System.out.println("Log----"+"环绕通知stop:"+signature.getName()+"方法执行结束了");
- } catch (Throwable throwable) {
- //throwable.printStackTrace();
- System.out.println("Log----"+"环绕异常通知:"+signature.getName()+"出现异常了");
- throw throwable;
- }finally {
- System.out.println("Log----"+"环绕返回通知:"+signature.getName()+"方法返回结果是:"+result);
- }
- return result;
- }
- }
- package com.zhoulz.util;
-
- import org.aspectj.lang.JoinPoint;
- import org.aspectj.lang.ProceedingJoinPoint;
- import org.aspectj.lang.Signature;
- import org.aspectj.lang.annotation.*;
- import org.springframework.core.annotation.Order;
- import org.springframework.stereotype.Component;
-
- import java.util.Arrays;
-
- /*@Aspect
- @Component
- @Order(100)*/
- public class SecurityUtil {
- //如果有多个匹配的表达式相同,能否做抽象?可以
- // : 定义一个没有返回值的空方法,给该方法添加@Pointcut注解,后续在使用(匹配表达式)的时候直接调用该方法名称
- // 此处的方法只是起一个声明的作用,能够供内部的其他通知方法进行调用
- @Pointcut("execution(public Integer com.zhoulz.service.MyCalculator.*(Integer,*))")
- public void myPointCut(){} // —— 然后后面用的时候直接写:myPointCut() 即可
- //还可以定义多个
- @Pointcut("execution(* *(..))")
- public void myPointCut2(){}
-
-
- @Before("execution(public Integer com.zhoulz.service.M*Calculator.*(Integer,*))")
- //public static void start(Method method,Object ... args){ //原来的写法 //方法里面暂时不用传入参数
- public static void start(JoinPoint joinPoint){
- //获取方法签名
- Signature signature = joinPoint.getSignature();
- //获取方法参数信息
- Object[] args = joinPoint.getArgs();
- //获取方法名称
- //System.out.println(signature.getName());
- System.out.println("Security----"+signature.getName()+"方法开始执行,参数是:" +Arrays.asList(args));
- }
-
- //@AfterReturning(value = "execution(public Integer com.zhoulz.service.MyCalculator.*(Integer,*))",returning = "result")
- //匹配表达式进行了抽象,见上面的 myPointCut()方法
- @AfterReturning(value = "myPointCut()",returning = "result")
- public static void stop(JoinPoint joinPoint, Object result){ // —— 怎么加结果result?:上面的通知注解要改动
- Signature signature = joinPoint.getSignature();
- System.out.println("Security----"+signature.getName()+"方法执行结束,结果是:" +result);
- }
-
- @AfterThrowing(value = "myPointCut()",throwing = "e")
- public static void logException(JoinPoint joinPoint,Exception e){
- Signature signature = joinPoint.getSignature();
- System.out.println("Security----"+signature.getName()+"方法抛出异常:" + e.getMessage());
- }
-
- @After("myPointCut2()")
- public static void logFinally(JoinPoint joinPoint){
- Signature signature = joinPoint.getSignature();
- System.out.println("Security----"+signature.getName()+"方法执行结束。。。。over");
- }
-
- //环绕通知 —— 把上面4个通知任意拿过来执行
- @Around("myPointCut2()")
- public Object around(ProceedingJoinPoint pjp) throws Throwable { //需要传参
- Signature signature = pjp.getSignature();
- Object[] args = pjp.getArgs();
-
- Object result = null;
- try {
- System.out.println("Security----"+"环绕通知start:"+signature.getName()+"方法开始执行,参数为:"+ Arrays.asList(args));
- //通过反射的方式调用目标的方法,相当于执行method.invoke(),可以自己修改结果值
- result = pjp.proceed(args);
- //result = 100;
- System.out.println("Security----"+"环绕通知stop:"+signature.getName()+"方法执行结束了");
- } catch (Throwable throwable) {
- //throwable.printStackTrace();
- System.out.println("Security----"+"环绕异常通知:"+signature.getName()+"出现异常了");
- throw throwable;
- }finally {
- System.out.println("Security----"+"环绕返回通知:"+signature.getName()+"方法返回结果是:"+result);
- }
- return result;
- }
- }
测试类:—— 注意:切换到 aop.xml (原来是 applicationContext.xml )
- import com.zhoulz.service.Calculator;
- import com.zhoulz.service.MyCalculator;
- import org.junit.Test;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
-
- public class MyTest {
- //ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
- //采用xml配置文件的方式,一定要注意切换到aop.xml
- ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("aop.xml");
-
- @Test
- public void test01() throws NoSuchMethodException {
- //ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
- //Calculator calculator = context.getBean("myCalculator", Calculator.class);
- //或者直接写
- //Calculator calculator = context.getBean(Calculator.class);
- //取消MyCalculator对Calculator的继承,再测试 —— 结果正常(即没有接口实现的话,则用的是cglib进行动态代理)
- MyCalculator calculator = context.getBean(MyCalculator.class);
- calculator.add(10,2);
- // calculator.sub(10,2);
- calculator.div(10,0);
- calculator.show(10,2.5);
- //System.out.println(calculator.getClass()); //class com.sun.proxy.$Proxy24
- //取消继承后,结果为:class com.zhoulz.service.MyCalculator$$EnhancerBySpringCGLIB$$77df863d
- }
-
- @Test
- public void test02() throws NoSuchMethodException {
- MyCalculator calculator = context.getBean(MyCalculator.class);
- //calculator.add(10,2);
- calculator.div(10,2);
- }
- }
结果:
Log----div方法开始执行,参数是:[10, 2]
Log----环绕通知start:div方法开始执行,参数为:[10, 2]
Security----div方法开始执行,参数是:[10, 2]
Security----环绕通知start:div方法开始执行,参数为:[10, 2]
Security----环绕通知stop:div方法执行结束了
Security----环绕返回通知:div方法返回结果是:5
Security----div方法执行结束,结果是:5
Security----div方法执行结束。。。。over
Log----环绕通知stop:div方法执行结束了
Log----环绕返回通知:div方法返回结果是:5
Log----div方法执行结束,结果是:5
Log----div方法执行结束。。。。over