03Spring实现AOP前置后置等
张创琦
代码详见 spring03_aop
以下代码共用一个测试类和service类
Test01.java
package com.kkb.test;import com.kkb.service.NBAService;import com.kkb.service.TeamService;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test01 {@Testpublic void test01(){ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");TeamService teamService = (TeamService)ac.getBean("teamService");teamService.add(1001, "湖人队");System.out.println("----------");boolean update = teamService.update(888);System.out.println("update结果: " + update);System.out.println("---------------------");NBAService nbaService = (NBAService)ac.getBean("nbaService");nbaService.add(1002, "热火队");System.out.println("----------");boolean update2 = teamService.update(888);System.out.println("update2结果: " + update2);}}
IService.java
package com.kkb.service;public interface IService {void add(int id, String name);boolean update(int num);}
NBAService.java
标头引入相关依赖。
package com.kkb.service;import org.springframework.stereotype.Service;@Service("nbaService")public class NBAService implements IService {@Overridepublic void add(int id, String name) {System.out.println("NBAService------add------");}@Overridepublic boolean update(int num) {System.out.println("NBAService------update------");if(num > 666){return true;}return false;}}
TeamService.java
package com.kkb.service;import org.springframework.stereotype.Service;@Servicepublic class TeamService implements IService {@Overridepublic void add(int id, String name) {//int num = 10 / 0;System.out.println("TeamService------add------");}@Overridepublic boolean update(int num) {System.out.println("TeamService------update------");if(num > 666){return true;}return false;}}
方法1: 通过注解方式实现
MyAspect.java
package com.kkb.aop;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.*;import org.springframework.stereotype.Component;//切面类@Component //切面对象的创建权限依然交给Spring容器@Aspect //aspectj框架的注解,标识当前类是一个切面类public class MyAspect {//统一提取切入点表达式//其它的通知可以直接在value直接使用方法名称@Pointcut("execution(* com.kkb.service..*.*(..))") //注解表示切入点表达式,方法一般声明为私有private void pointCut(){}//可以声明多个@Pointcut("execution(* com.kkb.service..*.update*(..))") //注解表示切入点表达式,方法一般声明为私有private void pointCut2(){}@Before("execution(* com.kkb.service..*.*(..))")//也可以写成@Before(pointCut())public void before(JoinPoint jp){System.out.println("前置通知:在目标方法调用之前被调用的通知。");String name = jp.getSignature().getName();System.out.println("拦截的方法名称:"+name);Object[] args = jp.getArgs();System.out.println("方法的参数格式:"+args.length);System.out.println("方法的参数列表:");for (Object arg: args) {System.out.println("\t"+arg);}}//Return表示返回的结果,如果需要的话可以在后置方法通知中修改结果,value依然表示切入点表达式@AfterReturning(value="execution(* com.kkb.service..*.update*(..))", returning = "result")public Object after(Object result){if(result != null){boolean res = (boolean) result;if(res){result = false;}}System.out.println("后置通知:在目标方法调用之后被调用的通知。result="+result);return result;}//注解声明环绕通知方法//ProceedingJoinPoint中的proceed方法表示目标方法被执行@Around("execution(* com.kkb.service..*.*(..))")public Object around(ProceedingJoinPoint pjp) throws Throwable {System.out.println("环绕方法------目标方法执行之前");Object proceed = pjp.proceed();System.out.println("环绕方法------目标方法执行之后");return proceed;}//注解声明异常通知方法@AfterThrowing(value="execution(* com.kkb.service..*.*(..))", throwing = "ex")public void exception(JoinPoint jp, Throwable ex){//一般会把异常发生的时间 位置 缘由记录下来System.out.println("异常通知:在目标方法执行出现异常被调用的通知。否则不执行");System.out.println(jp.getSignature() + "方法出现异常,异常信息是:" +ex.getMessage());}//注解声明最终通知方法@After("execution(* com.kkb.service..*.*(..))")public void myFinally(){System.out.println("最终通知:无论是否出现异常都会调用的通知。");}}
spring.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.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!-- 在beans标签中引入AOP和context约束 --><context:component-scan base-package="com.kkb.service, com.kkb.aop"/><!-- aspectj的相关配置, true开启代理模式 --><aop:aspectj-autoproxy proxy-target-class="true"/></beans>
方法2: 通过xml配置实现
MyAOP.java
package com.kkb.aop;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.*;import org.springframework.stereotype.Component;/*** 切面类*///通过xml调取@Component //切面对象的创建权限依然交给Spring容器@Aspect //aspectj框架的注解,标识当前类是一个切面类public class MyAOP {public void before(JoinPoint jp){System.out.println("AOP前置通知:在目标方法调用之前被调用的通知。");}public void after(Object result){System.out.println("AOP后置通知:在目标方法调用之后被调用的通知。result="+result);}public Object around(ProceedingJoinPoint pjp) throws Throwable {System.out.println("AOP环绕方法------目标方法执行之前");Object proceed = pjp.proceed();System.out.println("AOP环绕方法------目标方法执行之后");return proceed;}public void exception(JoinPoint jp, Throwable ex){//一般会把异常发生的时间 位置 缘由记录下来System.out.println("AOP异常通知:在目标方法执行出现异常被调用的通知。否则不执行");System.out.println(jp.getSignature() + "方法出现异常,异常信息是:" +ex.getMessage());}public void myFinally() {System.out.println("AOP最终通知:无论是否出现异常都会调用的通知。");}}
spring.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.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!-- 在beans标签中引入AOP和context约束 --><context:component-scan base-package="com.kkb.service, com.kkb.aop"/><!-- aspectj的相关配置, true开启代理模式 --><aop:aspectj-autoproxy proxy-target-class="true"/><!-- xml方式实现AOP --><aop:config><aop:pointcut id="pt1" expression="execution(* com.kkb.service..*.*(..))"/><aop:pointcut id="pt2" expression="execution(* com.kkb.service..*.add*(..))"/><aop:aspect ref="myAOP" ><!-- 声明切入点的表达式 --><aop:before method="before" pointcut-ref="pt1"></aop:before><!-- 也可以写成 <aop:before method="before" pointcut="execution(* com.kkb.service..*.*(..))"></aop:before>--><aop:after-returning method="after" pointcut-ref="pt2" returning="result"></aop:after-returning><aop:after-throwing method="exception" pointcut-ref="pt1" throwing="ex"></aop:after-throwing><aop:after method="myFinally" pointcut-ref="pt1"></aop:after><aop:around method="around" pointcut-ref="pt2"></aop:around></aop:aspect></aop:config></beans>
