一 基于注解的方式配置Spring AOP
示例:
1.接口,及实现类
实现类使用@Component注解,配置到IOC容器中
public interface ArithmeticCalculator { int add(int i, int j); int sub(int i, int j); int mul(int i, int j); int div(int i, int j); }
@Component("arithmeticCalculator") public class ArithmeticCalculatorImpl implements ArithmeticCalculator { @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; } }
2. 两个切面,验证切面 和 日志切面。验证切面在日志切面之前
(1)验证切面
//@Order 指定切面优先级,值越小切面优先级越高 @Order(1) @Component @Aspect public class ValicationAspect { //使用 LoggingAspect 中声明的切入点表达式 @Before(value = "com.spring.atguigu.aop.LoggingAspect.declareJoinPointExpression()") public void validateArgs(JoinPoint joinPoint){ System.out.println("--> valicate:" +Arrays.asList(joinPoint.getArgs())); } }(2)日志切面
//把这个类声明为一个切面:需把该类放到IOC容器中,再声明为一个切面 @Order(2) @Component @Aspect public class LoggingAspect { //定义一个方法,用于声明切入点表达式,一般地,该方法不需要添入其他代码 //使用@Pointcut 声明一个切入点表达式 //后面的其他通知直接使用方法名来引用当前切入点表达式 @Pointcut(value = "execution(public int com.spring.atguigu.aop.*.*(int,int))") public void declareJoinPointExpression(){} // 声明该方法为一个前置通知 @Before(value = "execution(public int com.spring.atguigu.aop.*.*(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..." + args); } // 后置通知:在目标方法执行后(无论是否发生异常),执行的通知 // 在后置通知中,还不能访问目标方法的执行结果 @After(value = "execution(public int com.spring.atguigu.aop.*.*(int,int))") public void afterMethod(JoinPoint joinpoint) { // 获取方法名 String methodName = joinpoint.getSignature().getName(); System.out.println("the method " + methodName + " ends ..."); } // 返回通知 在方法正常结束执行的代码 // 可以访问到结果 @AfterReturning(value = "declareJoinPointExpression()", returning = "result") public void afterReturningMethod(JoinPoint joinpoint, Object result) { String methodName = joinpoint.getSignature().getName(); System.out.println("the method " + methodName + " ends with " + result); } // 异常通知 方法发生异常时执行 // 可以访问到异常对象,且可以指定特定异常类型时,执行通知代码 public void afterThrowingMethod(JoinPoint // joinpoint , NullPointerException e) @AfterThrowing(value = "execution(public int com.spring.atguigu.aop.*.*(int,int))", throwing = "e") public void afterThrowingMethod(JoinPoint joinpoint, Exception e) { String methodName = joinpoint.getSignature().getName(); System.out.println("the method " + methodName + " occurs exception " + e); } /** * 环绕通知需携带 ProceedingJoinPoint 类型的参数 环绕通知类似于动态代理的全过程,ProceedingJoinPoint * 类型的参数可以决定是否执行目标方法 环绕通知必须有返回值,返回值即为目标方法的返回值 * * @param pjd * @return */ /*@Around(value = "execution(public int com.spring.atguigu.aop.*.*(int,int))") public Object aroundMethod(ProceedingJoinPoint pjd) { System.out.println("aroundMethod"); Object result = null; String methodName = pjd.getSignature().getName(); try { // 前置通知 System.out.println("the method" + methodName + " begins with" + Arrays.asList(pjd.getArgs())); // 执行目标方法 result = pjd.proceed(); // 返回通知 System.out.println("the method " + methodName + " ends with " + result); } catch (Throwable e) { // 异常通知 System.out.println("the method " + methodName + " occurs exception " + e); } //后置通知 System.out.println("the method " + methodName + " ends ..."); return result; }*/ }
注解说明:
@Component 将切面配置到IOC容器中@Aspect 声明为切面
@Order 指定切面优先级,值越小切面优先级越高
@Pointcut 声明一个切入点表达式
@Before声明该方法为一个前置通知
@After 后置通知 在目标方法执行后(无论是否发生异常),执行的通知
@AfterReturning 返回通知 在方法正常结束执行的代码
@AfterThrowing 异常通知 方法发生异常时执行
@Around 环绕通知需携带 ProceedingJoinPoint 类型的参数 环绕通知类似于动态代理的全过程,ProceedingJoinPoint
3.applicationContext.xml 配置文件
<context:component-scan base-package="com.spring.atguigu.aop"></context:component-scan> <!-- 使AspectJ注解起作用:自动为匹配的类生成代理对象 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
4.测试类
public class Main { public static void main(String[] args) { ApplicationContext ctx= new ClassPathXmlApplicationContext("applicationContext.xml"); ArithmeticCalculator arithmeticCalculator = (ArithmeticCalculator) ctx.getBean("arithmeticCalculator"); int result = arithmeticCalculator.add(3, 3); System.out.println("result:"+result); result = arithmeticCalculator.div(12,6); System.out.println(result); } }
5.结果:
--> valicate:[3, 3]
aroundMethod
the methodadd begins with[3, 3]
the method add ends with 6
the method add ends ...
result:6
--> valicate:[12, 6]
aroundMethod
the methoddiv begins with[12, 6]
the method div ends with 2
the method div ends ...
2
aroundMethod
the methodadd begins with[3, 3]
the method add ends with 6
the method add ends ...
result:6
--> valicate:[12, 6]
aroundMethod
the methoddiv begins with[12, 6]
the method div ends with 2
the method div ends ...
2
二、基于配置文件方式配置AOP
示例:
1.接口,实现类(和前面一样,只是去掉了注解)
public interface ArithmeticCalculator { int add(int i, int j); int sub(int i, int j); int mul(int i, int j); int div(int i, int j); }
public class ArithmeticCalculatorImpl implements ArithmeticCalculator { @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; } }
2. 验证切面,日志切面 (和前面一样,只是去掉注解)
public class ValicationAspect { public void validateArgs(JoinPoint joinPoint){ System.out.println("--> valicate:" +Arrays.asList(joinPoint.getArgs())); } }
public class LoggingAspect { public void beforeMethod(JoinPoint joinpoint) { // 获取方法名 String methodName = joinpoint.getSignature().getName(); // 获取参数 List<Object> args = Arrays.asList(joinpoint.getArgs()); System.out.println("the method " + methodName + " begins..." + args); } public void afterMethod(JoinPoint joinpoint) { // 获取方法名 String methodName = joinpoint.getSignature().getName(); System.out.println("the method " + methodName + " ends ..."); } public void afterReturningMethod(JoinPoint joinpoint, Object result) { String methodName = joinpoint.getSignature().getName(); System.out.println("the method " + methodName + " ends with " + result); } public void afterThrowingMethod(JoinPoint joinpoint, Exception e) { String methodName = joinpoint.getSignature().getName(); System.out.println("the method " + methodName + " occurs exception " + e); } public Object aroundMethod(ProceedingJoinPoint pjd) { System.out.println("aroundMethod"); Object result = null; String methodName = pjd.getSignature().getName(); try { // 前置通知 System.out.println("the method" + methodName + " begins with" + Arrays.asList(pjd.getArgs())); // 执行目标方法 result = pjd.proceed(); // 返回通知 System.out.println("the method " + methodName + " ends with " + result); } catch (Throwable e) { // 异常通知 System.out.println("the method " + methodName + " occurs exception " + e); } //后置通知 System.out.println("the method " + methodName + " ends ..."); return result; } }
3.配置文件 applicationContext-xml.xml
<!-- 配置bean --> <bean id = "arithmeticCalculator" class="com.spring.atguigu.aop.xml.ArithmeticCalculatorImpl"></bean> <!-- 配置一个切面的bean --> <bean id ="valicationAspect" class = "com.spring.atguigu.aop.xml.ValicationAspect" ></bean> <bean id = "loggingAspect" class = "com.spring.atguigu.aop.xml.LoggingAspect"></bean> <aop:config> <!-- 配置切点表达式 --> <aop:pointcut expression="execution(* com.spring.atguigu.aop.xml.ArithmeticCalculator.*(int , int ))" id="pointcut"/> <!-- 配置切面及通知 --> <aop:aspect ref="loggingAspect" order="2"> <aop:before method="beforeMethod" pointcut-ref="pointcut"/> <aop:after method="afterMethod" pointcut-ref="pointcut"/> <aop:after-returning method="afterReturningMethod" pointcut-ref="pointcut" returning="result"/> <aop:after-throwing method="afterThrowingMethod" pointcut-ref="pointcut" throwing="e"/> <!-- 环绕通知 --> <!-- <aop:around method="aroundMethod" pointcut-ref="pointcut"/> --> </aop:aspect> <aop:aspect ref="valicationAspect" order="1"> <aop:before method="validateArgs" pointcut-ref="pointcut"/> </aop:aspect> </aop:config>
4. 测试方法
public class Main { public static void main(String[] args) { ApplicationContext ctx= new ClassPathXmlApplicationContext("applicationContext-xml.xml"); ArithmeticCalculator arithmeticCalculator = (ArithmeticCalculator) ctx.getBean("arithmeticCalculator"); int result = arithmeticCalculator.add(3, 3); System.out.println("result:"+result); result = arithmeticCalculator.div(12,6); System.out.println(result); } }
5.结果:
--> valicate:[3, 3]
the method add begins...[3, 3]
the method add ends ...
the method add ends with 6
result:6
--> valicate:[12, 6]
the method div begins...[12, 6]
the method div ends ...
the method div ends with 2
2