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 {
@Test
public 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 {
@Override
public void add(int id, String name) {
System.out.println("NBAService------add------");
}
@Override
public 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;
@Service
public class TeamService implements IService {
@Override
public void add(int id, String name) {
//int num = 10 / 0;
System.out.println("TeamService------add------");
}
@Override
public 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.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
">
<!-- 在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.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
">
<!-- 在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>