spring揭秘01-spring容器启动过程分析

文章目录

【README】

本文总结自《spring揭秘》,作者王福强,非常棒的一本书,墙裂推荐;

spring容器根据配置元素组装可用系统分2个阶段,包括spring容器启动, springbean实例化阶段; 本文详细分析spring容器启动阶段;


【1】Spring容器根据配置元素组装可用系统的过程

Spring容器根据配置元素组装可用系统的过程,有2个阶段:

  • spring容器启动;
  • springbean实例化;

容器启动阶段: 加载配置元数据(xml文件),然后使用工具类如 BeanDefinitionReader对加载的配置元数据进行解析,并将结果编组为 BeanDefinition ,注册到相应的 BeanDefinitionRegistry,这样容器启动工作就完成了;

Bean实例化阶段: 容器会首先检查所请求的对象之前是否已经初始化,若没有,则根据注册的BeanDefinition实例化bean,并为其注入依赖。 如果该对象实现了某些回调接口,也会根据回调接口的要求来装配它; 当该对象被装配完成后 ,容器会立即将其返回给请求方使用;


【2】BeanFactoryPostProcessor-Bean工厂后置处理器

BeanFactoryPostProcessor: Spring提供了叫做 BeanFactoryPostProcessor 容器扩展机制; 该机制允许我们在容器启动阶段完成后新增逻辑;

常用BeanFactoryPostProcessor:

  1. PropertySourcePlaceHolderConfigurer:属性占位符配置器, 如jdbc连接串属性通过properties文件的属性值 ++替换++ 占位符;
  2. PropertyOverrideConfigurer : 属性覆盖替换配置器;如修改属性值;
  3. CustomEditorConfigurer:自定义编辑器配置器,用于不同数据格式间的转换;

【补充】

(1)上述2个BeanFactoryPostProcessor 都是通过修改BeanDefinition 来对属性进行替换或修改的;

(2) CustomerEditorConfigurer:没有修改BeanDefinition,而是把后期要用到的信息注册到容器;

【2.1】属性占位符配置器使用场景代码

PropertySourcesPlaceholderConfigurer-属性占位符配置器使用场景:初始化数据库连接池属性, 并利用 PropertyOverrideConfigurer 重写属性值;

【PropertySourcesPlaceholderConfigurerMain】入口

java 复制代码
public class PropertySourcesPlaceholderConfigurerMain {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans0404.xml");
        BasicDataSource dataSource = context.getBean("dataSource", BasicDataSource.class);
        System.out.println(dataSource.getUrl());
        System.out.println(dataSource.getUserName());
        System.out.println(dataSource.getDriverClassName());
    }
}

【beans0404.xml】

xml 复制代码
<!-- 为 PropertySourcesPlaceholderConfigurer 这个BeanFactoryPostProcessor 配置属性文件地址 -->
    <bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
        <property name="locations">
            <value>jdbc.properties</value>
        </property>
    </bean>

    <!-- 为 PropertyOverrideConfigurer 这个BeanFactoryPostProcessor 配置重写属性文件的地址 -->
    <bean class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
        <property name="locations" value="ds-pool-override.properties" />
    </bean>

    <!-- 数据源bean,其中属性值通过变量指定,变量通过 BeanFactoryPostProcessor 设置值-->
    <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
        <property name="url">
            <value>${jdbc.url}</value>
        </property>
        <property name="driverClassName">
            <value>${jdbc.driverClassName}</value>
        </property>
        <property name="username">
            <value>${jdbc.username}</value>
        </property>
        <property name="password">
            <value>${jdbc.password}</value>
        </property>
    </bean>

【jdbc.properties】

c++ 复制代码
jdbc.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai
jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.username=root
jdbc.password=root

【ds-pool-override.properties】重写属性值的属性文件

c++ 复制代码
dataSource.username=rootOverride

【打印日志】

c++ 复制代码
jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai
rootOverride
com.mysql.cj.jdbc.Driver

【2.2】CustomerEditorConfigurer-自定义编辑器配置器

应用场景: xml配置的bean信息都是字符串,但最终都要要转换为bean对象的,从字符串类型到对象类型的转换,就是由CustomerEditorConfigurer(EditorConfigurer)来完成的;

  • 只要为每种对象类型提供一个 PropertyEditor,就可以做类型转换

Spring 提供的PropertyEditor列表

  • (1) StringArrayPropertyEditor:把符合csv格式的字符串转换为String[] 数组的形式;类似的还有 ByteArrayPropertyEditor, CharArrayPropertyEditor;
  • (2) ClassEditor: 根据class名称转为 Class对象;
  • (3) FileEditor: file类型的PropertyEditor;类似的还有InputStreamEditor, URLEditor;
  • (4) LocaleEditor: 本地化转换;
  • (5) PatternEditor: 正则表达式转换

自定义属性编辑器PropertyEditor: 继承自 PropertyEditorSupport ; PropertyEditorSupport 实现了 PropertyEditor 接口; PropertyEditor 接口定义如下:

java 复制代码
public interface PropertyEditor {

    void setValue(Object value);

    Object getValue();

    boolean isPaintable();
    
    void paintValue(java.awt.Graphics gfx, java.awt.Rectangle box);

    String getJavaInitializationString();

    String getAsText();
   
    void setAsText(String text) throws java.lang.IllegalArgumentException;
    
    String[] getTags();
    
    java.awt.Component getCustomEditor();

    boolean supportsCustomEditor();

    void addPropertyChangeListener(PropertyChangeListener listener);

    void removePropertyChangeListener(PropertyChangeListener listener);
}

【2.3】自定义编属性编辑器案例代码

自定义日期i字符串转日期类型的编辑器;

【CustomPropertyEditorMain】入口

java 复制代码
public class CustomPropertyEditorMain {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans0404.xml");
        System.out.println(context.getBean("customDateDto", CustomDateDto.class));
    }
}

【beans0404.xml】

xml 复制代码
<!-- 自定义属性编辑器  -->
<bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
    <property name="propertyEditorRegistrars">
        <list>
            <ref bean="customDatePropertEditroResigtrar" />
        </list>
    </property>
</bean>
<bean id="customDatePropertEditroResigtrar" class="com.tom.springnote.chapter04.t0404.CustomDatePropertEditroResigtrar">
    <property name="customDatePropertyEditor">
        <ref bean="customDatePropertyEditor"/>
    </property>
</bean>
<bean id="customDatePropertyEditor" class="com.tom.springnote.chapter04.t0404.CustomDatePropertyEditor">
    <property name="datePattern" value="yyyy-MM-dd" />
</bean>
<bean id="customDateDto" class="com.tom.springnote.chapter04.t0404.CustomDateDto">
    <property name="date" value="2024-08-04" />
</bean>

【CustomDatePropertEditroResigtrar】自定义日期属性编辑器注册器

java 复制代码
public class CustomDatePropertEditroResigtrar implements PropertyEditorRegistrar {
    private PropertyEditor customDatePropertyEditor;
    @Override
    public void registerCustomEditors(PropertyEditorRegistry registry) {
        registry.registerCustomEditor(Date.class, getCustomDatePropertyEditor());
    }

    public PropertyEditor getCustomDatePropertyEditor() {
        return customDatePropertyEditor;
    }

    public void setCustomDatePropertyEditor(PropertyEditor customDatePropertyEditor) {
        this.customDatePropertyEditor = customDatePropertyEditor;
    }
}

【CustomDatePropertyEditor】自定义日期属性编辑器

java 复制代码
public class CustomDatePropertyEditor extends PropertyEditorSupport {
    private String datePattern;

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        try {
            setValue(new SimpleDateFormat(getDatePattern()).parse(text));
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    public String getDatePattern() {
        return datePattern;
    }

    public void setDatePattern(String datePattern) {
        this.datePattern = datePattern;
    }
}

【CustomDateDto】自定义dto (带date类型属性)

java 复制代码
public class CustomDateDto {
    private Date date;

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    @Override
    public String toString() {
        return "CustomDateDto{" +
                "date=" + date +
                '}';
    }
}

【打印日志】 (把字符串2024-08-04转换为 date类型属性)

c++ 复制代码
CustomDateDto{date=Sun Aug 04 00:00:00 CST 2024}
相关推荐
Abladol-aj28 分钟前
并发和并行的基础知识
java·linux·windows
清水白石00828 分钟前
从一个“支付状态不一致“的bug,看大型分布式系统的“隐藏杀机“
java·数据库·bug
吾日三省吾码6 小时前
JVM 性能调优
java
Estar.Lee6 小时前
查手机号归属地免费API接口教程
android·网络·后端·网络协议·tcp/ip·oneapi
弗拉唐7 小时前
springBoot,mp,ssm整合案例
java·spring boot·mybatis
oi777 小时前
使用itextpdf进行pdf模版填充中文文本时部分字不显示问题
java·服务器
2401_857610038 小时前
SpringBoot社团管理:安全与维护
spring boot·后端·安全
少说多做3438 小时前
Android 不同情况下使用 runOnUiThread
android·java
知兀8 小时前
Java的方法、基本和引用数据类型
java·笔记·黑马程序员