Spring IoC容器(二)Bean的自定义及容器的扩展

 Spring提供了一些接口来让我们定制bean 及扩展容器。

1 定制Bean

我们可以通过bean及容器的生命周期回调及一些Aware接口来定制bean。

1.1 生命周期回调

1.1.1 InitializingBean 与 DisposableBean

我们可以通过让Bean 实现InitializingBean 及DisposableBean 接口,当容器初始化完bean后会调用InitializingBean的afterPropertiesSet()方法,当容器销毁bean前会调用DisposableBean接口的destroy()方法。

上面这两个接口方法在JSR-250中,可以使用@PostConstruct 及@PreDestory注释来代替。

也可以在xml的bean标签的init-method 的属性指定bean中的一个实例方法来作为初始化方法(与afterPropertiesSet()作用一致)。

在xml的bean标签的destory-method属性指定bean中的一个实例方法作为销毁方法(与destroy()作用一致)。

在beans 标签中通过default-init-method及default-destroy-method属性用来指定bean默认的初始化及销毁的方法名。

可以将bean中指定初始化方法(销毁方法)、继承InitializingBean或DisposableBean及使用@PostConstruct或@PreDestory注释这三种方案组合一起使用。

初始化方法的执行顺序为:@PostConstruct -> afterPropertiesSet() -> init-method 属性。

销毁方法的执行顺序为:@PreDestory -> destroy() -> destroy-method属性。

public class InitService implements InitializingBean {public InitService() {System.out.println("initService 实例化");}private String name;public void setName(String name) {this.name = name;System.out.println("赋值完成:" + name);}public void customInit() {System.out.println("init-method指定的customInit()");}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("afterPropertiesSet");}public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/article/article.xml");applicationContext.getBean(InitService.class);}
}<bean class="article.InitService" init-method="customInit"/>

1.1.2 启动和关闭的回调

Lifecycle 接口定义了三个跟生命周期相关的方法:start() 启动,stop() 停止,isRuning() 是否运行。某些Io C容器实现了这个接口的方法,LifecycleProcessor接口扩展了Lifecycle接口并新增两个方法:onRefresh() 及 onClose()。

public interface Lifecycle {void start();void stop();boolean isRunning();
}public interface LifecycleProcessor extends Lifecycle {void onRefresh();void onClose();
}

当spring context被启动时会调用容器的start方法,当关闭时候会调用容器的stop()方法。同时bean也可以实现这个接口,当容器被调用start方法时,bean的start方法也会被调用。

在bean中,所依赖的bean会被先创建,也可以指定depend-on关系来控制bean的创建顺序。对于那些没有直接依赖关系的,但是我们想指定start()被调用顺序,这时bean可以通过实现Phased接口来控制被调用的顺序。该接口有个getPhase()方法返回一个int类型,值越小越先启动,越小越后关闭。而没有实现Phased接口的Bean,值为0.

注意,Lifecycle 是针对的是常规启动关闭情况,如果想在热启动或其他自动启动模式下触发,那么应该使用SmartLifecycle接口。

public class StartService1 implements Lifecycle, Phased {public StartService1() {System.out.println("StartService1 实例化");}private boolean running = false;@Overridepublic void start() {System.out.println("StartService1 启动");running = true;}@Overridepublic void stop() {System.out.println("StartService1 关闭");running = false;}@Overridepublic boolean isRunning() {return running;}@Overridepublic int getPhase() {return -1; // 比没有实现Phased接口的Bean更先调用start()}public static void main(String[] args) {ConfigurableApplicationContext applicationContext = new ClassPathXmlApplicationContext("/article/article.xml");applicationContext.start(); // 手动发出启动的信号}
}public class StartService2 implements Lifecycle {public StartService2() {System.out.println("StartService2实例化");}private boolean running = false;@Overridepublic void start() {System.out.println("StartService2 启动");running = true;}@Overridepublic void stop() {System.out.println("StartService2 关闭");running = false;}@Overridepublic boolean isRunning() {return running;}
}<bean class="article.StartService2" lazy-init="false"/>
<bean class="article.StartService1" lazy-init="false"/>

在上面的代码中,ConfigurableApplicationContext接口继承Lifecycle接口。而ClassPathXmlApplicationContext的一个祖先类AbstractApplicationContext 实现了ConfigurableApplicationContext的方法。

图 AbstractApplicationContext类中的start 方法

图 AbstractApplicationContext类中初始化生命周期处理器的方法

而在DefaultLifecycleProcessor类中的start方法内部,调用了该类的实例方法startBeans。

图 DefaultLifecycleProcessor 的startBeans方法

在非Web 环境的容器中,要安全的来关闭容器,需要调用ConfigurableApplicationContext的registerShutdownHook实例方法,来让JVM关闭前能调用容器的stop方法。

而Web环境的容器实现了安全关闭容器的方法。

1.2 Aware 接口

Spring 提供了广泛的Aware回调接口,让bean向容器指示它们需要特定的基础结构依赖关系。

ApplicationContextAware

向bean提供ApplicationContext变量。

ApplicationEventPublisherAware

发布ApplicationContext的事件。

BeanClassLoaderAware

用于加载bean类。

BeanFactoryAware

向bean提供BeanFactory变量。

BeanNameAware

向bean提供bean的命名。

BootstrapContextAware

当前容器里的资源适配器BootstrapContext

LoadTimeWeaverAware

定义的weaver用于在加载时处理类定义。

MessageSourceAware

配置解析消息的策略(支持参数化与国际化)。

NotificationPublisherAware

Spring JMX 通知的发布者。

ResourceLoaderAware

配置用于低级访问资源的加载器。

ServletConfigAware

当前在容器运行的ServletConfig。

ServletContextAware

当前在容器运行的ServletContext。

表 Spring提供的Aware接口

2 定义Bean的继承关系

子bean 可以从父bean继承配置数据,子bean可以根据需要覆盖某些值或添加其他值。使用这种继承关系可以节省大量的键入工作,这是一种模版形式。

如果bean 标签的abstract属性标志为true,那么这个bean将不会被实例化(class属性的值为空),但是可以被子bean继承。

public class ChildrenService {private String name;private Integer age;private String address;public void setName(String name) {this.name = name;}public void setAge(Integer age) {this.age = age;}public void setAddress(String address) {this.address = address;}public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/article/article.xml");ChildrenService childrenService = applicationContext.getBean(ChildrenService.class);System.out.println(childrenService);}@Overridepublic String toString() {return "ChildrenService{" +"name='" + name + '\'' +", age=" + age +", address='" + address + '\'' +'}';}
}<bean id="fatherBean" abstract="true"><property name="name" value="默认名"/><property name="age" value="28"/></bean><bean class="article.ChildrenService" parent="fatherBean"><property name="name" value="黄先生"/><property name="address" value="深圳"/></bean>

3 容器扩展

可以通过向容器中插入实现了特定接口的实例来对容器进行扩展,而不必通过继承ApplicationContext的方式。

3.1 BeanPostProcessor

BeanPostProcessor 接口提供了可以覆盖容器实例化逻辑或依赖逻辑的方法。bean 先由容器实例化,然后由BeanPostProcessor进行操作。并且可以向容器中插入多个这里的实例,控制执行顺序,则还需要实现Ordered接口。

public class CustomBeanPostProcessor1 implements BeanPostProcessor, Ordered {@Overridepublic int getOrder() {return 1; // 越小越先执行}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("CustomBeanPostProcessor1 postProcessBeforeInitialization() 实例化之前");return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("CustomBeanPostProcessor1 postProcessAfterInitialization() 实例化之后");return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);}
}public class CustomBeanPostProcessor2 implements BeanPostProcessor, Ordered {@Overridepublic int getOrder() {return 2;}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("CustomBeanPostProcessor2 postProcessBeforeInitialization() 实例化之前");return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("CustomBeanPostProcessor2 postProcessAfterInitialization() 实例化之后");return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);}
}<bean class="article.CustomBeanPostProcessor1"/>
<bean class="article.CustomBeanPostProcessor2"/>

3.2 BeanFactoryPostProcessor 定制配置元数据

IoC容器允许BeanFactoryPostProcessor 读取配置元数据,并可能在实例化之前更改元数据。同样允许配置多个BeanFactoryPostProcessor。当被注入到容器时会自动运行。

Spring 定义了多个实现了BeanFactoryPostProcessor的类。

3.2.1 PropertySourcesPlaceholderConfigurer

通过配置Properties的方式来取代bean中定义的占位符。

使用标准的Java Properties 格式将bean定义中的属性值外部化到一个单独的文件中。这样可以使部署时能自定义特定于环境的属性,如数据库host和帐号密码,而无需修改容器的一个或多个xml中bean定义的属性。

public class DataService {private String host;private String username;private String password;public void setHost(String host) {this.host = host;}public void setUsername(String username) {this.username = username;}public void setPassword(String password) {this.password = password;}@Overridepublic String toString() {return "DataService{" +"host='" + host + '\'' +", username='" + username + '\'' +", password='" + password + '\'' +'}';}public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/article/article.xml");DataService dataService = applicationContext.getBean(DataService.class);System.out.println(dataService);}
}// data.properties
jdbc.host=localhost
jdbc.username=root
jdbc.password=123<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"><property name="location" value="classpath:article/data.properties"/>
</bean>
<bean class="article.DataService"><property name="host" value="${jdbc.host}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/>
</bean>

3.2.1 PropertyOverrideConfigurer

可以覆盖任何bean 中的任何属性。

public class StudentService {private String name;private Integer age;public void setName(String name) {this.name = name;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "StudentService{" +"name='" + name + '\'' +", age=" + age +'}';}public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/article/article.xml");StudentService studentService = applicationContext.getBean(StudentService.class);System.out.println(studentService); // 输出值 StudentService{name='newName', age=1}}
}<bean id="studentService" class="article.StudentService"><property name="name" value="小柚柚"/><property name="age" value="3"/></bean><bean class="org.springframework.beans.factory.config.PropertyOverrideConfigurer"><property name="properties"><props><prop key="studentService.name">newName</prop><prop key="studentService.age">1</prop></props></property></bean>

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构】单向链表实现 超详细

目录 一. 单链表的实现 1.准备工作及其注意事项 1.1 先创建三个文件 1.2 注意事项&#xff1a;帮助高效记忆和理解 2.链表的基本功能接口 2.0 创建一个 链表 2.1 链表的打印 3.链表的创建新节点接口 4.链表的节点插入功能接口 4.1 尾插接口 4.2 头插接口 4.3 指定位…

【数据结构】双向带头循环链表实现及总结

简单不先于复杂&#xff0c;而是在复杂之后。 文章目录 1. 双向带头循环链表的实现2. 顺序表和链表的区别 1. 双向带头循环链表的实现 List.h #pragma once #include <stdio.h> #include <assert.h> #include <stdlib.h> #include <stdbool.h>typede…

数据分析基础之《pandas(2)—基本数据操作》

一、读取一个真实的股票数据 1、读取数据 # 基本数据操作 data pd.read_csv("./stock_day.csv")data# 删除一些列&#xff0c;使数据简洁点 data data.drop([ma5,ma10,ma20,v_ma5,v_ma10,v_ma20], axis1)data 二、索引操作 1、numpy当中我们已经讲过使用索引选取…

线性代数:线性方程组

目录 一、线性方程组概念 二、消元法求线性方程组 三、系数阵的秩与线性方程组的解 无解 唯一解 无数解 相关定理 一、线性方程组概念 二、消元法求线性方程组 三、系数阵的秩与线性方程组的解 无解 唯一解 无数解 相关定理

【项目日记(八)】第三层: 页缓存的具体实现(下)

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:项目日记-高并发内存池⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你做项目   &#x1f51d;&#x1f51d; 开发环境: Visual Studio 2022 项目日…

vit细粒度图像分类(九)RAMS-Trans学习笔记

1.摘要 在细粒度图像识别(FGIR)中&#xff0c;区域注意力的定位和放大是一个重要因素&#xff0c;基于卷积神经网络(cnn)的方法对此进行了大量探索。近年来发展起来的视觉变压器(ViT)在计算机视觉任务中取得了可喜的成果。与cnn相比&#xff0c;图像序列化是一种全新的方式。然…

逸学区块链【solidity】真随机数

参考Get a Random Number | Chainlink Documentation 但是很贵&#xff0c;价格 Gas Price&#xff1a;当前gas价格&#xff0c;根据网络状况而波动。Callback gas &#xff1a;返回您所请求的随机值时&#xff0c;回调请求消耗的gas 量。验证gas &#xff1a;量gas 用于验证…

优质成长:新生儿补充维生素B6的关键注意事项

引言&#xff1a; 维生素B6&#xff0c;作为B族维生素的一员&#xff0c;对于新生儿的神经系统发育和代谢功能至关重要。本文将深入探讨维生素B6的作用、新生儿补充的必要性&#xff0c;以及在补充维生素B6时应该注意的事项&#xff0c;为父母提供科学、全面的育儿指南。 第一…

windows pm2 执行 npm脚本或执行yarn脚本遇到的问题及解决方案

环境&#xff1a; 在windows上启动终端来运行一个项目&#xff1b;通过指令npm run start来启动&#xff0c;但是将终端一关&#xff0c;就无法访问了&#xff0c;所以想到用pm2来管理 1. 全局安装pm2 npm i pm2 -g2. 在项目根目录执行指令(大部分兄弟的错误使用方法) pm2 st…

C++初阶:适合新手的手撕string类(模拟实现string类)

上次讲了常用的接口&#xff1a;C初阶&#xff1a;初识STL、String类接口详细讲解&#xff08;万字解析&#xff09; 今天就来进行模拟实现啦 文章目录 1.基本结构与文件规划2.构造函数&#xff08;constructor)2.1构造函数2.1.1无参有参分开2.1.2利用缺省参数合起来 2.2拷贝构…

【Vue.js设计与实现】第二篇:响应系统-阅读笔记(持续更新)

从高层设计的角度去探讨框架需要关注的问题。 系列目录&#xff1a; 标题博客第一篇&#xff1a;框架设计概览【Vue.js设计与实现】第一篇&#xff1a;框架设计概览-阅读笔记第二篇&#xff1a;响应系统【Vue.js设计与实现】第二篇&#xff1a;响应系统-阅读笔记第三篇&#x…

flutter开发实战-ijkplayer视频播放器功能

flutter开发实战-ijkplayer视频播放器功能 使用better_player播放器进行播放视频时候&#xff0c;在Android上会出现解码失败的问题&#xff0c;better_player使用的是video_player&#xff0c;video_player很多视频无法解码。最终采用ijkplayer播放器插件&#xff0c;在flutt…

EasyX图形库学习(二、文字输出)

目录 一、文字绘制函数 字体属性结构体:logfont 文字输出 outtextxy 在指定位置输出字符串。 ​编辑 但如果直接使用,可能有以下报错&#xff1a; 三种解决方案&#xff1a; 将一个int类型的分数,输出到图形界面上 如果直接使用&#xff1a; 会把score输入进去根据A…

Docker基础知识

1、什么是Docker&#xff1f;Docker解决了什么问题 一个项目中&#xff0c;部署时需要依赖于node.js、Redis、RabbitMQ、MySQL等&#xff0c;这些服务部署时所需要的函数库、依赖项各不相同&#xff0c;甚至会有冲突。给部署带来了极大的困难。 所以引入了Docker Docker为了…

MaxKey 单点登录认证系统——登录验证流程分析

客户端依赖包 <dependency><groupId>net.unicon.cas</groupId><artifactId>cas-client-autoconfig-support</artifactId><version>2.3.0-GA</version> </dependency>未登录时 浏览器向客户端发送请求 http://localhost:8989/…

高级Java开发工程师岗位的基本职责(合集)

高级Java开发工程师岗位的基本职责1 职责&#xff1a; 1、负责区块链产品的研发&#xff0c;独立或与团队合作&#xff0c;按时保质完成软件开发项目; 2、参与产品系统设计、概要设计工作&#xff0c;核心功能的代码编写; 3、独立解决和指导其他同事处理开发中遇到的难点问题; …

Qt扩展-muParser数学公式解析

muParser数学公式解析 一、概述1. 针对速度进行了优化2. 支持的运算符3. 支持的函数4. 用户定义的常量5. 用户定义的变量6. 自定义值识别回调7. 其他功能 二、内置函数三、内置二元运算符四、三元运算符五、内置常量六、源码引入1. 源码文件2. 编译器开关1. MUP_BASETYPE2.MUP_…

Unity DOTS中的baking(三)过滤baking的输出

Unity DOTS中的baking&#xff08;三&#xff09;过滤baking的输出 默认情况下&#xff0c;在conversation world&#xff08;baker和baking system运行的环境&#xff09;下产生的所有entities和components&#xff0c;都会作为baking环节的输出。在baking结束时&#xff0c;U…

重写Sylar基于协程的服务器(5、IO协程调度模块的设计)

重写Sylar基于协程的服务器&#xff08;5、IO协程调度模块的设计&#xff09; 重写Sylar基于协程的服务器系列&#xff1a; 重写Sylar基于协程的服务器&#xff08;0、搭建开发环境以及项目框架 || 下载编译简化版Sylar&#xff09; 重写Sylar基于协程的服务器&#xff08;1、…

STM32--USART串口(2)串口外设

一、USART简介 可配置数据位&#xff1a;不需要校验就是8位&#xff0c;需要校验就选9位&#xff1b; 停止位&#xff1a;决定了帧的间隔; STM32F103C8T6USART&#xff1a;USART1挂载在APB2总线上&#xff0c;USART2和USART3挂载在APB1总线上&#xff1b; 二、USART框图 TXE…