2、Spring之AOP

    xiaoxiao2021-03-25  114

    AOP术语

    通知:定义了切面是什么以及何时使用。除了要描述页面要完成的工作,通知还解决了何时执行这个工作的问题。连接点:连接点是一个物理的存在。这个点可以是调用方法时、抛出异常时、甚至是修改一个字段时。切点:如果通知定义了切面是”什么“和”何时“,那么切点定义了”何处“。切点的定义会匹配通知所要织入的一个或者多个连接点。通常使用明确的类名和方法名来指定这些切点,或者使用正则表达式定义匹配的类和方法名模式来指定这些切点。切面:切面是切点和通知的组合。

    配置AOP

    <!-- 配置切面的Bean --> <bean id="loggingAspect" class="com.test.spring.aop.xml.LoggingAspect"></bean> <bean id="validationAspect" class="com.test.spring.aop.xml.ValidationAspect"></bean> <bean id ="constant" class="com.test.spring.aop.xml.ConstantImpl"></bean> <!-- 配置AOP --> <aop:config> <!-- 配置切点表达式 --> <aop:pointcut expression="execution(* com.test.spring.aop.xml.ArithmeticCalculator.*(..))" id="pointcut"/> <!-- 配置切面和通知 --> <aop:aspect ref="loggingAspect" order="2"> <aop:before method="beforeMethod" pointcut-ref="pointcut"/> <aop:after-returning method="afterReturning" returning="result" pointcut-ref="pointcut"/> <aop:after method="afterMethod" pointcut-ref="pointcut"/> <aop:after-throwing method="afterThrowing" throwing="ex" pointcut-ref="pointcut"/> <!--<aop:around method="aroundMethod" pointcut-ref="pointcut"/> --> </aop:aspect> <aop:aspect ref="validationAspect" order="1"> <aop:before method="validateArgs" pointcut-ref="pointcut"/> </aop:aspect> </aop:config>

    LoggingAspect

    public class LoggingAspect { public void beforeMethod(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); //为通知传递参数,可以在JoinPoint 中拦截调用的目标方法,包括调用的目标方法的名字,出入目标方法的参数。 Object[] args = joinPoint.getArgs(); System.out.println("The method " + methodName + " begins with " + Arrays.asList(args)); } public void afterMethod(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); System.out.println("The method " + methodName + " ends"); } public void afterReturning(JoinPoint joinPoint, Object result) { String methodName = joinPoint.getSignature().getName(); System.out.println("The method " + methodName + " ends with " + result); } public void afterThrowing(JoinPoint joinPoint, Exception ex) { String methodName = joinPoint.getSignature().getName(); System.out.println("The method " + methodName + " occurs excetion:" + ex); }

    环绕通知

    public Object aroundMethod(ProceedingJoinPoint pjd) { 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); throw new RuntimeException(e); } // 后置通知 System.out.println("The method " + methodName + " ends"); return result; }

    通过切面引入新功能

    <aop:aspect ref="loggingAspect" order="2"> <aop:declare-parents types-matching="com.test.spring.aop.xml.ArithmeticCalculator+" implement-interface="com.test.spring.aop.xml.Constant" delegate-ref="constant"/> </aop:aspect>

    说明:通过切面引入新的功能就是为代理实现接口的一个过程。ArithmeticCalculator 是一个代理,通过<aop:declare-parents/> 为此代理实现Constant接口,并指定默认实现delegate-ref="constant" 从而达到扩展基础对象ArithmeticCalculator 的效果。在掉用目标Bean的时候,如果不是目标Bean的方法,则从代理的实现的接口constant 寻找方法的代用,如果是目标Bean的方法,则调用目标Bean的方法。

    注解使用

    启用注解: <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

    /** * 可以使用 @Order 注解指定切面的优先级, 值越小优先级越高 */ @Order(1) @Aspect @Component public class LoggingAspect { /** * 定义一个方法, 用于声明切入点表达式. 一般地, 该方法中再不需要添入其他的代码. * 使用 @Pointcut 来声明切入点表达式. * 后面的其他通知直接使用方法名来引用当前的切入点表达式. */ @Pointcut("execution(public int com.spring.aop.ArithmeticCalculator.*(..))") public void declareJointPointExpression(){} /** * 在 com.spring.aop.ArithmeticCalculator 接口的每一个实现类的每一个方法开始之前执行一段代码 */ @Before("declareJointPointExpression()") public void beforeMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); Object [] args = joinPoint.getArgs(); System.out.println("The method " + methodName + " begins with " + Arrays.asList(args)); } /** * 在方法执行之后执行的代码. 无论该方法是否出现异常 */ @After("declareJointPointExpression()") public void afterMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method " + methodName + " ends"); } /** * 在方法法正常结束受执行的代码 * 返回通知是可以访问到方法的返回值的! */ @AfterReturning(value="declareJointPointExpression()", returning="result") public void afterReturning(JoinPoint joinPoint, Object result){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method " + methodName + " ends with " + result); } /** * 在目标方法出现异常时会执行的代码. * 可以访问到异常对象; 且可以指定在出现特定异常时在执行通知代码 */ @AfterThrowing(value="declareJointPointExpression()", throwing="e") public void afterThrowing(JoinPoint joinPoint, Exception e){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method " + methodName + " occurs excetion:" + e); } /** * 环绕通知需要携带 ProceedingJoinPoint 类型的参数. * 环绕通知类似于动态代理的全过程: ProceedingJoinPoint 类型的参数可以决定是否执行目标方法. * 且环绕通知必须有返回值, 返回值即为目标方法的返回值 */ @Around("execution(public int com.spring.aop.ArithmeticCalculator.*(..))") public Object aroundMethod(ProceedingJoinPoint pjd){ 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); throw new RuntimeException(e); } //后置通知 System.out.println("The method " + methodName + " ends"); return result; } }
    转载请注明原文地址: https://ju.6miu.com/read-17178.html

    最新回复(0)