使用完全注解的方式进行AOP功能实现(@Aspect+@Configuration+@EnableAspectJAutoProxy+@ComponentScan)

使用完全注解的方式进行AOP功能实现(@Aspect+@Configuration+@EnableAspectJAutoProxy+@ComponentScan)

1、⭐⭐⭐简单介绍🌙🌙🌙

如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP,如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换.本文中由于使用的是没接口的,所以会采用cglib实现动态代理。

2、⭐⭐⭐注解说明🌙🌙🌙

@Aspect表示该类是一个用于设置AOP切面相关的切面类@Pointcut 来声明切入点表达式@Order 注解指定切面的优先级, 值越小优先级越高@Before在方法开始之前执行一段代码@After在方法执行之后执行的代码. 无论该方法是否出现异常@AfterReturning在方法法正常结束受执行的代码,返回通知是可以访问到方法的返回值的!@AfterThrowing在目标方法出现异常时会执行的代码.可以访问到异常对象; 且可以指定在出现特定异常时在执行通知代码@Around环绕通知需要携带 ProceedingJoinPoint 类型的参数.环绕通知类似于动态代理的全过程: ProceedingJoinPoint 类型的参数可以决定是否执行目标方法.且环绕通知必须有返回值, 返回值即为目标方法的返回值@Configuration//用于定义配置类,可替换xml配置文件@EnableAspectJAutoProxy(proxyTargetClass=true) //开启AspectJ 自动代理模式,如果不填proxyTargetClass=true,默认为false(代表即便你配置了@EnableAspectJAutoProxy,也不会开启代理模式,调试的时候我就被卡在这里蛮久...)@ComponentScan(basePackages = "com.atguigu.spring5.configuration2")//扫描注入类

3、⭐⭐⭐示例代码🌙🌙🌙:

<1>简单的bean对象 User.java

package com.atguigu.spring5.configuration2;

import org.springframework.stereotype.Component;

@Component("user")

public class User {

public void add(){

System.out.println("add ...");

}

}

<2>用于替换以前bean的xml配置文件的配置类 SpringConfiguration.java

package com.atguigu.spring5.configuration2;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.ComponentScan;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.EnableAspectJAutoProxy;

import org.springframework.stereotype.Component;

//即使用jdk默认代理模式,AspectJ代理模式是CGLIB代理模式

//如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP

//如果目标对象实现了接口,可以强制使用CGLIB实现AOP (此例子我们就是强制使用cglib实现aop)

//如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

@Configuration//用于定义配置类,可替换xml配置文件

@EnableAspectJAutoProxy(proxyTargetClass=true) //开启AspectJ 自动代理模式,如果不填proxyTargetClass=true,默认为false

@ComponentScan(basePackages = "com.atguigu.spring5.configuration2")//扫描注入类

public class SpringConfiguration {

@Bean

public User user() {

return new User();

}

}

<3>用于替换bean的xml配置文件里AOP相关的配置类LoggingAspect .java

package com.atguigu.spring5.configuration2;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.annotation.*;

import org.springframework.context.annotation.EnableAspectJAutoProxy;

import org.springframework.stereotype.Component;

import java.util.Arrays;

/**

* 可以使用 @Order 注解指定切面的优先级, 值越小优先级越高

*/

//@Order(2)

@Aspect

@Component

public class LoggingAspect {

/**

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

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

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

*/

@Pointcut("execution(public void com.atguigu.spring5.configuration2.User.*(..))")

public void declareJointPointExpression(){

}

/**

* 在 com.atguigu.spring5.aop.User 接口的每一个实现类的每一个方法开始之前执行一段代码

*/

@Before("declareJointPointExpression()")

public void beforeMethod(JoinPoint joinPoint){

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

Object [] args = joinPoint.getArgs();

System.out.println("The beforeMethod " + methodName + " begins with " + Arrays.asList(args));

}

/**

* 在方法执行之后执行的代码. 无论该方法是否出现异常

*/

@After("declareJointPointExpression()")

public void afterMethod(JoinPoint joinPoint){

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

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

}

/**

* 在方法法正常结束受执行的代码

* 返回通知是可以访问到方法的返回值的!

*/

@AfterReturning(value="declareJointPointExpression()",returning="result")

public void afterReturning(JoinPoint joinPoint, Object result){

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

System.out.println("The afterReturning " + 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 afterThrowing " + methodName + " occurs excetion:" + e);

}

/**

* 环绕通知需要携带 ProceedingJoinPoint 类型的参数.

* 环绕通知类似于动态代理的全过程: ProceedingJoinPoint 类型的参数可以决定是否执行目标方法.

* 且环绕通知必须有返回值, 返回值即为目标方法的返回值

*/

/*

@Around("execution(public int com.atguigu.springspring5.aop.User.*(..))")

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;

}

*/

}

<4>测试类TestAnnotationConfig.java

package com.atguigu.spring5.configuration2;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import org.springframework.context.annotation.ComponentScan;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.EnableAspectJAutoProxy;

public class TestAnnotationConfig {

public static void main(String[] args) {

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfiguration.class);

User user = ctx.getBean(User.class);

user.add();

}

}

<5>运行测试类TestAnnotationConfig.java结果如下:

4、核心代码逻辑及思维导图

以下是文章中提到的使用完全注解方式进行AOP功能实现的核心逻辑,转换成横向的思维导图:

graph LR

A["AOP注解实现"] -->|定义切面类| B["@Aspect"]

A -->|声明切入点| C["@Pointcut"]

A -->|指定切面优先级| D["@Order"]

A -->|方法执行前| E["@Before"]

A -->|方法执行后| F["@After"]

A -->|方法正常返回后| G["@AfterReturning"]

A -->|方法抛出异常后| H["@AfterThrowing"]

A -->|环绕方法执行| I["@Around"]

A -->|定义配置类| J["@Configuration"]

A -->|开启AspectJ自动代理| K["@EnableAspectJAutoProxy"]

A -->|扫描组件包路径| L["@ComponentScan"]

A -->|具体实现类| M["示例代码"]

M -->|业务逻辑类| M1["User 类"]

M -->|配置Spring环境| M2["SpringConfiguration 类"]

M -->|定义切面逻辑| M3["LoggingAspect 类"]

M -->|运行AOP测试| M4["TestAnnotationConfig 类"]

在这个思维导图中,每个注解和配置类都有了更详细的说明,描述了它们在AOP实现中的作用:

@Aspect: 定义一个类作为切面类。

@Pointcut: 声明一个切入点,指定哪些方法可以被拦截。

@Order: 指定切面的执行顺序,值越小优先级越高。

@Before: 在目标方法执行之前执行的逻辑。

@After: 在目标方法执行之后执行的逻辑,无论是否抛出异常。

@AfterReturning: 当目标方法正常执行完成后执行的逻辑。

@AfterThrowing: 当目标方法抛出异常时执行的逻辑。

@Around: 环绕通知,可以在方法执行前后添加逻辑。

@Configuration: 定义配置类,用于替代XML配置。

@EnableAspectJAutoProxy: 开启AspectJ的自动代理功能。

@ComponentScan: 指定Spring扫描组件的包路径。

示例代码: 包含具体的实现类。

每个示例代码的子节点也都有相应的说明:

User 类: 业务逻辑类,被AOP代理的目标对象。

SpringConfiguration 类: 配置Spring环境,包括Bean的定义和AOP的配置。

LoggingAspect 类: 定义切面逻辑,包括各种通知类型的实现。

TestAnnotationConfig 类: 运行AOP测试的入口类。

相关数据

畞的解释
365BET是不是上市了

畞的解释

⌛ 09-01 👁️‍🗨️ 6733
天玑720处理器怎么样 天玑720相当于麒麟多少
365BET是不是上市了

天玑720处理器怎么样 天玑720相当于麒麟多少

⌛ 08-07 👁️‍🗨️ 9064
动车时速,动车速度
365BET是不是上市了

动车时速,动车速度

⌛ 06-30 👁️‍🗨️ 202
dnf阿修罗115毕业套装
office365

dnf阿修罗115毕业套装

⌛ 07-16 👁️‍🗨️ 1991
iOS 为什么用起来就是特别顺滑?
365BET是不是上市了

iOS 为什么用起来就是特别顺滑?

⌛ 08-05 👁️‍🗨️ 2222
热点 | 国足基本退出“世界杯出线”争夺,李铁回应!
mobileBET365

热点 | 国足基本退出“世界杯出线”争夺,李铁回应!

⌛ 07-19 👁️‍🗨️ 7408