spring中AOP 注解开发示例详解

针对“spring中AOP 注解开发示例详解”的完整攻略,我将分为以下几个部分进行讲解:

1. AOP 概述

AOP,即 Aspect Oriented Programming,面向切面编程,是一种程序设计的思想,可以让程序逻辑分散到各个部分,从而增加代码的可维护性和辅助性。Spring框架提供了完善的AOP实现,可以通过纯Java编写切面代码,实现统一的业务逻辑。

2. AOP 注解详解

Spring框架的AOP机制有两种实现方式:一种是通过XML配置文件实现,另一种则是通过注解实现。其中,注解是更为常见的方式,比XML更加简洁明了,而且维护成本更低。下面是常用的AOP注解:

注解 描述
@Aspect 表明该类是一个切面,用于声明通知和切点
@Before 在切点之前执行通知
@After 在切点之后执行通知
@AfterReturning 在切点方法返回后执行通知
@AfterThrowing 在切点方法抛出异常后执行通知
@Around 在切点前后都会执行的通知

3. AOP 注解示例一

首先,我们创建一个Calculator接口,定义两个方法:加法和减法。

public interface Calculator {
    int add(int a, int b);
    int sub(int a, int b);
}

然后,创建一个实现类CalculatorImpl,实现Calculator接口。

public class CalculatorImpl implements Calculator {
    @Override
    public int add(int a, int b) {
        return a + b;
    }

    @Override
    public int sub(int a, int b) {
        return a - b;
    }
}

接下来,我们需要创建一个切面类LoggingAspect,并且在这个类中添加@Aspect注解。

@Aspect
@Component
public class LoggingAspect {

}

然后,我们需要在这个切面类中定义一个切点,通过@Pointcut注解来定义。

@Pointcut("execution(* com.example.demo.Calculator.*(..))")
public void pointcut() {}

上面这个切点表示匹配Calculator接口下的所有方法。

接着,我们需要定义通知,并且通过@Before注解实现前置通知。在LoggingAspect类中实现如下方法:

@Before("pointcut()")
public void before(JoinPoint joinPoint) {
    String methodName = joinPoint.getSignature().getName();
    Object[] args = joinPoint.getArgs();
    System.out.println("执行方法 " + methodName + " 前,参数为:" + Arrays.toString(args));
}

最后,我们就可以在DemoApplication中调用Calculator的方法,观察是否有输出日志。

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
        Calculator calculator = new CalculatorImpl();
        int result = calculator.add(1, 2);
        System.out.println("1+2=" + result);
        result = calculator.sub(3, 4);
        System.out.println("3-4=" + result);
    }

}

如果控制台输出如下内容,则说明实现成功。

执行方法 add 前,参数为:[1, 2]
1+2=3
执行方法 sub 前,参数为:[3, 4]
3-4=-1

4. AOP 注解示例二

现在,我们通过一个更加复杂的示例来观察AOP注解的用法。我们需要创建一个UserService接口,并且定义两个方法:通过用户名查找用户和保存用户。

public interface UserService {
    User getUser(String username);
    void saveUser(User user);
}

其中,User是一个模型类。

public class User {
    private String username;
    private String password;
    // getter 和 setter 略
}

接下来,创建一个实现类UserServiceImpl,实现UserService接口并且添加@Component注解。

@Service
public class UserServiceImpl implements UserService {
    private Map<String, User> users = new HashMap<>();

    @Override
    public User getUser(String username) {
        return users.get(username);
    }

    @Override
    public void saveUser(User user) {
        users.put(user.getUsername(), user);
    }
}

然后,我们需要创建一个切面类UserServiceAspect

@Aspect
@Component
public class UserServiceAspect {
    private final Logger logger = LoggerFactory.getLogger(UserServiceAspect.class);

    @Before("execution(* com.example.demo.UserService.*(..)) && args(username, ..)")
    public void before(String username) {
        logger.info("[before]开始查找用户:{}", username);
    }

    @AfterReturning(value = "execution(* com.example.demo.UserService.*(..))", returning = "result")
    public void after(User result) {
        logger.info("[after]用户信息:{}", result);
    }

    @Around("execution(* com.example.demo.UserService.*(..)) && args(user, ..)")
    public void around(ProceedingJoinPoint pjp, User user) throws Throwable {
        if (user.getPassword().length() < 6) {
            logger.error("[around]密码长度不能少于6个字符");
        } else {
            pjp.proceed();
        }
    }
}

我们来逐步分析这段代码。首先,在before方法中,我们定义了一个前置通知,这个通知用于输出日志信息。@Before注解中的execution()表示匹配UserService接口下所有方法,同时使用args()来匹配参数是String类型的方法,并且可以通过..来表示任意参数。

接着,在after方法中,我们定义了一个后置通知,这个通知用于输出用户信息。@AfterReturning注解中的execution()args()的含义与before方法中相同,同时使用returning属性来匹配返回值为User类型的方法。

最后,在around方法中,我们定义了一个环绕通知,这个通知用于校验密码长度。@Around注解中的execution()args()的含义与before方法中相同,同时在方法体中,我们可以通过ProceedingJoinPoint类和proceed()方法来实现对方法的执行。如果密码长度小于6个字符,我们将输出错误日志,否则将继续执行方法。

最后,我们在DemoApplication中调用UserService中的方法,观察是否有输出日志。

@Service
public class DemoApplication implements CommandLineRunner {
    @Autowired
    private UserService userService;

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        User user1 = new User();
        user1.setUsername("xiaoming");
        user1.setPassword("123");
        userService.saveUser(user1);

        User user2 = new User();
        user2.setUsername("xiaowang");
        user2.setPassword("123456");
        userService.saveUser(user2);

        User user3 = userService.getUser("xiaoming");
        User user4 = userService.getUser("xiaowang");
    }
}

控制台输出如下内容,则说明实现成功。

[around]密码长度不能少于6个字符
[before]开始查找用户:xiaoming
[before]开始查找用户:xiaowang
[after]用户信息:User{username='xiaowang', password='123456'}

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:spring中AOP 注解开发示例详解 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • Java线程优先级变量及功能

    Java线程优先级变量及功能攻略 1. 什么是线程优先级 在Java中,每个线程都有一个优先级,用来确定线程在竞争资源时的调度顺序。线程优先级的范围是1到10,默认值为5。较高优先级的线程在竞争资源时有更大的机会被调度执行,但是并不能保证绝对的执行顺序。 2. 设置线程优先级 Java线程优先级的设置可以通过setPriority()方法实现。该方法接受一个…

    other 2023年6月28日
    00
  • 秒懂sqlintersect

    当然,我很乐意为您提供有关“秒懂SQL Intersect”的完整攻略。以下是详细的步骤和两个示例: 1 SQL Intersect SQL Intersect是一种用于比较两个或多个SELECT语句结果的操作符。它返回两个结果集的交集,即两个结果集中都存在的行。 2 SQL Intersect语法 以下是SQLsect的语法: SELECT column1…

    other 2023年5月6日
    00
  • 如何恢复TP-LINK无线路由器的用户名和密码?

    如何恢复TP-LINK无线路由器的用户名和密码? 如果您忘记了TP-LINK无线路由器的用户名和密码,恢复甚至重置路由器是一个不错的解决办法。下面我们详细介绍如何恢复TP-LINK无线路由器的用户名和密码。 步骤一:连接路由器 将计算机或笔记本电脑通过网线连接到 TP-LINK 无线路由器的 LAN 口上,确保您可以通过网线连接到路由器。然后打开浏览器,在地…

    other 2023年6月27日
    00
  • Android彻底清除APP数据的两种方案总结

    Android彻底清除APP数据的两种方案总结 在Android开发中,有时我们需要彻底清除应用的数据,包括缓存、数据库、SharedPreferences等。下面是两种常见的方案来实现这个目标: 方案一:使用应用管理器清除数据 Android提供了应用管理器来管理应用的信息和数据。我们可以通过应用管理器来清除应用的数据。具体步骤如下: String pac…

    other 2023年10月13日
    00
  • c++ 入门——浅析构造函数和析构函数

    关于“c++ 入门——浅析构造函数和析构函数”的攻略,我们可以分为以下三个部分来进行讲解: 一、构造函数 1.1 什么是构造函数 构造函数是一类特殊的成员函数,当我们创建类的新对象时,就会自动被调用。它的作用是初始化对象的成员变量。 class Test{ public: Test(int a, int b){ x = a; y = b; } private…

    other 2023年6月26日
    00
  • 服务端拼接json数据格式的正确写法(Append方式)

    当服务端需要输出一段JSON代码时,正确的写法是通过字符串拼接得到完整的JSON代码,并将其作为响应数据返回给客户端。下面是服务端拼接JSON数据格式的正确写法,使用Append方式实现。 1.准备数据 首先需要准备的是需要输出为JSON格式的数据,具体格式可以自定义。以一个简单的用户信息为例: var name = "张三"; var …

    other 2023年6月27日
    00
  • Java递归遍历树形结构的实现代码

    下面是详细讲解“Java递归遍历树形结构的实现代码”的完整攻略。 什么是树形结构 树形结构是一种具有层次和父子关系的数据结构,每个节点可以有零个或多个子节点,并且只有一个根节点。 在编程中,树形结构经常用来表示层次关系,比如文件系统、部门组织架构等等。 Java递归遍历树形结构的实现 在Java中,递归是遍历树形结构的常用方法,主要思路是从根节点开始访问所有…

    other 2023年6月27日
    00
  • unicode编码解码在线转换工具

    unicode编码解码在线转换工具 Unicode编码是一种国际化编码标准,它为世界范围内的大部分语言字符提供了统一的编码方式。不同于常见的ASCII编码,它包括了许多如汉字、日语假名、阿拉伯字母等字符。 对于需要处理多语言字符的开发者们,通过网页进行Unicode编码与解码已经成为了经常需要操作的事情。这时候我们需要一个可以方便地进行转换的在线工具。本文将…

    其他 2023年3月29日
    00
合作推广
合作推广
分享本页
返回顶部