Spring的常用拓展点

news2024/10/7 14:26:19

文章目录

  • 自定义拦截器
  • 获取 Spring 容器对象
  • 修改 BeanDefinition
    • 添加BeanDefinition
    • 测试
  • 初始化 Bean 前后
  • 初始化方法
    • 使用@PostConstruct 注解
    • 实现 InitializingBean 接口
  • BeanFactoryPostProcessor 接口
  • 关闭容器前
  • 自定义作用域

自定义拦截器

spring mvc 拦截器的顶层接口是:HandlerInterceptor,包含三个方法:

  • preHandle 目标方法执行前执行
  • postHandle 目标方法执行后执行
  • afterCompletion 请求完成时执行

一 般 情 况 会 用 HandlerInterceptor 接 口 的 实 现 类HandlerInterceptorAdapter 类。
假如有权限认证、日志、统计的场景,可以使用该拦截器

第一步,继承 HandlerInterceptorAdapter 类定义拦截器:


import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

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

@Slf4j
public class AuthInterceptor extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler)
            throws Exception {
        String requestUrl = request.getRequestURI ();
        if (checkAuth (requestUrl)) {
            return true;
        }
        return false;
    }

    private boolean checkAuth(String requestUrl) {
        System.out.println ("===权限校验===");
        return true;
    }
}

第二步,将该拦截器注册到 spring 容器:



import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import javax.annotation.Resource;

@Configuration
public class WebAuthConfig extends WebMvcConfigurerAdapter {
    @Resource
    private AuthInterceptor authInterceptor;

    @Bean
    public AuthInterceptor getAuthInterceptor() {
        return new AuthInterceptor ();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor (authInterceptor);
    }
}

第三步,在请求接口时 spring mvc 通过该拦截器,能够自动拦截该接口,并且校验权限

获取 Spring 容器对象

在我们日常开发中,经常需要从 Spring 容器中获取 Bean,但你知道如何获取 Spring 容器对象吗?

ApplicationListener 接口


@Service
public class PersonService2 implements ApplicationContextAware {
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        this.applicationContext = applicationContext;
    }

    public void add() {
        Person person = (Person) applicationContext.getBean ("person");
    }
}

实现 ApplicationContextAware 接口,然后重写 setApplicationContext 方法,也能从该方法中获取到 spring 容器对象。

修改 BeanDefinition

Spring IOC 在实例化 Bean 对象之前,需要 先读取 Bean 的相关属性
保存到 BeanDefinition 对象中,然后通过 BeanDefinition 对象,实例化 Bean 对象。
如果想修改 BeanDefinition 对象中的属性,该怎么办呢?

答:我们可以实现 BeanFactoryPostProcessor 接口

添加BeanDefinition

import lombok.Data;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.stereotype.Component;

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory)
            throws BeansException {
        DefaultListableBeanFactory defaultListableBeanFactory =
                (DefaultListableBeanFactory) configurableListableBeanFactory;
        BeanDefinitionBuilder beanDefinitionBuilder =
                BeanDefinitionBuilder.genericBeanDefinition (User.class);
        beanDefinitionBuilder.addPropertyValue ("id", 123);
        beanDefinitionBuilder.addPropertyValue ("name", "xiaoding");
        defaultListableBeanFactory.registerBeanDefinition ("user",
                beanDefinitionBuilder.getBeanDefinition ());
    }
}

@Data
class User {
    private int id;
    private String name;
}

测试

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;

@SpringBootTest
@RunWith(SpringRunner.class)
public class TestBean {
    @Resource
    private User user;

    @Test
    public void test() {

        System.out.println (user.getId ());
        System.out.println (user.getName ());
    }
}

在这里插入图片描述
postProcessBeanFactory 方法中,可以获取 BeanDefinition 的相关对象,并且修改该对象的属性。

初始化 Bean 前后

这时可以实现:BeanPostProcessor 接口。

该接口目前有两个方法:

  • postProcessBeforeInitialization 该在初始化方法之前调用
  • postProcessAfterInitialization 该方法在初始化方法之后调用
import lombok.Data;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessAfterInitialization(Object bean,
                                                 String beanName
    ) throws BeansException {
        if (bean instanceof User) {
            ((User) bean).setUserName ("mr ding");
        }
        return bean;
    }
}

@Data
class User {
    private int id;
    private String UserName;
}

如果 spring 中存在 User 对象,则将它的 userName 设置成:mr ding

初始化方法

  1. 使用**@PostConstruct** 注解
  2. 实现 InitializingBean 接口

使用@PostConstruct 注解

@Service
public class AService {
    @PostConstruct
    public void init() {
        System.out.println ("===初始化===");
    }
}

在需要初始化的方法上增加@PostConstruct 注解,这样就有初始化的能力。

实现 InitializingBean 接口

@Service
public class BService implements InitializingBean {
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println ("===初始化===");
    }
}

实现 InitializingBean 接口,重写 afterPropertiesSet 方法,该方法中可以完成初始化功能

BeanFactoryPostProcessor 接口

beanFactory后置处理器,可以获取BeanDefinition 进行修改

@Component
class UserServiceImpl implements BeanFactoryPostProcessor {


    @Override
    //实现BeanFactoryPostProcessor ,可以获取beanDefinition ,修改bean的作用范围和className
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanDefinition userService = beanFactory.getBeanDefinition("userService");
        userService.setScope("singleton");
        userService.setBeanClassName("");
    }
}

关闭容器前

有时候,我们需要在关闭 spring 容器前,做一些额外的工作,比如:关闭资源文件等。
这时可以实现 DisposableBean 接口,并且重写它的 destroy 方法

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;

@Service
public class DService implements InitializingBean, DisposableBean {
    @Override
    public void destroy() throws Exception {
        System.out.println ("DisposableBean destroy");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println ("InitializingBean afterPropertiesSet");
    }
}

这样 spring 容器销毁前,会调用该 destroy 方法,做一些额外的工作。

通常情况下,我们会同时实现 InitializingBeanDisposableBean接口,重写初始化方法和销毁方法

自定义作用域

我们都知道 spring 默认支持的 Scope 只有两种:

  • singleton 单例,每次从 spring 容器中获取到的 bean 都是同一个对象。
  • prototype 多例,每次从 spring 容器中获取到的 bean 都是不同的对象。

spring web 又对 Scope 进行了扩展,增加了:

  • RequestScope 同一次请求从 spring 容器中获取到的 bean 都是同一个对象。
  • SessionScope 同一个会话从 spring 容器中获取到的 bean 都是同一个对象。
    即便如此,有些场景还是无法满足我们的要求。

比如,我们想在 同一个线程中 从 spring 容器获取到的 bean 都是同一个对象,该怎么办?

这就需要自定义 Scope 了。
第一步实现 Scope 接口

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;

public class ThreadLocalScope implements Scope {
    private static final ThreadLocal THREAD_LOCAL_SCOPE = new ThreadLocal ();

    @Override
    public Object get(String name, ObjectFactory<?> objectFactory) {
        Object value = THREAD_LOCAL_SCOPE.get ();
        if (value != null) {
            return value;
        }
        Object object = objectFactory.getObject ();
        THREAD_LOCAL_SCOPE.set (object);
        return object;
    }

    @Override
    public Object remove(String name) {
        THREAD_LOCAL_SCOPE.remove ();
        return null;
    }

    @Override
    public void registerDestructionCallback(String name, Runnable callback) {
    }

    @Override
    public Object resolveContextualObject(String key) {
        return null;
    }

    @Override
    public String getConversationId() {
        return null;
    }
}

第二步将新定义的 Scope 注入到 spring 容器中:


import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

@Component
public class ThreadLocalBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        beanFactory.registerScope ("threadLocalScope", new ThreadLocalScope ());
    }
}


第三步使用新定义的 Scope:

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

@Scope("threadLocalScope")
@Service
public class CService {
    public void add() {
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/27904.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

web端常见导航设计

一、导航的定义 导航作为网站或者平台的骨架&#xff0c;是产品设计中不容忽视的一环导航是内容或者功能的定位、导向与通道。 二、导航分类 遵循导航层级结构&#xff0c;包括全局导航和局部导航 全局导航往往指页眉和页脚&#xff0c;存在于网站的大部分页面&#xff0c;便于…

游戏引擎概述-Part1

一、简述自己的学习心路历程 自从业UNITY以来已经有4个月多了&#xff0c;回想起来自己从工作以来就很少写博客了&#xff0c;也算督促一下自己&#xff0c;回想自己从最早的Unity开始&#xff0c;入手C#和编辑器、Unity开发界面&#xff0c;再到自己学一些Unity的小项目…

有效学习,通过PMP考试

但是我们时间有限&#xff0c;如何有效利用这些资料&#xff0c;花最少时间通过考试&#xff0c;是个关键问题。 课程主要的资料包括&#xff1a; PMBOK。官方指定用书&#xff0c;考试知识点来自PMBOK。 汪博士解读PMP考试。考试参考书&#xff0c;比PMBOK解析得更清楚&…

Qt-FFmpeg开发-视频播放(3)

Qt-FFmpeg开发-视频播放【软解码 OpenGL显示RGB图像】 文章目录Qt-FFmpeg开发-视频播放【软解码 OpenGL显示RGB图像】1、概述2、实现效果3、FFmpeg软解码流程4、主要代码4.1 解码代码4.2 OpenGL显示RGB图像代码5、完整源代码更多精彩内容&#x1f449;个人内容分类汇总 &…

Bio-Helix 艾美捷IRIS11预染蛋白Markers基参及相关研究

IRIS11预染色蛋白梯是11种分子量为3至60kDa的预染色蛋白的组合。11种重组蛋白与蓝色发色团共价偶联&#xff0c;而2条70kDa和260kDa的红色带、一条15kDa的绿色带和一条新设计的60kDa的孔雀绿色带作为参考带。IRIS11预拉伸蛋白质阶梯在SDS聚丙烯酰胺凝胶电泳过程中跟踪蛋白质的大…

[附源码]java毕业设计新冠疫苗线上预约系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

【测试沉思录】17. 性能测试中的系统资源分析之四:网络

作者&#xff1a;马海琴 编辑&#xff1a;毕小烦 计算机网络&#xff0c;就是通过光缆、电缆、电话线或无线通讯将两台以上的计算机互连起来的集合&#xff0c;包括广域网、城域网、局域网和无线网。 计算机网络是传输信息的媒介。我们常说的千兆网&#xff0c;是指网络带宽为…

openssl中SM2、SM3、SM4使用实例

目录 openssl的版本如下&#xff1a; SM3使用实例 1. SM3的扎凑实例 SM2使用实例 1. 生成SM2密钥对 2.查看SM2密钥对 3.生成自签名证书 4.查看证书详情 5.私钥签名消息 6.证书验证消息签名 SM4 使用实例 openssl的版本如下&#xff1a; SM3使用实例 SM3是中华人民共…

前端框架 Nextjs 实现React SEO优化

目录 一、Nextjs框架创建React项目 二、路由的使用 1、静态路由 2、动态路由 3、Link路由跳转 4、Api路由 5、Api动态路由 三、Nextjs中加载js脚本 四、Nextjs中加载图片 五、Nextjs的公共布局 六、Pages的其他特性 一、Nextjs框架创建React项目 快速入门 | Next.…

YOLOv5~目标检测模型精确度

还是yolo5的基础啊~~ 一些关于目标检测模型的评估指标&#xff1a;IOU、TP&FP&FN&TN、mAP等&#xff0c;并列举了目标检测中的mAP计算。 指标评估(重要的一些定义) IOU 也称重叠度表示计算预测回归框和真实回归框的交并比,计算公式如下: TP&FP&FN&…

2022CTF培训(二)Hook进阶反调试

附件下载链接 Hook进阶 更精准的 Inline Hook 要求 实现防止任务管理器对某进程自身的结束要求不影响任务管理器结束其它进程的功能 Dll 注入程序编写 提权 主要过程如下&#xff1a; 首先,程序需要调用OpenProcessToken函数打开指定的进程令牌&#xff0c;并获取TOKEN…

【架构设计】作为架构师你应该掌握的画图技术

1.前言 大家知道&#xff0c;架构的过程其实就是建模的过程&#xff0c;那自然离不开架构图。那么&#xff0c;我们先来看几个问题。 &#xff08;1&#xff09;什么是架构图&#xff1f; 架构图 架构 图&#xff0c;用图的形式把系统架构展示出来&#xff0c;配上简单的文…

Rust学习笔记——安装、创建、编译、输入输出

目录 一.安装 二.创建 三.编译 四.输入输出 &#xff08;一&#xff09;.输出hello world &#xff08;二&#xff09;.输入 一.安装 Rust Programming Language (rust-lang.org)&#xff0c;这是Rust官网。 直接下载自己对应系统版本即可&#xff0c;小编是linux版。 下…

ARP协议map4(3层网络层的协议)

数据来源 一、广播与广播域概述 1、广播域广播域 广播&#xff1a;将广播地址做为目标地址的数据帧 广播域&#xff1a;网络中能接收到同一个广播所有节点的集合&#xff08;广播域越小越好&#xff0c;这样通信效率更高&#xff09; 下图每个圈都是一个广播域&#xff0c;说…

通关算法题之 ⌈数组⌋ 上

滑动窗口 3. 无重复字符的最长子串 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 输入: s "abcabcbb" 输出: 3 这就是变简单了&#xff0c;连 need 和 valid 都不需要&#xff0c;而且更新窗口内数据也只需要简单的更新计数器 …

(续)SSM整合之SSM整合笔记(ContextLoaderListener)(P179-188)

一 准备工作 1 新建模块ssm com.atguigu.ssm 2 导入依赖 <packaging>war</packaging><properties><spring.version>5.3.1</spring.version> </properties><dependencies><dependency><groupId>org.springframew…

Day10--初步实现自定义tabBar的效果

承接上文配置信息之后。 1.添加tabBar代码文件 我的操作&#xff1a; 1》在文件区新建一个custom-tab-bar文件夹 2》并在其中新建一个index组件 3》文件区展示图 4》最终的效果图&#xff1a; **************************************************************************…

界面组件DevExpress Reporting v22.1亮点 - 报表设计器功能全面升级

DevExpress Reporting是.NET Framework下功能完善的报表平台&#xff0c;它附带了易于使用的Visual Studio报表设计器和丰富的报表控件集&#xff0c;包括数据透视表、图表&#xff0c;因此您可以构建无与伦比、信息清晰的报表。 DevExpress Reporting v22.1版本已正式发布&am…

数据结构之二叉树(前提知识)

文章目录前言**一、树****二、树的相关概念****节点的度****叶节点****分支节点****子节点****父节点****兄弟节点****树的度****节点的层****树的高度****祖先****子孙****森林****三、树的表示****孩子表示法****左孩子右兄弟法****双亲表示法****四、树在实际中的应用****总…

iPhone/iPad屏幕投屏镜像到PC或Mac上面教程分享

AirServer是一款Mac应用程序&#xff0c;可将AirPlay / AirTunes的音频&#xff0c;视频&#xff0c;照片&#xff0c;幻灯片和镜像接收功能添加到Mac电脑。它可以实现将iPhone手机或Mac电脑上的媒体文件以及其他操作投射到Mac电脑上。使用AirServer&#xff0c;可以从Mac&…