SpringFramework — 配置源&配置元信息

小龙 528 2022-05-17

配置源

就是配置的来源,像使用 xml 配置文件或者注解配置类来驱动 IOC 容器,那么对于 IOC 容器而言,xml 配置文件或者注解配置类就可以称之为配置源。

Spring 是如何根据我们写好的配置源驱动起整个应用上下文的

Spring 拿到配置源后肯定是先加载再解析最后注册那些定义好的 bean 到 IOC 容器

配置源的解析思路

XML配置源解析

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.linkedbear.spring.basic_di.c_value_spel.bean"/>

    <context:property-placeholder location="classpath:basic_di/value/red.properties"/>

    <bean id="person" class="com.linkedbear.spring.basic_di.a_quickstart_set.bean.Person">
        <property name="name" value="test-person-byset"/>
        <property name="age" value="18"/>
    </bean>
</beans>

这个XML中包含了几个基本信息

  • component-scan:声明包扫描

  • property-placeholder:引用外部 properties 文件

  • bean: 注册 Bean 并赋值

上面的这些标签能使用是因为在xml文件头上约束声明的

给上面这个xml一个定义解释:

  • xml中包含一条组件扫描的声明

  • 包含一条properties资源文件引入的声明

  • 包含一个bean的注册

把这些定义抽象成一种语言描述:

bean.xml {
	context:[component-scan,property-placeholder]
    beans: [person]
}

注解配置类

写一个待注解的配置类

@Configuration
@ComponentScan("com.linkedbear.spring.bean.b_scope.bean")
public class BeanScopeConfiguration {
    
    @Bean
    public Child child1(Toy toy) {
        Child child = new Child();
        child.setToy(toy);
        return child;
    }
    
    @Bean
    public Child child2(Toy toy) {
        Child child = new Child();
        child.setToy(toy);
        return child;
    }
}

根据xml中的抽象,这个注解配置也可以抽象成一下形式:

BeanScopeConfiguration .java {
	context: [ComponentScan]
    beans: [child1,child2]
}

在这两个抽象定义中只记录配置类中的配置结构,任何配置信息都不会体现在这里面。

元信息

上面的配置源解析思路像是把整个文件中配置的所有定义都抽取出来了,形成了一个类似于配置定义信息的东西。这个东西就与元信息类似

理解元信息

元信息,又可以理解为元定义,简单的说,它就是定义的定义。

这样有点抽象,直接看一例子

  • 张三,男,18岁
    • 它的元信息就是它的属性们:Person {name, age, sex}
  • 咪咪,美国短毛,黑白毛,主人是张三
    • 它的元信息可以抽取为: Cat {name, type, color, master}

上面这种形式就是 类中包含对象的元信息。

在Class中就包含了类的元信息一个类的所有定义(属性、方法、继承实现、注解等)

在举个例子:数据库表结构信息,这也是非常典型的信息与元信息:数据库表结构描述了数据库表的整体表属性,以及表字段的属性。

SpringFramework中的配置元信息

Bean的定义元信息

和上面 class 描述类相似,SpringFramework中定义的Bean也会封装为一个个Bean的元信息,就是 BeanDifinition,这个BeanDifinition包含了一个Bean需要的几乎所有的维度定义

  • Bean 的全限定名 className

  • Bean 的作用域 scope

  • Bean 是否延迟加载 lazy

  • Bean 的工厂Bean 名称 factoryBean

  • Bean 构造方法参数列表 constructorArgumentValues

  • Bean 的属性值 propertyValues

  • … … …

可以发现基本上一个Bean的所有特征、属性全都描述出来了

OC容器的配置元信息

在xml文件的 <beans></beans> 标签中也有一些属性,只不过这些属性在开发中几乎用不到,所有都使用默认值了

配置元信息 含义 / 作用 默认值
profile 基于环境的配置 “”
default-autowire 默认的自动注入模式(不需要声明 @Autowired 等注解即可注入组件) default(no)
default-autowire-candidates 满足指定属性名规则的属性才会被自动注入 “”
default-init-method 全局 bean 的初始化方法 “”
default-destroy-method 全局 bean 的销毁方法 “”
default-lazy-init 全局 bean 是否延迟加载 default(false)
default-merge 继承父 bean 时直接合并父 bean 的属性值 default(false)

注:默认值中提到的 default 是在没有声明时继承父配置的默认值( 标签是可以嵌套使用的),如果都没有声明,则配置的默认值是括号内的值。

context的配置元信息

<context></context>标签中也有一些IOC容器的配置元信息

配置元信息 含义 / 作用
<context:annotation-config/> 开启注解驱动
<context:component-scan/> 开启组件扫描
<context:property-placeholder/> 引入外部的资源文件( properties xml yml 等)
<context:property-override/> 指定配置源会覆盖全局配置(可用于配置覆盖)
<context:spring-configured/> 可以对没有注册到 IOC 容器的 bean 实现依赖注入
<context:load-time-weaver/> 与 AOP 相关(放到 AOP 章节介绍)
<context:mbean-server/> 暴露应用运行状态监控(与 JMX 管理监控有关)
<context:mbean-export/> 注册 MBean 到 JMX 实现运行状态监控(与 JMX 管理监控有关)

这一堆标签中只有前三个是经常使用的

beans的其他配置元信息

在 beans 的命名空间里还有两个常用的标签,而且也都比较简单:

配置元信息 含义 / 作用 使用方式举例
<alias /> 给指定的 bean 指定别名 <alias name="person" alias="zhangsan"/>
<import /> 导入外部现有的 xml 配置文件 <import resource="classpath:basic_dl/quickstart-byname.xml"/>

properties等配置元信息

SpringFramework中支持properties 、xml 、yml 文件,它们的作用都是为了将具体的配置抽取为一个可任意修改的配置文件,防止在程序代码中出现硬编码配置,导致修改配置还需要重新编译的麻烦。这种将配置内容抽取为配置文件的动作,我们称之为 “配置外部化”,抽取出来的配置文件又被成为 “外部化配置文件” 。而加载这些外部化配置文件的方式,要么通过上面的 <context:property-placeholder/> ,要么通过 @PropertySource 注解,它们最终都会被封装为一个一个的 PropertySource 对象( properties 文件被封装为 PropertiesPropertySource )了,而这个 PropertySource 对象内部就持有了这些外部化配置文件的所有内容。



# IOC