1.AOP方式
1.1 Schema-based 方式(上篇有写)
1.2.AspectJ
1.2.1 每个通知不需要实现接口或类
1.2.2 配置 spring 配置文件是在<aop:config>的子标签<aop:aspect>中配置
AOP配置元素 | 描述 ------------ | ------------- `<aop:advisor>` | 定义AOP通知器 `<aop:after>` | 定义AOP后置通知(不管该方法是否执行成功) `<aop:after-returning>` | 在方法成功执行后调用通知 `<aop:after-throwing>` | 在方法抛出异常后调用通知 `<aop:around>` | 定义AOP环绕通知 `<aop:aspect>` | 定义切面 `<aop:aspect-autoproxy>` | 定义`@AspectJ`注解驱动的切面 `<aop:before>` | 定义AOP前置通知 `<aop:config>` | 顶层的AOP配置元素,大多数的<aop:*>包含在<aop:config>元素内 `<aop:declare-parent>` | 为被通知的对象引入额外的接口,并透明的实现 `<aop:pointcut>` | 定义切点
1.2.3 使用AspectJ方式配置
1.2.3.1在 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"> <!-- 配置 Demo 类,测试使用 --> <bean id="demo" class="com.suncl.test.Demo"></bean> <bean id="myadvice" class="com.suncl.model.MyAdvice" ></bean> <aop:config> <aop:aspect ref="myadvice"> <aop:pointcut expression="execution(* com.suncl.test.Demo.demo1(..)) " id="mypoint"/> <!--执行前置通知--> <aop:before method="beforeLog" pointcut-ref="mypoint" /> <!-- <aop:after/> 后置通知,是否出现异常都执行 --> <aop:after method="afterLog" pointcut-ref="mypoint"/> <!--<aop:after-returing/> 后置通知,只有当切点正确执行时执行--> <aop:after-returning method="afterReturningLog" pointcut-ref="mypoint"/> <!-- <aop:after-throwing 后置通知,只有当切点错误执行的时候执行--> <aop:after-throwing method="afterThrowingLog" pointcut-ref="mypoint"/> <!--环绕通知--> <aop:around method="aroundLog" pointcut-ref="mypoint" /> </aop:aspect> </aop:config> </beans>
1.2.3.2实体类
package com.suncl.test; /** * Created by SCL-PC on 2019/2/28. */ public class Demo { public void demo(){ System.out.println("执行了demo方法"); } public void demo1(String a ,int b){ System.out.println("执行了demo1111方法"); //用来验证出现错误的时候切点执行情况 // int i = 5/0; } }
package com.suncl.model; import org.aspectj.lang.ProceedingJoinPoint; /** * Created by SCL-PC on 2019/3/3. */ public class MyAdvice { public void beforeLog() { System.out.println("开始执行前置通知 日志记录"); } // 方法执行完后通知 public void afterLog() { System.out.println("开始执行后置通知 日志记录"); } // 执行成功后通知 public void afterReturningLog() { System.out.println("方法成功执行后通知 日志记录"); } // 抛出异常后通知 public void afterThrowingLog() { System.out.println("方法抛出异常后执行通知 日志记录"); } // 环绕通知 public Object aroundLog(ProceedingJoinPoint joinpoint) { Object result = null; try { System.out.println("环绕通知开始 日志记录"); long start = System.currentTimeMillis(); //有返回参数 则需返回值 result = joinpoint.proceed(); long end = System.currentTimeMillis(); System.out.println("总共执行时长" + (end - start) + " 毫秒"); System.out.println("环绕通知结束 日志记录"); } catch (Throwable t) { System.out.println("出现错误"); } return result; } }
1.2.3.3测试类
package com.suncl.test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * Created by SCL-PC on 2019/2/28. */ public class Test { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); Demo demo = ac.getBean("demo",Demo.class); demo.demo1("a",1); } }
1.2.3.4运行结果
开始执行前置通知 日志记录
环绕通知开始 日志记录
执行了demo1111方法
总共执行时长16 毫秒
环绕通知结束 日志记录
方法成功执行后通知 日志记录
开始执行后置通知 日志记录
Process finished with exit code 0
1.3 自定义注解(基于AspectJ)
1.3.1 每个通知不需要实现接口或类
1.3.2 使用自动以注解方式配置
1.3.2.1在 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"> <!--标识哪些类需要扫描注解--> <context:component-scan base-package="com.suncl"></context:component-scan> <!--使用配置注解,首先我们要将切面在spring上下文中声明成自动代理bean--> <aop:aspectj-autoproxy /> </beans>
1.3.2.2实体类
package com.suncl.model; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; /** * Created by SCL-PC on 2019/3/3. */ @Component @Aspect public class MyAdvice { // 配置切点 及要传的参数 @Pointcut(" execution(* com.suncl.test.Demo.demo1(..)) ") public void pointCut() { } @Before("pointCut()") public void beforeLog() { System.out.println("开始执行前置通知 日志记录"); } // 方法执行完后通知 @After("pointCut()") public void afterLog() { System.out.println("开始执行后置通知 日志记录"); } // 执行成功后通知 @AfterReturning("pointCut()") public void afterReturningLog() { System.out.println("方法成功执行后通知 日志记录"); } // 抛出异常后通知 @AfterThrowing("pointCut()") public void afterThrowingLog() { System.out.println("方法抛出异常后执行通知 日志记录"); } // 环绕通知 @Around("pointCut()") public Object aroundLog(ProceedingJoinPoint joinpoint) { Object result = null; try { System.out.println("环绕通知开始 日志记录"); long start = System.currentTimeMillis(); //有返回参数 则需返回值 result = joinpoint.proceed(); long end = System.currentTimeMillis(); System.out.println("总共执行时长" + (end - start) + " 毫秒"); System.out.println("环绕通知结束 日志记录"); } catch (Throwable t) { System.out.println("出现错误"); } return result; } }
package com.suncl.test; import org.springframework.stereotype.Component; /** * Created by SCL-PC on 2019/2/28. */ @Component public class Demo { public void demo(){ System.out.println("执行了demo方法"); } public void demo1(String a ,int b){ System.out.println("执行了demo1111方法"); //用来验证出现错误的时候切点执行情况 // int i = 5/0; } }
1.3.2.3测试类
package com.suncl.test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * Created by SCL-PC on 2019/2/28. */ public class Test { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); Demo demo = ac.getBean("demo",Demo.class); demo.demo1("a",1); } }
1.3.2.4运行结果
环绕通知开始 日志记录
开始执行前置通知 日志记录
执行了demo1111方法
总共执行时长31 毫秒
环绕通知结束 日志记录
开始执行后置通知 日志记录
方法成功执行后通知 日志记录
Process finished with exit code 0
以上代码地址:链接:https://pan.baidu.com/s/1xRWt4ndOAZfVJ_YER-aO1w 提取码:jw84