原文: https://howtodoinjava.com/spring-aop/aspectj-around-annotation-example/

在此 Spring 操作示例中,我们将学习使用 Aspectj @Around注解@Around带注解的方法在与切入点表达式匹配的所有方法之前和之后运行。

在此示例中,我们将创建一个简单的 spring 应用程序,添加记录切面周围的内容,然后基于@Around注解中传递的切入点信息调用切面方法。

1. AspectJ @Around注解用法

@Around建议包围了连接点,例如方法调用。 这是最有力的建议。 围绕建议可以在方法调用之前和之后执行自定义行为。 它还负责选择是返回连接点还是通过返回其自身的返回值或引发异常来捷径建议的方法执行。

  1. @Aspect
  2. public class LoggingAspect {
  3. @Around("execution(* com.howtodoinjava.app.service.impl.EmployeeManagerImpl.*(..))")
  4. public void logAroundAllMethods(ProceedingJoinPoint joinPoint) { ... }
  5. @Around("execution(* com.howtodoinjava.app.service.impl.EmployeeManagerImpl.getEmployeeById(..))")
  6. public void logAroundGetEmployee(ProceedingJoinPoint joinPoint) { ... }
  7. }

不要忘记使用ProceedingJoinPoint作为参数。 您必须调用ProceedingJoinPoint.proceed()方法,否则将执行原始方法。

2. 项目结构

Spring AOP AspectJ `@Around`注解示例 - 图1

Spring AOP 项目结构

3. Spring AOP AspectJ maven 依赖项

我添加了 spring 核心,spring aop 和 Aspectj 依赖项。

  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd;
  3. <modelVersion>4.0.0</modelVersion>
  4. <groupId>com.howtodoinjava</groupId>
  5. <artifactId>SpringAOPExamples</artifactId>
  6. <version>0.0.1-SNAPSHOT</version>
  7. <name>Spring AOP Examples</name>
  8. <dependencies>
  9. <dependency>
  10. <groupId>org.springframework</groupId>
  11. <artifactId>spring-context</artifactId>
  12. <version>4.3.2.RELEASE</version>
  13. </dependency>
  14. <dependency>
  15. <groupId>org.springframework</groupId>
  16. <artifactId>spring-context-support</artifactId>
  17. <version>4.3.2.RELEASE</version>
  18. </dependency>
  19. <dependency>
  20. <groupId>org.springframework</groupId>
  21. <artifactId>spring-aop</artifactId>
  22. <version>4.3.2.RELEASE</version>
  23. </dependency>
  24. <dependency>
  25. <groupId>org.aspectj</groupId>
  26. <artifactId>aspectjrt</artifactId>
  27. <version>1.8.9</version>
  28. </dependency>
  29. <dependency>
  30. <groupId>org.aspectj</groupId>
  31. <artifactId>aspectjweaver</artifactId>
  32. <version>1.8.9</version>
  33. </dependency>
  34. </dependencies>
  35. </project>

4. 启用 Spring AOP AspectJ 支持

在 XML 配置文件中,您可以添加aop:aspectj-autoproxy元素以启用@AspectJ注解支持。

  1. <beans xmlns="http://www.springframework.org/schema/beans"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xmlns:aop="http://www.springframework.org/schema/aop"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  6. http://www.springframework.org/schema/aop
  7. http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">
  8. <!-- Enable @AspectJ annotation support -->
  9. <aop:aspectj-autoproxy />
  10. <!-- Employee manager -->
  11. <bean id="employeeManager" class="com.howtodoinjava.app.service.impl.EmployeeManagerImpl" />
  12. <!-- Logging Aspect -->
  13. <bean id="loggingAspect" class="com.howtodoinjava.app.aspect.LoggingAspect" />
  14. </beans>

5. 需要执行@Around切面的方法

EmployeeManager.javaEmployeeManagerImpl.java

  1. public interface EmployeeManager
  2. {
  3. public EmployeeDTO getEmployeeById(Integer employeeId);
  4. public List<EmployeeDTO> getAllEmployee();
  5. public void createEmployee(EmployeeDTO employee);
  6. public void deleteEmployee(Integer employeeId);
  7. public void updateEmployee(EmployeeDTO employee);
  8. }
  9. public class EmployeeManagerImpl implements EmployeeManager
  10. {
  11. public EmployeeDTO getEmployeeById(Integer employeeId)
  12. {
  13. System.out.println("Method getEmployeeById() called");
  14. return new EmployeeDTO();
  15. }
  16. public List<EmployeeDTO> getAllEmployee()
  17. {
  18. System.out.println("Method getAllEmployee() called");
  19. return new ArrayList<EmployeeDTO>();
  20. }
  21. public void createEmployee(EmployeeDTO employee)
  22. {
  23. System.out.println("Method createEmployee() called");
  24. }
  25. public void deleteEmployee(Integer employeeId)
  26. {
  27. System.out.println("Method deleteEmployee() called");
  28. }
  29. public void updateEmployee(EmployeeDTO employee)
  30. {
  31. System.out.println("Method updateEmployee() called");
  32. }
  33. }

6. 编写 AspectJ 注解的类和方法

用切入点信息编写 aspectj 注解的类和方法。

  1. @Aspect
  2. public class LoggingAspect {
  3. @Around("execution(* com.howtodoinjava.app.service.impl.EmployeeManagerImpl.*(..))")
  4. public void logAroundAllMethods(ProceedingJoinPoint joinPoint) throws Throwable
  5. {
  6. System.out.println("****LoggingAspect.logAroundAllMethods() : " + joinPoint.getSignature().getName() + ": Before Method Execution");
  7. try {
  8. joinPoint.proceed();
  9. } finally {
  10. //Do Something useful, If you have
  11. }
  12. System.out.println("****LoggingAspect.logAroundAllMethods() : " + joinPoint.getSignature().getName() + ": After Method Execution");
  13. }
  14. @Around("execution(* com.howtodoinjava.app.service.impl.EmployeeManagerImpl.getEmployeeById(..))")
  15. public void logAroundGetEmployee(ProceedingJoinPoint joinPoint) throws Throwable
  16. {
  17. System.out.println("****LoggingAspect.logAroundGetEmployee() : " + joinPoint.getSignature().getName() + ": Before Method Execution");
  18. try {
  19. joinPoint.proceed();
  20. } finally {
  21. //Do Something useful, If you have
  22. }
  23. System.out.println("****LoggingAspect.logAroundGetEmployee() : " + joinPoint.getSignature().getName() + ": After Method Execution");
  24. }
  25. @Around("execution(* com.howtodoinjava.app.service.impl.EmployeeManagerImpl.createEmployee(..))")
  26. public void logAroundCreateEmployee(ProceedingJoinPoint joinPoint) throws Throwable
  27. {
  28. System.out.println("****LoggingAspect.logAroundCreateEmployee() : " + joinPoint.getSignature().getName() + ": Before Method Execution");
  29. try {
  30. joinPoint.proceed();
  31. } finally {
  32. //Do Something useful, If you have
  33. }
  34. System.out.println("****LoggingAspect.logAroundCreateEmployee() : " + joinPoint.getSignature().getName() + ": After Method Execution");
  35. }
  36. }

7. Spring AspectJ @Around示例

现在,我们来测试以上配置的切面是否在给定的切入点信息上执行。

  1. import org.springframework.context.ApplicationContext;
  2. import org.springframework.context.support.ClassPathXmlApplicationContext;
  3. import com.howtodoinjava.app.model.EmployeeDTO;
  4. import com.howtodoinjava.app.service.EmployeeManager;
  5. public class TestMain
  6. {
  7. @SuppressWarnings("resource")
  8. public static void main(String[] args) {
  9. ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  10. EmployeeManager manager = (EmployeeManager) context.getBean("employeeManager");
  11. manager.getEmployeeById(1);
  12. manager.createEmployee(new EmployeeDTO());
  13. }
  14. }
  1. ****LoggingAspect.logAroundAllMethods() : getEmployeeById: Before Method Execution
  2. ****LoggingAspect.logAroundGetEmployee() : getEmployeeById: Before Method Execution
  3. Method getEmployeeById() called
  4. ****LoggingAspect.logAroundGetEmployee() : getEmployeeById: After Method Execution
  5. ****LoggingAspect.logAroundAllMethods() : getEmployeeById: After Method Execution
  6. ****LoggingAspect.logAroundAllMethods() : createEmployee: Before Method Execution
  7. ****LoggingAspect.logAroundCreateEmployee() : createEmployee: Before Method Execution
  8. Method createEmployee() called
  9. ****LoggingAspect.logAroundCreateEmployee() : createEmployee: After Method Execution
  10. ****LoggingAspect.logAroundAllMethods() : createEmployee: After Method Execution

显然,在相关连接点周围执行切面建议。

学习愉快!

参考文献:

Spring AOP 参考

@Around注解

@Aspect注解

AspectJ 注解配置示例

不同切入点表达式以及示例