# Spring 配置

# 元数据基本配置

以下示例显示了基于 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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="..." class="...">  
        <!-- collaborators and configuration for this bean go here -->
    </bean>
    <bean id="..." class="...">
        <!-- collaborators and configuration for this bean go here -->
    </bean>
    <!-- more bean definitions go here -->
</beans>
id 属性是一个字符串,用于标识单个 bean 定义。
class 属性定义 bean 的类型并使用完全限定的类名。

id 属性的值是指协作对象。此示例中未显示用于引用协作对象的 XML。

# 别名

可以使用 <alias/> 元素来完成此操作。以下示例显示了如何执行此操作:

<alias name="fromName" alias="toName"/>

在这种情况下,命名的 bean(在同一容器中) fromName 也可以在使用此别名定义后称为 toName .

例如,子系统 A 的配置元数据可能引用名为 的数据源 subsystemA-dataSource 。子系统 B 的配置元数据可以通过名称来引用数据源 subsystemB-dataSource 。在组合使用这两个子系统的主应用程序时,主应用程序通过名称引用 DataSource myApp-dataSource 。要让所有三个名称都引用同一个对象,可以将以下别名定义添加到配置元数据中:

<alias name="myApp-dataSource" alias="subsystemA-dataSource"/>
<alias name="myApp-dataSource" alias="subsystemB-dataSource"/>

现在每个组件和主应用程序都可以通过一个唯一的名称来引用数据源,并且保证不会与任何其他定义发生冲突(有效地创建一个命名空间),但它们引用同一个 bean。

User.java

public class User {
    private String name;
    public  User(String name){
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void show() {
        System.out.println("name=" + name);
    }
}

配置文件:

<bean id="user" class="com.Spring.User">
        <constructor-arg name="name" value="李六"></constructor-arg>
    </bean>
<alias name="user" alias="h1"></alias>

测试程序代码:

public class MyText {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        User user1 = (User) context.getBean("h1");
        User user2 = (User) context.getBean("h1");
        user1.show();
        user2.show();
    }
}
// 控制台就会输出:
//     name = 李四
//     name = 李四

# bean 配置

<!--
    id: bean 的唯一标识符,也就是相当于我们学的对象名
    class: bean 对象所对应的全限定名:包名 + 类名
    name: 也是别名,而且 name 可以同时取多个别名 (命名之间可以使用空格、分号或者逗号分隔)
    -->
<bean id="userT" class="com.xia.pojo.UserT" name="user2 u2,us2;uss2"></bean>

# import

这个 import,一般用于团队开发使用,他可以将多个配置文件,导入合并为一个。

假设,现在项目中有多个人开发,这三个人负责不同的类的开发,不同的类需要注册在不同的 bean 中,文名可以利用 import 将所有人的 beans.xml 合并为一个总的!

<beans>
    <import resource="services.xml"/>
    <import resource="resources/messageSource.xml"/>
    <import resource="/resources/themeSource.xml"/>
    <bean id="bean1" class="..."/>
    <bean id="bean2" class="..."/>
</beans>

在 applicationContext.xml 里面导入对应的配置,就可以将所有配置汇总,这样创建容器的时候就可以只导入 applicationContext.xml

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

在诸多配置中出现 id 相同的时候,这些 ID 的 value 不相同的时候,后面的内容会覆盖掉前面的内容

# 依赖注入

# 构造器注入

示例显示了一个只能使用构造函数注入进行依赖注入的类:

public class SimpleMovieLister {
    // the SimpleMovieLister has a dependency on a MovieFinder
    private final MovieFinder movieFinder;
    // a constructor so that the Spring container can inject a MovieFinder
    public SimpleMovieLister(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
    // business logic that actually uses the injected MovieFinder is omitted...
}

请注意,这个类没有什么特别之处。它是一个不依赖于容器特定接口、基类或注释的 POJO(简单的 Java 对象,实际就是普通 JavaBeans,是为了避免和 EJB 混淆所创造的简称)。

# Set 方法注入

  • 依赖注入
    • 依赖:bean 对象的创建依赖于容器
    • 注入:bean 对象中的所有属性,由容器注入

示例:

public class Student {
    private String name;
    private address address;
    private String wifi;
    private String[] books;
    private List<String> hobby;
    private Map<String, String> card;
    private Set<String> games;
    private Properties info;
}
public class address {
    private String address;
}

beans.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:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
    <bean id="address" class="com.pojo.address"></bean>
    <bean id="student" class="com.pojo.Student">
        <!-- 第一种:普通值的注入  property->value  -->
        <property name="name" value="A"></property>
        <!-- 第二种:bean 注入 使用 ref 注入  -->
        <property name="address" ref="address"></property>
        <!-- 第三种:数组注入 (上面两个也可以以这种形式注入,但是直接使用 value=“” 更加方便) -->
        <property name="books">
            <array>
                <value>红楼梦</value>
                <value>水浒传</value>
                <value>三国演义</value>
                <value>西游记</value>
            </array>
        </property>
        <!-- 第四种注入:list 集合注入 -->
        <property name="hobby">
            <list>
                <value>看小说</value>
                <value>追番剧</value>
                <value>听音乐</value>
            </list>
        </property>
        <!-- 第五种注入:Map 集合注入 -->
        <property name="card">
            <map>
                <entry key="姓名" value="愧诗"/>
                <entry key="性别" value=""/>
                <entry key="年龄" value="18"/>
            </map>
        </property>
        <!-- 第六种注入:Set 集合注入 -->
        <property name="games">
            <set>
                <value>LOL</value>
                <value>BOB</value>
            </set>
        </property>
        
        <!-- 第七种注入:null 注入 -->
        <property name="wifi" >
            <null></null>
        </property>
        <!-- 第八种注入:property 注入 -->
        <property name="info">
            <props>
                <prop key="工作">......</prop>
                <prop key="来自">天启预报</prop>
                <!-- 最常见到的用法:-->
                <prop key="url">https://iyhi.github.io</prop>
                <prop key="username">YH</prop>
                <prop key="password">XXXXXX</prop>
            </props>
        </property>
    </bean>
</beans>

测试类:

public class MyText {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Student student= (Student) context.getBean("student");
        System.out.println(student.toString());
    }
}
    /* 控制台输出:
        Student {
        name='A', 
        address=address {address='null'}, 
        wifi='null', 
        books=[红楼梦,水浒传,三国演义,西游记], 
        hobby=[看小说,追番剧,听音乐], 
        card={姓名 = 愧诗,性别 = 男,年龄 = 18}, 
        games=[LOL, BOB], 
        info={
        	来自 = 天启预报,
        	password=XXXXXX, 
        	url=https://iyhi.github.io, 
        	工作 =......, 
        	username=YH}}
         */

# 拓展方式注入

p-namespace 允许您使用 bean 元素的属性(而不是嵌套 <property/> 元素)来描述协作 bean 的属性值,或两者兼而有之。

Spring 支持具有命名空间的可扩展配置格式,这些格式基于 XML 模式定义。

p 命名空间并未在 XSD 文件中定义,仅存在于 Spring 的核心中、

以下示例显示了两个解析为相同结果的 XML 片段(第一个使用标准 XML 格式,第二个使用 p 命名空间):

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean name="classic" class="com.example.ExampleBean">
        <property name="email" value="someone@somewhere.com"/>
    </bean>
    <bean name="p-namespace" class="com.example.ExampleBean"
        p:email="someone@somewhere.com"/>
</beans>

该示例显示了 email 在 bean 定义中调用的 p 命名空间中的一个属性。这告诉 Spring 包含一个属性声明。如前所述,p 命名空间没有模式定义,因此可以将属性的名称设置为属性名称。

c-namespace 允许内联属性来配置构造函数参数而不是嵌套 constructor-arg 元素。

示例 P、C 命名空间:

User 文件

public class User {
    private String name;
    private int age;
    public User() {
    }
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--p 命名空间注入 -->
    <bean id="user" class="com.pojo.User" p:age="18" p:name="愧诗">
    </bean>
    <!--c 命名空间注入,通过构造器注入,前提条件是类里面必须要有 有参构造函数 (当你设置了有参构造函数的时候,默认的无参构造就会消失,就会引起上面的错误)-->
    <bean id="user2" class="com.pojo.User" c:_0="愧诗" c:_1="18"></bean>
</beans>

官方文档说明位置:p 命名空间说明 c 命名空间说明

注意:p 命名和 c 命名空间不能直接使用,需要导入 xml 约束!

xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"

# bean 作用域

ScopeDescription
singleton(默认)将单个 bean 定义范围限定为每个 Spring IoC 容器的单个对象实例。
prototype将单个 bean 定义范围限定为任意数量的对象实例。
request将单个 bean 定义范围限定为单个 HTTP 请求的生命周期。也就是说,每个 HTTP 请求都有自己的 bean 实例,该 bean 实例是在单个 bean 定义的后面创建的。仅在 web-aware Spring 的上下文中有效 ApplicationContext
session将单个 bean 定义范围限定为 HTTP 的生命周期 Session 。仅在 web-aware Spring 的上下文中有效 ApplicationContext .
application将单个 bean 定义范围限定为 ServletContext . 仅在 web-aware Spring 的上下文中有效 ApplicationContext
websocket将单个 bean 定义范围限定为 WebSocket . 仅在 web-aware Spring 的上下文中有效 ApplicationContext .

# 重点:

# 单例模式(Spring 默认机制)
<bean id="user" class="com.xia.pojo.User" p:age="18" p:name="愧诗" scope="singleton"></bean>
# 原型模式:每一次从容器中 get 的时候,都会产生一个新的对象
<bean id="user" class="com.xia.pojo.User" p:age="18" p:name="愧诗" scope="prototype"></bean>

其余的 request、session、application,这些只能在 web 开发中使用到!

有待更新...