300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > SpringBoot-AOP深入浅出通俗易懂—看不懂你捶鹅

SpringBoot-AOP深入浅出通俗易懂—看不懂你捶鹅

时间:2019-04-22 06:04:05

相关推荐

SpringBoot-AOP深入浅出通俗易懂—看不懂你捶鹅

目录

前言

AOP总体思想

AOP图解

AOP-Aspect-代码举例

1、定义Service

2. 定义LoginController

3. 定义UserLoginAspect切面

AOP-Handler拦截器-代码举例

1、定义拦截器

2、注册拦截器

总结

前言

Spring最重要的两个思想就是IOC、AOP,之前的文章SpringBoot自动装配分析了IOC思想并进行了源码详解。这次看一下AOP思想。

网上有很多AOP思想的讲解,五花八门,最重要的几点都会讲到,但是很多文章不会给人恍然大悟的感觉。我这次就把我对AOP的理解总结一下。

最近整理了汇总了⼀些 Java ⾯试相关的⾼质量 PDF 资料和免费Idea账号,在公众号:Java小白,回复“⾯试” 和“idea破解”即可获取!

AOP总体思想

AOP(面向切面编程)是一种编程范式,它在软件开发中用于将横切关注点与核心业务逻辑进行解耦。

想象一下,你正在开发一个大型的 Web 应用程序。你可能会有很多模块和功能需要实现,例如点赞模块、收藏模块、评论模块等等。同时,你还需要处理一些共性的任务,例如用户信息校验、记录日志、权限验证、异常处理等。这些共性任务可能会散布在各个模块和功能的代码中,如果要逐一添加则会导致代码的重复和冗余,增加了维护成本。(这段中的红色标字就是要插入模块中的功能)

这时候,AOP 就派上了用场。AOP 允许你在不改变原有模块代码的情况下,将这些共性任务从核心业务逻辑中抽离出来,形成一个独立的横切关注点。这个横切关注点就像一个切面,可以被动态地织入到不同的模块和功能中。

以下是AOP专用名词的解释:

Aspect(切面): Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。Joint point(连接点):表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它 joint point。Pointcut(切点):表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方。Advice(增强):Advice 定义了在 Pointcut 里面定义的程序点具体要做的操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码。Target(目标对象):织入 Advice 的目标对象.。Weaving(织入):将 Aspect 和其他对象连接起来, 并创建 Adviced object 的过程。

以下是Advice中方法名词解释:

before advice, 在 join point 前被执行的 advice. 虽然 before advice 是在 join point 前被执行, 但是它并不能够阻止 join point 的执行, 除非发生了异常(即我们在 before advice 代码中, 不能人为地决定是否继续执行 join point 中的代码)after return advice, 在一个 join point 正常返回后执行的 adviceafter throwing advice, 当一个 join point 抛出异常后执行的 adviceafter(final) advice, 无论一个 join point 是正常退出还是发生了异常, 都会被执行的 advice.around advice, 在 join point 前和 joint point 退出后都执行的 advice. 这个是最常用的 advice.introduction,introduction可以为原有的对象增加新的属性和方法。

AOP图解

我画一张图来描述:

这时想在前端和controller2模块中间增加用户信息校验,没有用户信息不能点赞、收藏、评论,并跳到登陆页面。

现在,我们看到,我把Aspect放在了前端和controller中间,Joint Ponit就是负责抓取链路的,符合controller2的链路就被抓取到Pointcut中,进行Advice-Before处理这个意思我们看图也能知道,就是在进入controller方法前执行的操作,那么,Advice-After就是在controller方法结束后执行的操作。

这样的话,就在不改动原来代码的情况下,织入了登录校验步骤。

AOP-Aspect-代码举例

现在我们就从SpringBoot系统的模块中,添加一个登陆验证的AOP切面。

假设我们有一个LikeService类,其中包含了一个方法 `likePost` 用于实现用户点赞功能,以及LoginController类,用于处理用户登录逻辑,我们将在这个LoginController方法中应用 AOP 来校验用户登录状态。

1、定义Service

import org.springframework.stereotype.Service;@Servicepublic class LikeService {public void likePost() {// 点赞操作的逻辑System.out.println("Post liked!");}}

2. 定义LoginController

import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.GetMapping;@Controllerpublic class LoginController {@GetMapping("/login")public String showLoginPage() {// 展示登录页面的逻辑return "login";}}

3. 定义UserLoginAspect切面

定义UserLoginAspect切面,并指定切点对象

import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.ponent;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;import java.io.IOException;@Aspect@Componentpublic class UserLoginAspect {@Pointcut("execution(* com.example.demo.service.LikeService.likePost(..))")public void likePostPointcut() {}@Before("likePostPointcut()")public void checkUserLogin() throws IOException {HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();// 这里假设用户登录状态通过 Session 中的一个标志位来判断if (request.getSession().getAttribute("loggedInUser") == null) {// 用户未登录,跳转到登录页面System.out.println("Please login to like the post.");// 使用 redirect 实现页面跳转到登录页面request.sendRedirect("/login");} else {// 用户已登录,执行点赞操作System.out.println("Post liked!");}}}

在上述代码中,我们定义了一个Aspect命名为UserLoginAspect用于切面,Pointcut命名为likePostPointcut用于指定切点对象,这里指定为LikeService类中的likePost方法。

然后,在checkUserLogin方法上使用 @Before注解,并指定了 likePostPointcut()作为切点表达式,表示该切面将在 `LikeService` 的 `likePost` 方法执行前执行。

在 `checkUserLogin` 方法中,我们进行用户登录状态的校验,如果用户未登录,则抛出一个运行时异常并提示用户登录;如果用户已登录,则继续执行点赞操作。

请注意,在实际应用中,我们需要根据具体的业务需求,实现真正的用户登录校验逻辑,例如从 Session、Token 或数据库中验证用户登录状态。

AOP-Handler拦截器-代码举例

也可以使用 Spring MVC 的拦截器(Interceptor)来实现用户登录状态的校验和页面跳转。拦截器在 Spring MVC 中是一种更通用的方式来实现横切关注点的处理,包括用户登录校验、日志记录、权限验证等。

以下是使用拦截器实现用户登录状态校验和页面跳转的代码示例:

1、定义拦截器

定义拦截器类 `UserLoginInterceptor`:

import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;public class UserLoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {// 这里假设用户登录状态通过 Session 中的一个标志位来判断if (request.getSession().getAttribute("loggedInUser") == null) {// 用户未登录,跳转到登录页面System.out.println("Please login to like the post.");// 使用 redirect 实现页面跳转到登录页面response.sendRedirect("/login");return false; // 返回 false 阻止后续请求处理}// 用户已登录,放行继续执行后续请求return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {// 在处理完请求后进行拦截器的后处理操作}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {// 在视图渲染完成后进行拦截器的后处理操作}}

在上述拦截器中,我们重写了 `preHandle` 方法,在该方法中进行用户登录状态的校验。如果用户未登录,则使用 `response.sendRedirect("/login");` 将请求重定向到登录页面,并返回 false 阻止后续请求处理。如果用户已登录,则返回 true 放行继续执行后续请求。

2、注册拦截器

注册拦截器,创建一个配置类,用@Configuration注解来标注:

import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configurationpublic class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 注册自定义的拦截器registry.addInterceptor(new UserLoginInterceptor()).addPathPatterns("/like"); // 设置需要拦截的请求路径,这里假设点赞请求的路径为 /like}}

在上述配置中,我们通过 `addInterceptor` 方法注册了自定义的拦截器 `UserLoginInterceptor`,并使用 `addPathPatterns` 方法指定了需要拦截的请求路径为 `/like`,这样只有当请求路径为 `/like` 时才会触发拦截器的执行。

上述代码可以作为模板直接复制使用,但是在实际应用中,你需要根据具体的业务需求,设置拦截器的拦截路径和校验逻辑。

总结

在使用AOP的时候,我们要注意,我们织入的功能一定要是共性任务,不然如果只是对一个模块进行织入,那就是大题小作了,不如直接对那个模块进行改造。

对您有帮助的话,点赞收藏,嘿嘿!

最后我还整理汇总了⼀些 Java ⾯试相关的⾼质量 PDF 资料和免费Idea账号

公众号:Java小白,回复“⾯试” 和“idea破解”即可获取!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。