Spring框架概述 --- AOP, 拦截器, 过滤器

2023-11-04

  • 执行顺序是 过滤器 -> 拦截器 -> AOP

AOP概念

  • AOP 的全称是“Aspect Oriented Programming”,即面向切面编程,它将业务逻辑的各个部分进行隔离,使开发人员在编写业务逻辑时可以专心于核心业务,从而提高了开发效率
  • 就是为了更清晰的结构,一方面AOP可以让你的业务逻辑去关注业务本身,而不需要处理与业务不相关的事情。这些其他的事情是重复调用的,例如:安全,事物,日志等。另一方面,例如日志,在不同的地方实现的是同一套逻辑,这样就可以抽取出来,作为一个通知,然后引入到各个模块。
  • 整个程序就像一个西瓜, 把西瓜竖着切成几块, 横截面就是切面, 我们可以在切面中间放入通用代码 (比如日志)
  • filter 和 interceptor 都是AOP的具体实现

过滤器 — Filter

  • filter是作用在interceptor(拦截器)之前,filter主要是依赖serlvet容器
  • filter的三个方法
  • init(): 此方法在只在过滤器创建的时候执行一次,用于初始化过滤器的属性
  • doFilter(): doFilter(): 该方法会对请求进行拦截,用户需要在该方法中自定义对请求内容以及响应内容进行过滤的,调用该方法的入参 FilterChain对象的 doFilter 方法对请求放行执行后面的逻辑,若未调用 doFilter 方法则本次请求结束,并向客户端返回响应失败
  • destroy(): 此方法用于销毁过滤器,过滤器被创建以后只要项目一直运行,过滤器就会一直存在,在项目停止时,会调用该方法销毁过滤器
  • FilterChain: 一般filter都是一个链,web.xml 里面配置了几个就有几个。一个一个的连在一起
    request -> filter1 -> filter2 ->filter3 -> …. -> request resource.
/**
 * 系统后台访问权限控制过滤器
 */
public class SystemManagerAccessController implements Filter {
	private static Logger logger = Logger.getLogger(SystemManagerAccessController.class);
	@Override
	public void destroy() {
		
	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse resp,
						 FilterChain chain) throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest)req;
		String url = request.getServletPath();
		String ip = request.getRemoteAddr();
		
		logger.debug("Access URL=" + url + ", From IP=" + ip);
		
		HttpSession session = request.getSession();
		Object obj = session.getAttribute("LOGIN_USER");
		if(obj != null) {
			if(obj instanceof com.mln.system.beans.Manager){
				chain.doFilter(req, resp);
				return;
			} 
		}
		
		//记录无效访问信息
		logger.error("无效访问,[url=" + url +", From IP=" + ip + "]。");
		
		return;
	}

	@Override
	public void init(FilterConfig config) throws ServletException {
		
	}

}

拦截器 — Interceptor

package com.daniel.wiki.interceptor;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 拦截器:Spring框架特有的,常用于登录校验,权限校验,请求日志打印 /login
 */

@Component
public class LogInterceptor implements HandlerInterceptor {

    private static final Logger LOG = LoggerFactory.getLogger(LogInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 打印请求信息
        LOG.info("------------- LogInterceptor 开始 -------------");
        LOG.info("请求地址: {} {}", request.getRequestURL().toString(), request.getMethod());
        LOG.info("远程地址: {}", request.getRemoteAddr());

        long startTime = System.currentTimeMillis();
        request.setAttribute("requestStartTime", startTime);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        long startTime = (Long) request.getAttribute("requestStartTime");
        LOG.info("------------- LogInterceptor 结束 耗时:{} ms -------------", System.currentTimeMillis() - startTime);
    }
}

过滤器和拦截器的区别

  • 过滤器和拦截器都属于面向切面编程的具体实现。而两者的主要区别包括以下几个方面:
      1、Filter是依赖于Servlet容器,属于Servlet规范的一部分,而Interceptor则是独立存在的,可以在任何情况下使用。
      2、Filter的执行由Servlet容器回调完成,而Interceptor通常通过动态代理的方式来执行
      3、Filter的生命周期由Servlet容器管理,而Interceptor则可以通过IoC容器来管理,因此可以通过注入等方式来获取其他Bean的实例,因此使用会更方便

Spring AOP

  • 目前最流行的 AOP 框架有两个,分别为 Spring AOP 和 AspectJ。
  • Spring AOP 使用纯 Java 实现,基于动态代理. 不需要专门的编译过程和类加载器,在运行期间通过代理方式向目标类植入增强的代码。Spring
  • AspectJ 是一个基于 Java 语言的 AOP 框架,基于静态代理. 从 Spring 2.0 开始,Spring AOP 引入了对 AspectJ 的支持。AspectJ 扩展了 Java 语言,提供了一个专门的编译器,在编译时提供横向代码的植入

相关概念:

  • Joinpoint(连接点) 指那些被拦截到的点,在 Spring 中,可以被动态代理拦截目标类的方法。
  • Pointcut(切入点) 指要对哪些 Joinpoint 进行拦截,即被拦截的连接点。
  • Advice(通知) 指拦截到 Joinpoint 之后要做的事情,即对切入点增强的内容。
  • Target(目标) 指代理的目标对象。
  • Weaving(植入) 指把增强代码应用到目标上,生成代理对象的过程。
  • Proxy(代理) 指生成的代理对象。
  • Aspect(切面) 切入点和通知的结合

补充:通知(Advice)的类型:

  • 前置通知 @Before(Before advice):
    在某个连接点(Join point)之前执行的通知,但这个通知不能阻止连接点的执行(除非它抛出一个异常)。
  • 返回后通知 @AfterRunning(After returning advice):
    在某个连接点(Join point)正常完成后执行的通知。例如,一个方法没有抛出任何异常正常返回。
  • 抛出异常后通知 @AfterThrowing(After throwing advice):
    在方法抛出异常后执行的通知。
  • 后置通知 @After(After(finally)advice):
    当某个连接点(Join point)退出的时候执行的通知(不论是正常返回还是发生异常退出)。
  • 环绕通知 @Around(Around advice):
    包围一个连接点(Join point)的通知,如方法调用。这是最强大的一种通知类型。环绕通知可以在方法前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行.

AOP Example: Log Aspect

  • 打印接口参数, 请求参数, 返回参数
package com.daniel.wiki.aspect;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.support.spring.PropertyPreFilters;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

@Aspect //要加这个注释
@Component
public class LogAspect {

    private final static Logger LOG = LoggerFactory.getLogger(LogAspect.class);

    /** 定义一个切点 */
    //针对所有controller的所有方法
    @Pointcut("execution(public * com.daniel.*.controller..*Controller.*(..))")
    public void controllerPointcut() {}

    //前置通知
    //也可以放进环绕通知里
    @Before("controllerPointcut()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {

        // 开始打印请求日志
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        Signature signature = joinPoint.getSignature();
        String name = signature.getName();

        // 打印请求信息
        LOG.info("------------- 开始 -------------");
        LOG.info("请求地址: {} {}", request.getRequestURL().toString(), request.getMethod());
        LOG.info("类名方法: {}.{}", signature.getDeclaringTypeName(), name);
        LOG.info("远程地址: {}", request.getRemoteAddr());

        // 打印请求参数
        Object[] args = joinPoint.getArgs();
        // LOG.info("请求参数: {}", JSONObject.toJSONString(args));

        Object[] arguments  = new Object[args.length];
        for (int i = 0; i < args.length; i++) {
            if (args[i] instanceof ServletRequest
                    || args[i] instanceof ServletResponse
                    || args[i] instanceof MultipartFile) {
                continue;
            }
            arguments[i] = args[i];
        }
        // 排除字段,敏感字段或太长的字段不显示
        String[] excludeProperties = {"password", "file"};
        PropertyPreFilters filters = new PropertyPreFilters();
        PropertyPreFilters.MySimplePropertyPreFilter excludefilter = filters.addFilter();
        excludefilter.addExcludes(excludeProperties);
        LOG.info("请求参数: {}", JSONObject.toJSONString(arguments, excludefilter));
    }
    //环绕通知
    @Around("controllerPointcut()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        //执行实际代码
        Object result = proceedingJoinPoint.proceed();
        // 排除字段,敏感字段或太长的字段不显示
        String[] excludeProperties = {"password", "file"};
        PropertyPreFilters filters = new PropertyPreFilters();
        PropertyPreFilters.MySimplePropertyPreFilter excludefilter = filters.addFilter();
        excludefilter.addExcludes(excludeProperties);
        LOG.info("返回结果: {}", JSONObject.toJSONString(result, excludefilter));
        LOG.info("------------- 结束 耗时:{} ms -------------", System.currentTimeMillis() - startTime);
        return result;
    }

}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring框架概述 --- AOP, 拦截器, 过滤器 的相关文章

  • 为什么 i++ 不是原子的?

    Why is i Java 中不是原子的 为了更深入地了解 Java 我尝试计算线程中循环的执行频率 所以我用了一个 private static int total 0 在主课中 我有两个线程 主题 1 打印System out prin
  • Java - 将节点添加到列表的末尾?

    这是我所拥有的 public class Node Object data Node next Node Object data Node next this data data this next next public Object g
  • Android:捕获的图像未显示在图库中(媒体扫描仪意图不起作用)

    我遇到以下问题 我正在开发一个应用程序 用户可以在其中拍照 附加到帖子中 并将图片保存到外部存储中 我希望这张照片也显示在图片库中 并且我正在使用媒体扫描仪意图 但它似乎不起作用 我在编写代码时遵循官方的Android开发人员指南 所以我不
  • 加速代码 - 3D 数组

    我正在尝试提高我编写的一些代码的速度 我想知道从 3d 整数数组访问数据的效率如何 我有一个数组 int cube new int 10 10 10 我用价值观填充其中 然后我访问这些值数千次 我想知道 由于理论上所有 3d 数组都存储在内
  • 列出jshell中所有活动的方法

    是否有任何命令可以打印当前 jshell 会话中所有新创建的方法 类似的东西 list但仅适用于方法 您正在寻找命令 methods all 它会打印所有方法 包括启动 JShell 时添加的方法 以及失败 被覆盖或删除的方法 对于您声明的
  • 操作错误不会显示在 JSP 上

    我尝试在 Action 类中添加操作错误并将其打印在 JSP 页面上 当发生异常时 它将进入 catch 块并在控制台中打印 插入异常时出错 请联系管理员 在 catch 块中 我添加了它addActionError 我尝试在jsp页面中打
  • 无法解析插件 Java Spring

    我正在使用 IntelliJ IDEA 并且我尝试通过 maven 安装依赖项 但它给了我这些错误 Cannot resolve plugin org apache maven plugins maven clean plugin 3 0
  • 如何为俚语和表情符号构建正则表达式 (regex)

    我需要构建一个正则表达式来匹配俚语 即 lol lmao imo 等 和表情符号 即 P 等 我按照以下示例进行操作http www coderanch com t 497238 java java Regular Expression D
  • Java按日期升序对列表对象进行排序[重复]

    这个问题在这里已经有答案了 我想按一个参数对对象列表进行排序 其日期格式为 YYYY MM DD HH mm 按升序排列 我找不到正确的解决方案 在 python 中使用 lambda 很容易对其进行排序 但在 Java 中我遇到了问题 f
  • Java TestNG 与跨多个测试的数据驱动测试

    我正在电子商务平台中测试一系列商店 每个商店都有一系列属性 我正在考虑对其进行自动化测试 是否有可能有一个数据提供者在整个测试套件中提供数据 而不仅仅是 TestNG 中的测试 我尝试不使用 testNG xml 文件作为机制 因为这些属性
  • 在两个活动之间传输数据[重复]

    这个问题在这里已经有答案了 我正在尝试在两个不同的活动之间发送和接收数据 我在这个网站上看到了一些其他问题 但没有任何问题涉及保留头等舱的状态 例如 如果我想从 A 类发送一个整数 X 到 B 类 然后对整数 X 进行一些操作 然后将其发送
  • 将不同类型的参数传递给 jdbctemplate 查询

    我正在尝试使用带有少量不同类型参数的 where 子句从数据库中检索记录 这是我编写的简单方法 我将breedId和性别作为参数传递 public List
  • Eclipse Java 远程调试器通过 VPN 速度极慢

    我有时被迫离开办公室工作 这意味着我需要通过 VPN 进入我的实验室 我注意到在这种情况下使用 Eclipse 进行远程调试速度非常慢 速度慢到调试器需要 5 7 分钟才能连接到远程 jvm 连接后 每次单步执行断点 行可能需要 20 30
  • 如何从指定日期获取上周五的日期? [复制]

    这个问题在这里已经有答案了 如何找出上一个 上一个 星期五 或指定日期的任何其他日期的日期 public getDateOnDay Date date String dayName 我不会给出答案 先自己尝试一下 但是 也许这些提示可以帮助
  • 如何在桌面浏览器上使用 webdriver 移动网络

    我正在使用 selenium webdriver 进行 AUT 被测应用程序 的功能测试自动化 AUT 是响应式网络 我几乎完成了桌面浏览器的不同测试用例 现在 相同的测试用例也适用于移动浏览器 因为可以从移动浏览器访问 AUT 由于它是响
  • 获取 JVM 上所有引导类的列表?

    有一种方法叫做findBootstrapClass对于一个类加载器 如果它是引导的 则返回一个类 有没有办法找到类已经加载了 您可以尝试首先通过例如获取引导类加载器呼叫 ClassLoader bootstrapLoader ClassLo
  • 有没有办法为Java的字符集名称添加别名

    我收到一个异常 埋藏在第 3 方库中 消息如下 java io UnsupportedEncodingException BIG 5 我认为发生这种情况是因为 Java 没有定义这个名称java nio charset Charset Ch
  • java.lang.IllegalStateException:驱动程序可执行文件的路径必须由 webdriver.chrome.driver 系统属性设置 - Similiar 不回答

    尝试学习 Selenium 我打开了类似的问题 但似乎没有任何帮助 我的代码 package seleniumPractice import org openqa selenium WebDriver import org openqa s
  • 按日期对 RecyclerView 进行排序

    我正在尝试按日期对 RecyclerView 进行排序 但我尝试了太多的事情 我不知道现在该尝试什么 问题就出在这条线上适配器 notifyDataSetChanged 因为如果我不放 不会显示错误 但也不会更新 recyclerview
  • 节拍匹配算法

    我最近开始尝试创建一个移动应用程序 iOS Android 它将自动击败比赛 http en wikipedia org wiki Beatmatching http en wikipedia org wiki Beatmatching 两

随机推荐

  • Leetcode-4. Median of Two Sorted Arrays

    Topic background Given two sorted arrays nums1 and nums2 of size m and n respectively return the median of the two sorte
  • vue使用element plus引入ElMessage样式失效的问题

    样式失效如图 我使用的是按需引用 所以在main js中直接导入下面样式就行 import element plus theme chalk index css
  • 装饰模式与代理区别

    学着学着真容易懵 相同点 装饰者类与目标类要求实现同一接口 静态代理类与目标类要求也实现同一接口 装饰者类与静态代理类都可以实现增强目标类的功能 装饰者类与静态代理类中都具有目标类的引用 目的都是为了在其中调用目标类的方 法 不同点 装饰者
  • JSP 点击量统计

    2019独角兽企业重金招聘Python工程师标准 gt gt gt JSP 点击量统计 有时候我们需要知道某个页面被访问的次数 这时我们就需要在页面上添加页面统计器 页面访问的统计一般在用户第一次载入时累加该页面的访问数上 要实现一个计数器
  • 第5章 使用图像(html)

    第5章 使用图像 html 目录标题 5 1 有序列表 5 1 1 ol标签 5 1 2 有序列表的序号类型type 5 1 3 有序列表的起始数值start 5 2 无序列表 5 3 定义列表dl 5 4 列表的嵌套 5 5 练习题 5
  • windows 8 pro vl_微软MSDN原版Windows10/8/7/XP系统镜像与office下载地址大全

    相信如今大多数的用户开始讨厌GHOST形式安装操作系统 而使用微软MSDN原版系统进行安装 原因是网上分享的GHOST系统已经形成了一个黑色产业链 由于系统被删减过 众多功能缺失 并捆绑了众多无用的软件程序 还强制修改浏览器主页等让人讨厌的
  • 深度学习边缘检测 HED 训练自己的数据

    深度学习边缘检测 HED 训练自己的数据 数据集制作 使用labelme标注 选择lineStrip 线条束 标注 生成json文件 之后使用批量处理脚本将json文件转为边缘数据集 具体过程如下 首先将所有的json文件放入一个文件夹内
  • 云计算与海量数据处理技术

    云计算提供了一种对资源 按需索取服务 的能力 确保了使用时间与需要时间的完全一致 从而建立了一种分布式 高效率 低成本的IT商业模式 正是这些特点 使云计算成为IT发展的潮流与趋势 为解决广大系统设计人员深入研究与开发云计算系统的需要 培训
  • 小美的数组操作2---牛客周赛 Round 11

    注意给a 0 赋一个最小值 include
  • 1004 成绩排名 (20 分)

    1004 成绩排名 20 分 读入 n gt 0 名学生的姓名 学号 成绩 分别输出成绩最高和成绩最低学生的姓名和学号 输入格式 每个测试输入包含 1 个测试用例 格式为 第 1 行 正整数 n 第 2 行 第 1 个学生的姓名 学号 成绩
  • WEB应用防火墙安全技术要求与测试评价方法

    信息安全技术 WEB应用防火墙安全技术要求与测试评价方法 范围 本标准规定了WEB应用防火墙的安全功能要求 自身安全保护要求 性能要求和安全保证要求 并提供了相应的测试评价方法 本标准适用于WEB应用防火墙的设计 生产 检测及采购 规范性引
  • Android自定义View-Path的详细介绍

    一 构造方法 1 Path path new Path 空的构造方法 2 Path path new Path Path src 创建一个新的路径 并从src路径获取内容赋值给新的路径 二 Path常用的一些方法 分类 Path方法 备注
  • Verilog学习之位拆分与运算设计

    文章目录 前言 一 题目描述 二 实现思路 1 题意分析 2 状态分析 三 代码展示 总结 前言 今天我们做的是第五道题 位拆分与运算 这道题比较简单 我们只需要用到状态机的思想和 运算以及数据锁存的问题 接下来就让我们看看如何写这道题 位
  • Kibana server is not ready yet

    Kibana server is not ready yet 这个错误通常是由于Kibana服务无法连接到Elasticsearch引起的 这可能是由于以下原因之一 1 Elasticsearch没有启动 请确保Elasticsearch正
  • vivado时序分析之set_input_delay(三)

    本篇用vivado timing constraints wizard来进行set input delay的约束 set input delay界面如图一所示 包括interface clock synchronous alignment
  • Python第三方库在命令行使用pip安装完成之后只能使用idle,而不能pycharm的解决方法

    先使用pip install requests 或者其他模块也可以 然后如图 就可以看到这些模块被安装的位置 看到安装的一些模块都在这里 直接把site packages整个文件夹Ctrl C一下 然后找到Pycharm的项目文件夹 就是你
  • uniapp各个页面监听

    当前页面在退出时 uni emit zxpg zxpg res tips uni navigateBack 返回上一个页面 在上一个页面的onShow uni on zxpg data gt console log 接收事件test成功 d
  • Spring Boot 创建RESTful Web Service

    1 介绍 本篇将使用Spring Boot创建一个简单restful风格web服务 接受HTTP GET请求 http localhost 8080 greeting 响应体 respond 为一个JSON字符串 id 1 content
  • 解决网页不能复制

    按f12 console点圆圈斜杠那个图标 输入 document body contentEditable true
  • Spring框架概述 --- AOP, 拦截器, 过滤器

    Spring框架概述 AOP 拦截器 过滤器 AOP概念 过滤器 Filter 拦截器 Interceptor Spring AOP AOP Example Log Aspect 执行顺序是 过滤器 gt 拦截器 gt AOP AOP概念