spring自身也有一套AOP框架,但相比较于AspectJ,更推荐AspectJ
在Spring2.0以上版本中,可以使用基于AspectJ注解或基于XML配置的AOP。
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
<!-- 配置自动扫描的包 --> <context:component-scan base-package="com.wul.spring.aop.impl"></context:component-scan> <!-- 使AspectJ注解起作用:自动为匹配的类生成代理对象 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>(当Spring IOC 容器侦测到Bean配置文件中的<aop:aspectj-autoproxy>元素时,会自动与AspectJ切面匹配的Bean创建代理。)
I.切面首先是一个IOC中的bean,即加入@Component注释
II.切面还需要加入@Aspect
II.在方法前加入@Before注解
III.利用方法签名编写AspectJ切入点表达式
方法名:String methodName = joinPoint.getSignature().getName();
参数值:List<Object> args = Arrays.asList(joinPoint.getArgs());
前置通知:
//声明该方法是一个前置通知:在目标方法开始之前执行 // @Before("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.add(int ,int))") @Before("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int ,int))") public void beforeMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); List<Object> args = Arrays.asList(joinPoint.getArgs()); System.out.println("The method "+methodName +" begins with "+ args); }
//后置通知:在目标方法之后(无论是否发生异常),执行的通知, //在后置通知中还不能访问目标方法执行的结果。执行结果须在返回通知中访问。 @After("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int ,int))") public void afterMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method "+ methodName+" ends"); }
//返回通知:在目标方法正常结束执行后的通知 //返回通知是可以访问到目标方法的返回值的 @AfterReturning(value="execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int,int))" , returning = "result") public void afterRunningMethod(JoinPoint joinPoint , Object result){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method "+ methodName+" ends with the Result "+ result); }
//在目标方法出现异常时会执行的代码, //可以访问到异常对象,且可以指定在出现特定异常时在执行通知代码 //如下面Exception ex,若是指定为NullpointerException ex就不会执行通知代码 @AfterThrowing(value="execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int,int))" , throwing="ex") public void afterThrowingMethod(JoinPoint joinPoint,Exception ex){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method "+ methodName+"occurs exception:"+ex); }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); //日志 System.out.println("The method "+methodName+" begin with "+Arrays.asList(args)); //执行方法 Object result = null; try{ //前置通知 result = method.invoke(target, args); //返回通知,可以访问到方法的返回通知 }catch(Exception e){ e.printStackTrace(); //异常通知:可以访问到方法出现的异常 } //后置通知:因为方法可能出错,所以访问不到方法的返回值。 //日志 System.out.println("The method "+methodName + " ends with "+result); return result; }
环绕通知:(类似于动态代理的过程)
package com.wul.spring.aop.impl; import java.util.Arrays; import java.util.List; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; //把这个类声明为一个切面:需要把该类放入到IOC容器中,再声明为一个切面 @Aspect @Component public class LogginAspect { //声明该方法是一个前置通知:在目标方法开始之前执行 // @Before("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.add(int ,int))") @Before("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int ,int))") public void beforeMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); List<Object> args = Arrays.asList(joinPoint.getArgs()); System.out.println("The method "+methodName +" begins with "+ args); } //后置通知:在目标方法之后(无论是否发生异常),执行的通知, //在后置通知中还不能访问目标方法执行的结果。执行结果须在返回通知中访问。 @After("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int ,int))") public void afterMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method "+ methodName+" ends"); } //返回通知:在目标方法正常结束执行后的通知 //返回通知是可以访问到目标方法的返回值的 @AfterReturning(value="execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int,int))" , returning = "result") public void afterRunningMethod(JoinPoint joinPoint , Object result){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method "+ methodName+" ends with the Result "+ result); } //在目标方法出现异常时会执行的代码, //可以访问到异常对象,且可以指定在出现特定异常时在执行通知代码 //如下面Exception ex,若是指定为NullpointerException ex就不会执行通知代码 @AfterThrowing(value="execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int,int))" , throwing="ex") public void afterThrowingMethod(JoinPoint joinPoint,Exception ex){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method "+ methodName+"occurs exception:"+ex); } //坏绕通知:需要携带ProceedingJoinPoint类型的参数 //环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法 //且环绕通知必须有返回值,返回值即目标方法的返回值。 @Around("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int,int))") public Object aroundMethod(ProceedingJoinPoint pjd){ Object result = null; String methodName = pjd.getSignature().getName(); Object args = Arrays.asList(pjd.getArgs()); //执行目标方法 try { //前置通知 System.out.println("Arround:The method "+methodName +" begins with "+ args); result = pjd.proceed(); //后置通知 System.out.println("Arround:The method "+ methodName+" ends"); } catch (Throwable e) { e.printStackTrace(); //异常通知 System.out.println("Arround:The method "+ methodName+"occurs exception:"+e); //throw new RuntimeException(e); //不抛出异常的话,异常就被上面抓住,执行下去,返回result,result值为null,转换为int } //返回通知 System.out.println("Arround:The method "+ methodName+" ends with the Result "+ result); //return 100; return result; } }
AtithmeticCalculator.java
package com.wul.spring.aop.impl; public interface AtithmeticCalculator { int add(int i, int j); int sub(int i, int j); int mul(int i, int j); int div(int i, int j); }
AtithmeticCalculatorImpl.java
package com.wul.spring.aop.impl; import org.springframework.stereotype.Component; @Component public class AtithmeticCalculatorImpl implements AtithmeticCalculator { @Override public int add(int i, int j) { int result = i + j; return result; } @Override public int sub(int i, int j) { int result = i - j; return result; } @Override public int mul(int i, int j) { int result = i * j; return result; } @Override public int div(int i, int j) { int result = i / j; return result; } }
LogginAspect.java
package com.wul.spring.aop.impl; import java.util.Arrays; import java.util.List; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; //把这个类声明为一个切面:需要把该类放入到IOC容器中,再声明为一个切面 @Aspect @Component public class LogginAspect { //声明该方法是一个前置通知:在目标方法开始之前执行 // @Before("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.add(int ,int))") @Before("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int ,int))") public void beforeMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); List<Object> args = Arrays.asList(joinPoint.getArgs()); System.out.println("The method "+methodName +" begins with "+ args); } //后置通知:在目标方法之后(无论是否发生异常),执行的通知, //在后置通知中还不能访问目标方法执行的结果。执行结果须在返回通知中访问。 @After("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int ,int))") public void afterMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method "+ methodName+" ends"); } //返回通知:在目标方法正常结束执行后的通知 //返回通知是可以访问到目标方法的返回值的 @AfterReturning(value="execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int,int))" , returning = "result") public void afterRunningMethod(JoinPoint joinPoint , Object result){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method "+ methodName+" ends with the Result "+ result); } //在目标方法出现异常时会执行的代码, //可以访问到异常对象,且可以指定在出现特定异常时在执行通知代码 //如下面Exception ex,若是指定为NullpointerException ex就不会执行通知代码 @AfterThrowing(value="execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int,int))" , throwing="ex") public void afterThrowingMethod(JoinPoint joinPoint,Exception ex){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method "+ methodName+"occurs exception:"+ex); } //坏绕通知:需要携带ProceedingJoinPoint类型的参数 //环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法 //且环绕通知必须有返回值,返回值即目标方法的返回值。 @Around("execution(public int com.wul.spring.aop.impl.AtithmeticCalculator.*(int,int))") public Object aroundMethod(ProceedingJoinPoint pjd){ Object result = null; String methodName = pjd.getSignature().getName(); Object args = Arrays.asList(pjd.getArgs()); //执行目标方法 try { //前置通知 System.out.println("Arround:The method "+methodName +" begins with "+ args); result = pjd.proceed(); //后置通知 System.out.println("Arround:The method "+ methodName+" ends"); } catch (Throwable e) { e.printStackTrace(); //异常通知 System.out.println("Arround:The method "+ methodName+"occurs exception:"+e); //throw new RuntimeException(e); //不抛出异常的话,异常就被上面抓住,执行下去,返回result,result值为null,转换为int } //返回通知 System.out.println("Arround:The method "+ methodName+" ends with the Result "+ result); //return 100; return result; } }
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-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- 配置自动扫描的包 --> <context:component-scan base-package="com.wul.spring.aop.impl"></context:component-scan> <!-- 使AspectJ注解起作用:自动为匹配的类生成代理对象 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
Main.java
package com.wul.spring.aop.impl; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { //1.创建Spring的IOC容器 ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); //2.从IOC容器中获取bean的实例 AtithmeticCalculator arithmeticCalculator = ctx.getBean(AtithmeticCalculator.class); //3.使用bean int result = arithmeticCalculator.add(3,6); System.out.println("result: "+result); result = arithmeticCalculator.div(10,5); System.out.println("result: "+result); result = arithmeticCalculator.div(10,0); } }
热门源码