vue面向切面_Spring Boot之面向切面编程:Spring AOP

前言

来啦老铁!

笔者学习Spring Boot有一段时间了,附上Spring Boot系列学习文章,欢迎取阅、赐教:

之前在刚学习Spring Boot的时候有看到AOP,还是挺容易的,但没有实践一下,而近期由于某些原因,几次被问及AOP,作为系统学习Spring Boot的咱们,当然不能落下Spring AOP!

AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,是面向对象编程的补充,它提供了另外一种思路来实现应用系统的公共服务。AOP采用“横切”技术,解剖已封装的对象,将这种公共服务封装到一个可重用的模块中,这模块称之为“Aspect”,即“切面”。“切面”可降低系统代码冗余,降低模块间的耦合度,提升系统的可维护性。

AOP常见的使用场景:

1. 日志功能;

采用AOP之后,不需要在每一处功能中添加日志收集代码,而是在切面中统一完成这一步骤,提升了编程速度和代码整洁度!

2. 业务方法调用的权限管理;

采用AOP在处理权限管理,我们不用在所有业务代码处判断用户是否有权限调用此方法,而是在切面中统一完成这一步骤,减少了这种非核心业务的代码!

3. 数据库事务的管理;

采用AOP可以统一在执行数据库前先开启事务,在执行完成后提交事务,若执行出错,则回滚事务等。

4. 缓存方面;

我们可采用AOP技术,统一对数据进行缓存,在下次调用时,如果参数、条件等未变,则直接获取数据,而不再调取应用方法。

5. 等。

AOP有点拦截的感觉!

AOP有一些术语:

Aspect;

Joint point;

Pointcut;

Advice;

AOP proxy;

Weaving;

这些术语对我们理解、实践AOP没有太大阻碍,请自行脑补哈,我们直接上代码开始Demo!

项目代码已上传Git Hub仓库,欢迎取阅:

整体步骤

创建AOP演示项目;

引入AOP依赖;

创建演示用API;

编写AOP切面类;

验证AOP代码织入效果;

1. 创建AOP演示项目;

Spring Boot项目创建可参考文章:5分钟入手Spring Boot,此处不再介绍。

2. 引入AOP依赖;

在项目pom.xml中添加spring-boot-starter-aop依赖:

org.springframework.boot

spring-boot-starter-aop

记得安装一下依赖:

mvn install -Dmaven.test.skip=true -Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true

3. 创建演示用API;

项目内创建controller包,包内创建一个controller,如HelloWorldController.java,HelloWorldController内创建一个用于演示用的API:

package com.github.dylanz666.controller;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.RestController;

/**

* @author : dylanz

* @since : 10/22/2020

*/

@RestController

public class HelloWorldController {

@GetMapping("/api/hello")

public String sayHello(@RequestParam String user) {

return "Hello " + user;

}

}

此处特地写了一个需要参数的API,我将把API处理过程进行横切,在API请求前后做一些系统级别的操作,但不影响业务过程。

4. 编写AOP切面类;

在项目内创建config包,在包内创建一个config类,如AOPConfig.java,在AOPConfig编写如下代码:

package com.github.dylanz666.config;

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.Aspect;

import org.springframework.context.annotation.Configuration;

import org.springframework.web.context.request.RequestContextHolder;

import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

import java.util.Arrays;

/**

* @author : dylanz

* @since : 10/22/2020

*/

@Configuration

@Aspect

public class AOPConfig {

@Around("@within(org.springframework.web.bind.annotation.RestController)")

public Object simpleAop(final ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

assert attributes != null;

HttpServletRequest request = attributes.getRequest();

System.out.println("client ip:" + request.getRemoteAddr());

Object[] args = proceedingJoinPoint.getArgs();

System.out.println("args:" + Arrays.asList(args));

Object object = proceedingJoinPoint.proceed();

System.out.println("return: " + object);

return object;

}

}

稍微解读一下:

1). @Aspect,声明了这个类是个切面类;

2). @Around,声明了一个表达式,描述了要织入的目标特性;

比如本例@within表示目标类型带有注解,且其注解类型为 org.springframework.web.bind.annotation.RestController(如果API的注解用的是@Conrtoller,则此处为 org.springframework.stereotype.Controller),这样系统内所有RestController方法(Rest API,也即带有@RestController注解的controller类中的方法)被调用的时候,都会执行@Around注解的方法,也就是本例的simpleAop方法;

除了@Around(方法执行前后织入代码),还有@Before、@After、@AfterReturning、@AfterThrowing,他们均分别表示该织入代码用于执行方法前、执行方法后、方法返回后、方法抛出异常后,如:

@Before("@within(org.springframework.web.bind.annotation.RestController)")

public void before(JoinPoint joinPoint) throws Throwable {

Object[] args = joinPoint.getArgs();

System.out.println("args:" + Arrays.asList(args));

ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

assert attributes != null;

HttpServletRequest request = attributes.getRequest();

System.out.println("client ip:" + request.getRemoteAddr());

}

我们在执行方法前打印请求参数和客户端ip;

3). 除了Around注解的方法可以传ProceedingJionPoint类型的参数外,其余的几个都不能传ProceedingJionPoint类型的参数;

4). simpleAop(名字任意)是用来织入的代码,我们可以利用参数ProceedingJoinPoint提供的方法,来对请求前后进行系统级别操作。

例如本例在接收到API请求还未执行业务代码时将客户端ip、请求参数打印出来,然后在业务代码执行完成后未返回给客户端前,将返回结果先打印出来;

5). 通常当切面代码执行完后,我们需要继续执行应用代码,并将返回对象正常返回,Object object = proceedingJoinPoint.proceed();就是为了完成这一过程;

6). 除了@within这种切面目标匹配表达式外,Spring AOP还提供了多种可选的表达式及表达式组合:

(1). within();

(2). @within;

(3). execution(),如:

execution(public * *(...));

execution(* set*(...));

execution(public set*(...));

execution(public com.xyz.service..set(...));

(4). target();

(5). @target;

(6). args();

(7). @args();

(8). @annotation();

(9). this();

(10). @Transactional;

等,读者可自行展开学习!

5. 验证AOP代码织入效果;

1). 项目整体结构:

项目整体结构

2). 启动项目:

启动项目

3). 访问API:

访问API

4). 后端执行切面代码:

后端执行切面代码

我们可以看到,在API执行前,打印了手机的ip地址:192.168.0.100,同时打印了请求参数值:dylanz,在API对应的方法执行后,打印方法返回的Hello dylanz字符串给客户端,然后将该字符串传给客户端,之后我们便能在手机客户端看到Hello dylanz字符串!

不难看出,我们可以将这些打印换成日志打印,就能全局收集详细的信息!

或者也可在切面中做一些缓存操作、数据库事务方面的行为等。

至此,我们完成了一个简单的Spring AOP案例,整个过程简单而不失灵活,灵活而不失优雅,有没有?

如果本文对您有帮助,麻烦点赞+关注!

谢谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值