需要用的基本的jar包:
aopalliance-1.0.jar
aspectj-1.6.8.jar
aspectjweaver-1.6.8.jar
commons-logging-1.1.3.jar
spring-aop-4.0.0.RELEASE.jar
spring-aspects-4.0.0.RELEASE.jar
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar
1:基于注解的日志通知和验证通知:
定义接口:
1 package com.yinfu.spring.aop.impl; 2 3 public interface ArithmeticCalculator { 4 5 public int add(int i,int j); 6 public int sub(int i,int j); 7 public int mul(int i,int j); 8 public int div(int i,int j); 9 }
定义实现类:
1 package com.yinfu.spring.aop.impl; 2 3 import org.springframework.stereotype.Component; 4 5 @Component("arithmeticCalculator") 6 public class ArithmeticCalculatorImpl implements ArithmeticCalculator { 7 8 @Override 9 public int add(int i, int j) { 10 11 int result = i+j; 12 return result; 13 } 14 15 @Override 16 public int sub(int i, int j) { 17 int result = i-j; 18 return result; 19 } 20 21 @Override 22 public int mul(int i, int j) { 23 int result = i*j; 24 return result; 25 } 26 27 @Override 28 public int div(int i, int j) { 29 int result = i/j; 30 return result; 31 } 32 33 }
定义spring的配置文件:applicationContext.xml:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:aop="http://www.springframework.org/schema/aop" 5 xmlns:context="http://www.springframework.org/schema/context" 6 xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd 7 http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 8 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> 9 10 <!-- <bean id="helloWorld" class="com.yinfu.spring.beans.HelloWorld"> 11 <property name="name" value="fuck"></property> 12 </bean> --> 13 <!-- 配置自动扫描包 --> 14 <context:component-scan base-package="com.yinfu.spring.aop.impl"></context:component-scan> 15 16 <!-- 使AspectJ注解起作用:自动为匹配的类生成代理对象 --> 17 <aop:aspectj-autoproxy></aop:aspectj-autoproxy> 18 19 </beans>
定义切面类:
1 package com.yinfu.spring.aop.impl; 2 3 import java.util.Arrays; 4 import java.util.List; 5 6 import org.aspectj.lang.JoinPoint; 7 import org.aspectj.lang.ProceedingJoinPoint; 8 import org.aspectj.lang.annotation.After; 9 import org.aspectj.lang.annotation.AfterReturning; 10 import org.aspectj.lang.annotation.AfterThrowing; 11 import org.aspectj.lang.annotation.Around; 12 import org.aspectj.lang.annotation.Aspect; 13 import org.aspectj.lang.annotation.Before; 14 import org.aspectj.lang.annotation.Pointcut; 15 import org.springframework.core.annotation.Order; 16 import org.springframework.stereotype.Component; 17 18 /** 19 * 把此类声明为一个切面 20 * 首相把该类放到IOC容器中,然后在声明为切面 21 * @Aspect声明此类是一个切面 22 * @Order声明切面的优先级,值越小优先级越高 23 * @author lusong 24 * 25 */ 26 @Order(1) 27 @Aspect 28 @Component 29 public class LoggingAspect { 30 31 32 //定义一个方法用于声明切入点表达式,因为表达式都相同,可以进行封装不过方法内不需要添加其他代码 33 //使用@Pointcut声明切入点表达式 34 /** 35 * 此时下面的通知注解都可以将value值写成此方法名 如:@Before("declareJoinPointException()")即可 36 */ 37 @Pointcut("execution(public int com.yinfu.spring.aop.impl.ArithmeticCalculatorImpl.*(int, int))") 38 public void declareJoinPointException(){} 39 40 //1.前置通知:声明该方法是一个前置方法,在指定目标方法之前执行 41 /** 42 * before中写的是aspectj的表达式 43 * public int可以用*代替,代表:任意修饰符和任意返回值 44 * com.yinfu.spring.aop.impl代表包名 45 * ArithmeticCalculatorImpl代表类名,可以用*代替,代表该包下的任意类 46 * add代表方法名,可以用*好代替,代表该类下的任意方法 47 * (int,int)参数类型,可以用..代替 48 * @param joinPoint 链接点利用此链接点可以得到代理对象中的方法名称和参数等细节 49 */ 50 @Before("execution(public int com.yinfu.spring.aop.impl.ArithmeticCalculatorImpl.*(int, int))") 51 public void beforeMethod(JoinPoint joinPoint ){ 52 String methodName = joinPoint.getSignature().getName(); 53 List<Object> args = Arrays.asList(joinPoint.getArgs()); 54 System.out.println("this method "+methodName+" begin"+args); 55 } 56 //2.后置通知:在目标方法执行后(无论是否发生异常),执行的通知 57 //后置通知中还不能访问目标方法执行的结果 58 @After("execution(public int com.yinfu.spring.aop.impl.ArithmeticCalculatorImpl.*(int, int))") 59 public void afterMethod(JoinPoint joinPoint ){ 60 String methodName = joinPoint.getSignature().getName(); 61 System.out.println("this method "+methodName+" end"); 62 } 63 64 //3返回通知:在目标方法正常执行后,执行的通知 65 //返回通知是可以访问到方法的返回值的 66 @AfterReturning(value="execution(public int com.yinfu.spring.aop.impl.ArithmeticCalculatorImpl.*(int, int))",returning="result") 67 public void afterReturning(JoinPoint joinPoint ,Object result){ 68 String methodName = joinPoint.getSignature().getName(); 69 System.out.println("this method "+methodName+" end with "+result); 70 } 71 72 //4.异常通知:在目标方法出现异常时会执行代码 73 //可以访问异常对象,指定异常类型,当出现指定的异常时才会执行代码 74 //也就是Exception可以换成NullPoinException异常,当出现空指针异常的时候才会执行异常通知,其他异常不执行 75 @AfterThrowing(value="execution(public int com.yinfu.spring.aop.impl.ArithmeticCalculatorImpl.*(int, int))",throwing="ex") 76 public void afterThrowing(JoinPoint joinPoint ,Exception ex){ 77 String methodName = joinPoint.getSignature().getName(); 78 System.out.println("this method "+methodName+" throw with "+ex); 79 } 80 81 //5.环绕通知 82 //环绕通知携带ProceedingJoinPoint类型的参数 83 //环绕通知类似于动态代理的全过程,ProceedingJoinPoint类型的参数可以决定是否执行目标方法 84 //环绕通知必须有返回值,返回值即为目标方法的返回值 85 @Around("execution(public int com.yinfu.spring.aop.impl.ArithmeticCalculatorImpl.*(int, int))") 86 public Object aroundMethod(ProceedingJoinPoint pjp){ 87 Object result = null; 88 String methodName = pjp.getSignature().getName(); 89 Object[] args = pjp.getArgs(); 90 //执行目标方法 91 try { 92 //前置通知 93 System.out.println("this aroundMethod "+methodName+" begin with "+Arrays.asList(args)); 94 result = pjp.proceed(); 95 //返回通知 96 System.out.println("this aroundMethod "+methodName+" resutn with "+result); 97 } catch (Throwable e) { 98 //异常通知 99 System.out.println("this aroundMethod "+methodName+" throw with "+e); 100 } 101 //后置通知 102 System.out.println("this aroundMethod "+methodName+" end "); 103 return result; 104 } 105 106 107 }
2.基于配置文件的日志通知和验证通知:
将类中的注解全部去掉,其他不变
此时的配置文件applicationContext.xml 这样写即可:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:aop="http://www.springframework.org/schema/aop" 5 xmlns:context="http://www.springframework.org/schema/context" 6 xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd 7 http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 8 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> 9 10 <!-- 配置方法对象bean --> 11 <bean id="arithmeticCalculator" class="com.yinfu.spring.aop.impl.ArithmeticCalculatorImpl"></bean> 12 <!-- 配置切面bean --> 13 <bean id="loggingAspect" class="com.yinfu.spring.aop.impl.LoggingAspect"></bean> 14 <!-- 配置AOP切面 --> 15 <aop:config> 16 <!-- 配置切点表达式 --> 17 <aop:pointcut expression="execution(public int com.yinfu.spring.aop.impl.ArithmeticCalculatorImpl.*(int, int))" id="pointcut"/> 18 <!-- 配置切点及通知 --> 19 <aop:aspect ref="loggingAspect" order="1"> 20 <aop:before method="beforeMethod" pointcut-ref="pointcut"/> 21 <aop:after method="afterMethod" pointcut-ref="pointcut"/> 22 <!-- 这里的returning值必须与切面类中定义的值是一样的 --> 23 <aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="result"/> 24 <!-- 这里的throwing值必须与切面类中定义的值是一样的 --> 25 <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="ex"/> 26 <aop:around method="aroundMethod" pointcut-ref="pointcut"/> 27 </aop:aspect> 28 </aop:config> 29 30 </beans>