Spring--Aop面向切面编程
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.spring.aop"></context:component-scan> <!-- 配置自动为匹配 aspectJ 注解的 Java 类生成代理对象 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
Calculator类
package com.spring.aop; import org.springframework.stereotype.Component; @Component("calculator") public class Calculator { public int add(int i, int j) { int result = i + j; return result; } public int sub(int i, int j) { int result = i - j; return result; } public int mul(int i, int j) { int result = i * j; return result; } public int div(int i, int j) { int result = i / j; return result; } }
插入Log
package com.spring.aop; import java.util.Arrays; 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.aspectj.lang.annotation.Pointcut; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; /** * 可以使用 @Order 注解指定切面的优先级, 值越小优先级越高 */ @Order(1) @Aspect @Component public class LoggingAspect { /** * 定义一个方法, 用于声明切入点表达式. 一般地, 该方法中再不需要添入其他的代码. * 使用 @Pointcut 来声明切入点表达式. * 后面的其他通知直接使用方法名来引用当前的切入点表达式. */ @Pointcut("execution(public int com.spring.aop.Calculator.*(..))")//Calculator内所有方法参数不限制 public void declareJointPointExpression(){} @Before("declareJointPointExpression()") public void beforeMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); Object [] args = joinPoint.getArgs();//得到参数 System.out.println("方法 "+methodName + " 前执行 " + Arrays.asList(args)); } /** * 在方法执行之后执行的代码. 无论该方法是否出现异常 */ @After("declareJointPointExpression()") public void afterMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); System.out.println("方法 " + methodName + " 后执行"); } /** * 在方法法正常结束受执行的代码 * 返回通知是可以访问到方法的返回值的! */ @AfterReturning(value="declareJointPointExpression()", returning="result") public void afterReturning(JoinPoint joinPoint, Object result){ String methodName = joinPoint.getSignature().getName(); System.out.println("方法 " + methodName + " 返回后执行 " + result); } /** * 在目标方法出现异常时会执行的代码. * 可以访问到异常对象; 且可以指定在出现特定异常时在执行通知代码 */ @AfterThrowing(value="declareJointPointExpression()", throwing="e") public void afterThrowing(JoinPoint joinPoint, Exception e){ String methodName = joinPoint.getSignature().getName(); System.out.println("方法 " + methodName + " 出现异常:" + e); } /** * 环绕通知需要携带 ProceedingJoinPoint 类型的参数. * 环绕通知类似于动态代理的全过程: ProceedingJoinPoint 类型的参数可以决定是否执行目标方法. * 且环绕通知必须有返回值, 返回值即为目标方法的返回值 */ // @Around(value="declareJointPointExpression()") // public Object aroundMethod(ProceedingJoinPoint pjd){ // // Object result = null; // String methodName = pjd.getSignature().getName(); // // try { // //前置通知 // System.out.println("方法 " + methodName + " 前 " + Arrays.asList(pjd.getArgs())); // //执行目标方法 // result = pjd.proceed(); // //返回通知 // System.out.println("方法 " + methodName + " 返回后 " + result); // } catch (Throwable e) { // //异常通知 // System.out.println("方法 " + methodName + " 出现异常:" + e); // throw new RuntimeException(e); // } // //后置通知 // System.out.println("方法 " + methodName + " 后"); // // return result; // } // }
测试
package com.spring.aop; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-aop.xml"); Calculator calculator = (Calculator) ctx.getBean("calculator"); System.out.println(calculator.getClass().getName()); int result = calculator.add(1, 2); System.out.println("result:" + result); result = calculator.div(1000, 0); System.out.println("result:" + result); } }
或者xml配置AOP
LoggingAspect
package com.spring.aop.xml; import java.util.Arrays; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.springframework.stereotype.Component; @Component public class LoggingAspect { public void beforeMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); Object [] args = joinPoint.getArgs();//得到参数 System.out.println("方法 "+methodName + " 前执行 " + Arrays.asList(args)); } public void afterMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); System.out.println("方法 " + methodName + " 后执行"); } public void afterReturning(JoinPoint joinPoint, Object result){ String methodName = joinPoint.getSignature().getName(); System.out.println("方法 " + methodName + " 返回后执行 " + result); } public void afterThrowing(JoinPoint joinPoint, Exception e){ String methodName = joinPoint.getSignature().getName(); System.out.println("方法 " + methodName + " 出现异常:" + e); } public Object aroundMethod(ProceedingJoinPoint pjd){ Object result = null; String methodName = pjd.getSignature().getName(); try { //前置通知 System.out.println("方法 " + methodName + " 前 " + Arrays.asList(pjd.getArgs())); //执行目标方法 result = pjd.proceed(); //返回通知 System.out.println("方法 " + methodName + " 返回后 " + result); } catch (Throwable e) { //异常通知 System.out.println("方法 " + methodName + " 出现异常:" + e); throw new RuntimeException(e); } //后置通知 System.out.println("方法 " + methodName + " 后"); return result; } }
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.spring.aop.xml"></context:component-scan> <!-- 配置 AOP --> <aop:config> <!-- 配置切点表达式 --> <aop:pointcut expression="execution(* com.spring.aop.xml.Calculator.*(..))" id="pointcut"/> <!-- 配置切面及通知 --> <aop:aspect ref="loggingAspect" order="1"> <aop:before method="beforeMethod" pointcut-ref="pointcut"/> <aop:after method="afterMethod" pointcut-ref="pointcut"/> <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="e"/> <aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="result"/> <!-- <aop:around method="aroundMethod" pointcut-ref="pointcut"/> --> </aop:aspect> </aop:config> </beans>