spring AOP (使用AspectJ的注解方式 的aop实现) (6)

本文内容纲要:

- 一、在 Spring 中启用 AspectJ 注解支持

- 二、AspectJ 支持 5 种类型的通知注解:

- 2.1、使用之前的 计算器接口和实现类 ArithmeticCalculator.java , ArithmeticCalculatorImpl.java

- 2.2、在xml中增加扫描注解和aspectj的支持

- 2.3、编写切面类,定义各种通知

前面的动态代理中,可以有前置通知,后置通知,返回通知,异常通知

在spring2.0以后,可以使用基于 AspectJ 注解或基于 XML 配置的 AOP

  • AspectJ:Java 社区里最完整最流行的 AOP 框架.

目录

  • 一、在 Spring 中启用 AspectJ 注解支持

  • 二、AspectJ 支持 5 种类型的通知注解:

    • 2.1、使用之前的 计算器接口和实现类 ArithmeticCalculator.java , ArithmeticCalculatorImpl.java
    • 2.2、在xml中增加扫描注解和aspectj的支持
    • 2.3、编写切面类,定义各种通知

一、在 Spring 中启用 AspectJ 注解支持

  • 1要在 Spring 应用中使用 AspectJ 注解, 必须在 classpath 下包含 AspectJ 类库: aopalliance.jar、aspectj.weaver.jar 和 spring-aspects.jar

    maven 引入

    org.springframework

    spring-aop

    4.1.9.RELEASE

    org.springframework

    spring-aspects

    4.1.9.RELEASE

    org.aspectj

    aspectjrt

    1.6.8

    org.aspectj

    aspectjweaver

    1.6.8

    runtime

  • 2将 aop Schema 添加到 根元素中.

  • 3要在 Spring IOC 容器中启用 AspectJ 注解支持, 只要在 Bean 配置文件中定义一个空的 XML 元素

  • 4当 Spring IOC 容器侦测到 Bean 配置文件中的 aop:aspectj-autoproxy 元素时, 会自动为与 AspectJ 切面匹配的 Bean 创建代理.

二、AspectJ 支持 5 种类型的通知注解:

  • @Before: 前置通知, 在方法执行之前执行
  • @After: 后置通知, 在方法执行之后执行
  • @AfterRunning: 返回通知, 在方法返回结果之后执行
  • @AfterThrowing: 异常通知, 在方法抛出异常之后
  • @Around: 环绕通知, 围绕着方法执行

2.1、使用之前的 计算器接口和实现类 ArithmeticCalculator.java , ArithmeticCalculatorImpl.java

@Component("arithmeticCalculator")

public class ArithmeticCalculatorImpl implements ArithmeticCalculator{}

2.2、在xml中增加扫描注解和aspectj的支持

<?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:context="http://www.springframework.org/schema/context"

xmlns:aop="http://www.springframework.org/schema/aop"

xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd

http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">

<!-- 配置自动扫描的包 -->

<context:component-scan base-package="com.hp.spring.aop.annotation"></context:component-scan>

<!-- 配置自动为匹配 aspectJ 注解的 Java 类生成代理对象 -->

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>

2.3、编写切面类,定义各种通知

@Aspect //注解定义切面

@Component

public class LoggingAspect {

//前置通知

@Before("execution(public int com.hp.spring.aop.annatation.ArithmeticCalculator.*(int, int))")

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("execution(* com.hp.spring.aop.annatation.*.*(..))")

public void afterMethod(JoinPoint joinPoint){

String methodName = joinPoint.getSignature().getName();

System.out.println("The method " + methodName + " ends");

}

}

由于@before 和@after的表达式都一样,所以spring支持对表达式进行抽取成一个方法,抽取后的代码如下:

package com.hp.spring.aop.annotation;

import java.util.Arrays;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.annotation.After;

import org.aspectj.lang.annotation.AfterReturning;

import org.aspectj.lang.annotation.AfterThrowing;

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(2)

@Aspect

@Component

public class LoggingAspect {

/**

* 定义一个方法, 用于声明切入点表达式. 一般地, 该方法中再不需要添入其他的代码.

* 使用 @Pointcut 来声明切入点表达式.

* 后面的其他通知直接使用方法名来引用当前的切入点表达式.

*/

@Pointcut("execution(public int com.hp.spring.aop.annotation.ArithmeticCalculator.*(..))")

public void declareJointPointExpression(){}

/**

* 在 com.hp.spring.aop.annotation.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.hp.spring.aop.annotation.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;

}

*/

}

  • 切面二

    package com.hp.spring.aop.annotation;

    import java.util.Arrays;

    import org.aspectj.lang.JoinPoint;

    import org.aspectj.lang.annotation.Aspect;

    import org.aspectj.lang.annotation.Before;

    import org.springframework.core.annotation.Order;

    import org.springframework.stereotype.Component;

    @Order(1)

    @Aspect

    @Component

    public class VlidationAspect {

    @Before("com.hp.spring.aop.annotation.LoggingAspect.declareJointPointExpression()")

    public void validateArgs(JoinPoint joinPoint){

    System.out.println("-->validate:" + Arrays.asList(joinPoint.getArgs()));

    }

    }

  • 测试类

    package com.hp.spring.aop.annotation;

    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-aspectj.xml");

    ArithmeticCalculator arithmeticCalculator = (ArithmeticCalculator) ctx.getBean("arithmeticCalculator");

    System.out.println(arithmeticCalculator.getClass().getName());

    int result = arithmeticCalculator.add(1, 2);

    System.out.println("result:" + result);

    result = arithmeticCalculator.div(1000, 10);

    System.out.println("result:" + result);

    }

    }

打印出:

com.sun.proxy.$Proxy12

-->validate:[1, 2]

The method add begins with [1, 2]

The method add ends

The method add ends with 3

result:3

-->validate:[1000, 10]

The method div begins with [1000, 10]

The method div ends

The method div ends with 100

result:100

打印的日志中,可以看出,跟动态代理一样,可以定义各类通知。

整个系列项目代码: http://git.oschina.net/nmc5/spring

本文内容总结:一、在 Spring 中启用 AspectJ 注解支持,二、AspectJ 支持 5 种类型的通知注解:,2.1、使用之前的 计算器接口和实现类 ArithmeticCalculator.java , ArithmeticCalculatorImpl.java,2.2、在xml中增加扫描注解和aspectj的支持,2.3、编写切面类,定义各种通知,

原文链接:https://www.cnblogs.com/linhp/p/5881798.html

以上是 spring AOP (使用AspectJ的注解方式 的aop实现) (6) 的全部内容, 来源链接: utcz.com/z/296901.html

回到顶部