Spring Framework 基础 第三章 Spring 配置文件


Spring Framework 基础 —— 第三章 Spring 配置文件


1. Bean 标签基本配置

用于配置对象交由 Spring 来创建。

默认情况下它调用的是类中的无参构造函数,如果没有无参构造函数则不能创建成功。

基本属性:

  • idBean 实例在 Spring 容器中的唯一标识
  • classBean 的全限定名称

2. Bean 标签的配置范围

Scope:指对象的作用范围,取值如下:

取值范围 说明
singleton (默认)单例的
prototype 多列的
Request Web 项目中,Spring 创建一个 Bean 对象,将对象存入到 request 域中
session Web 项目中,Spring 创建一个 Bean 对象,将对象存入到 session 域中
global session Web 项目中,应用在 Portlet 环境,如果没有 Portlet 环境,那么 golbalSession 相当于 session

测试代码:

com.yourname.test.SpringTest

import com.gregperlinli.dao.UserDao;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringTest {
    /**
     * Test scope attribute
     */
    @Test
    public void test1() {
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao1 = (UserDao) app.getBean("userDao");
        UserDao userDao2 = (UserDao) app.getBean("userDao");
        System.out.println(userDao1);
        System.out.println(userDao2);
    }
}

测试结果:

scope="singletion"

com.gregperlinli.dao.impl.UserDaoImpl@342c38f8
com.gregperlinli.dao.impl.UserDaoImpl@342c38f8

scope="prototype"

com.gregperlinli.dao.impl.UserDaoImpl@4f2b503c
com.gregperlinli.dao.impl.UserDaoImpl@bae7dc0

注意⚠️:

  1. scope 取值为 singleton 时:
    • Bean 的实例化个数:1个
    • Bean 的实例化时机:当 Spring 核心配置文件被加载时,实例化配置 Bean 实例
    • Bean 的生命周期:
      • 对象创建:当应用加载,创建容器时,对象就已经创建了
      • 对象运行:只要容器在,对象就一直活着
      • 对象销毁:当应用卸载,销毁容器时,对象就被销毁了
  2. scope 取值为 prototype 时:
    • Bean 的实例化个数:多个
    • Bean 的实例化时机:当调用 getBean() 方法时实例化 Bean
    • Bean 的生命周期:
      • 对象创建:当使用对象时,创建新的对象实例
      • 对象运行:只要对象在容器中,就一直活着
      • 对象销毁:当对象长时间不用时,被 Java 垃圾回收器回收了

3. Bean 生命周期配置

  • init-method指定类中的初始化方法名称
  • destroy-method制定类中的销毁方法名称

测试代码:

com.yourname.dao.impl.UserDaoImpl

import com.gregperlinli.dao.UserDao;

public class UserDaoImpl implements UserDao {
    public UserDaoImpl() {
        System.out.println("UserDaoImpl created......");
    }
    public void init() {
        System.out.println("Initialize method...");
    }
    public void destroy() {
        System.out.println("Destroy method...");
    }
    @Override
    public void save() {
        System.out.println("Save running......");
    }
}

applicationContext

<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userDao" class="com.gregperlinli.dao.impl.UserDaoImpl" scope="prototype" init-method="init" destroy-method="destroy"></bean>

</beans>

com.yourname.test.SpringTest

import com.gregperlinli.dao.UserDao;
import org.junit.jupiter.api.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringTest &#123;
    /**
     * Test scope attribute
     */
    @Test
    public void test1() &#123;
        ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = (UserDao) app.getBean("userDao");
        System.out.println(userDao);
        app.close();
    &#125;
&#125;

测试结果:

UserDaoImpl created......
Initialize method...
com.gregperlinli.dao.impl.UserDaoImpl@32502377
Destroy method...

4. Bean 实例化的三种方式

  1. 无参构造方法实例化(重点)

  2. 工厂静态方法实例化

  3. 工厂实例方法实例化

示例代码:

  1. 工厂静态方法实例化

    com.yourname.factory.StaticFactory

    import com.gregperlinli.dao.UserDao;
    import com.gregperlinli.dao.impl.UserDaoImpl;
    
    public class StaticFactory &#123;
        public static UserDao getUserDao() &#123;
            return new UserDaoImpl();
        &#125;
    &#125;
    

    applicationContext

    <?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 http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="userDao" class="com.gregperlinli.factory.StaticFactory" factory-method="getUserDao"></bean>
    
    </beans>
    
  2. 工厂实例方法实例化

    com.yourname.factory.DynamicFactory

    import com.gregperlinli.dao.UserDao;
    import com.gregperlinli.dao.impl.UserDaoImpl;
    
    public class DynamicFactory &#123;
        public UserDao getUserDao() &#123;
            return new UserDaoImpl();
        &#125;
    &#125;
    

    applicationContext

    <?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 http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="factory" class="com.gregperlinli.factory.DynamicFactory"></bean>
        <bean id="userDao" factory-bean="factory" factory-method="getUserDao"></bean>
    
    </beans>
    

5. Bean 的依赖注入分析

示例代码:

com.yourname.service.UserService

public interface UserService &#123;
    public void save();
&#125;

com.yourname.service.impl.UserServiceImpl

import com.gregperlinli.dao.UserDao;
import com.gregperlinli.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserServiceImpl implements UserService &#123;
    @Override
    public void save() &#123;
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = (UserDao) app.getBean("userDao");
        userDao.save();
    &#125;
&#125;

com.yourname.demo.UserController

import com.gregperlinli.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserController &#123;
    public static void main(String[] args) &#123;
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService) app.getBean("userService");
        userService.save();
    &#125;
&#125;

applicationContext

<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userDao" class="com.gregperlinli.dao.impl.UserDaoImpl"></bean>
    <bean id="userService" class="com.gregperlinli.service.impl.UserServiceImpl"></bean>

</beans>

目前 UserService 实例和 UserDao 实例都写在 Spring 容器中,当前做法是在容器外获取 UserService 实例和 UserDao 实例,然后再程序中进行结合。

image-20210715101215649

因为 UserServiceUserDao 都在容器中,而最终的程序直接使用的是 UserService,所以可在 Spring 容器中,将 UserDao 设置到 UserService内部。

image-20210715102011353

6. 依赖注入概念

依赖注入Dependency Injection 简称 DI):它是 Spring 核心框架 IoC 的具体实现

在编写程序时,通过控制反转,把对象的创建交给了 Spring,但是代码中不可能出现没有依赖的情况。IoC 解耦只是降低它们的依赖关系,但不会消除。例如:业务层仍会调用持久层的方法。

那这种业务层和持久层的依赖关系,在使用 Spring 之后,就让 Spring 来维护了。简单的说,就是坐等框架把持久层对像传入业务层,而不用我们自己去获取。

7. Bean 的依赖注入方式

怎么将 UserDao 注入到 UserService 内部呢?主要有两种方式:

  1. 构造方法

  2. set 方法

示例代码:

  1. set 方法注入

    com.yourname.service.impl.UserServiceImpl

    import com.gregperlinli.dao.UserDao;
    import com.gregperlinli.service.UserService;
    
    public class UserServiceImpl implements UserService &#123;
        private UserDao userDao;
    
        public void setUserDao(UserDao userDao) &#123;
            this.userDao = userDao;
        &#125;
        @Override
        public void save() &#123;
            userDao.save();
        &#125;
    &#125;
    

    com.yourname.demo.UserController

    import com.gregperlinli.service.UserService;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class UserController &#123;
        public static void main(String[] args) &#123;
            ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
            UserService userService = (UserService) app.getBean("userService");
            userService.save();
        &#125;
    &#125;
    

    applicationContext

    <?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 http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="userDao" class="com.gregperlinli.dao.impl.UserDaoImpl"></bean>
        <bean id="userService" class="com.gregperlinli.service.impl.UserServiceImpl">
            <property name="userDao" ref="userDao"></property>
        </bean>
    
    </beans>
    

    set 方法注入的简便化 —— P 命名空间注入

    ​ P 命名空间注入本质也是 set 方法注入,但比起上述的 set 方法注入更为简便,主要体现在配置文件中,如下所示:

    ​ 首先,在 beans 标签内引入 P 命名空间:

    <beans ... xmlns:p="http://www.springframework.org/schema/p" ... ></beans>
    

    ​ 其次,需要修改注入方式:

    <bean id="userService" class="com.gregperlinli.service.impl.UserServiceImpl" p:userDao-ref="userDao"/>
    

    ​ 简化后效果如下:

    <?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:p="http://www.springframework.org/schema/p"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="userDao" class="com.gregperlinli.dao.impl.UserDaoImpl"></bean>
        <bean id="userService" class="com.gregperlinli.service.impl.UserServiceImpl" p:userDao-ref="userDao"/>
    
    </beans>
    
  2. 构造方法注入

    com.yourname.service.impl.UserServiceImpl

    import com.gregperlinli.dao.UserDao;
    import com.gregperlinli.service.UserService;
    
    public class UserServiceImpl implements UserService &#123;
        private UserDao userDao;
    
        public UserServiceImpl() &#123;
        &#125;
        public UserServiceImpl(UserDao userDao) &#123;
            this.userDao = userDao;
        &#125;
        @Override
        public void save() &#123;
            userDao.save();
        &#125;
    &#125;
    

    application.Context

    <?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 http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="userDao" class="com.gregperlinli.dao.impl.UserDaoImpl"></bean>
        <bean id="userService" class="com.gregperlinli.service.impl.UserServiceImpl">
            <constructor-arg name="userDao" ref="userDao"></constructor-arg>
        </bean>
    
    </beans>
    

8. Bean 的依赖注入的数据类型

上面的操作,都是注入要引用的 Bean,除了对象的引用可以注入,普通的数据类型,集合等都可以在容器中进行注入。

注入数据的三种数据类型:

  1. 普通数据类型

  2. 引用数据类型

  3. 集合数据类型

示例代码:

com.yourname.dao.impl.UserDaoImpl

import com.gregperlinli.dao.UserDao;
import com.gregperlinli.domain.User;
import java.util.List;
import java.util.Map;
import java.util.Properties;

public class UserDaoImpl implements UserDao &#123;
    private List<String> strList;
    private Map<String, User> userMap;
    private Properties properties;
    private String username;
    private int age;

    public UserDaoImpl() &#123;
        System.out.println("UserDaoImpl created......");
    &#125;
    public void setUsername(String username) &#123;
        this.username = username;
    &#125;
    public void setAge(int age) &#123;
        this.age = age;
    &#125;
    public void setStrList(List<String> strList) &#123;
        this.strList = strList;
    &#125;
    public void setUserMap(Map<String, User> userMap) &#123;
        this.userMap = userMap;
    &#125;
    public void setProperties(Properties properties) &#123;
        this.properties = properties;
    &#125;
    public void init() &#123;
        System.out.println("Initialize method...");
    &#125;
    public void destroy() &#123;
        System.out.println("Destroy method...");
    &#125;
    @Override
    public void save() &#123;
        System.out.println("Username: " + username);
        System.out.println("Age: " + age);
        System.out.println(strList);
        System.out.println(userMap);
        System.out.println(properties);
        System.out.println("Save running......");
    &#125;
&#125;

com.yourname.domain.User

public class User &#123;
    private String name;
    private String address;

    public String getName() &#123;
        return name;
    &#125;
    public void setName(String name) &#123;
        this.name = name;
    &#125;
    public String getAddress() &#123;
        return address;
    &#125;
    public void setAddress(String address) &#123;
        this.address = address;
    &#125;
    @Override
    public String toString() &#123;
        return "User&#123;" +
                "name='" + name + '\'' +
                ", address='" + address + '\'' +
                '&#125;';
    &#125;
&#125;

applicationContext.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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userDao" class="com.gregperlinli.dao.impl.UserDaoImpl">
        <property name="username" value="Xiao Ming"/>
        <property name="age" value="18"/>
        <property name="strList">
            <list>
                <value>String1</value>
                <value>String2</value>
                <value>String3</value>
            </list>
        </property>
        <property name="userMap">
            <map>
                <entry key="User1" value-ref="user1"></entry>
                <entry key="User2" value-ref="user2"></entry>
                <entry key="User3" value-ref="user3"></entry>
            </map>
        </property>
        <property name="properties">
            <props>
                <prop key="p1">prop1</prop>
                <prop key="p2">prop2</prop>
                <prop key="p3">prop3</prop>
            </props>
        </property>
    </bean>
    <bean id="user1" class="com.gregperlinli.domain.User">
        <property name="name" value="Tom"/>
        <property name="address" value="Beijing"/>
    </bean>
    <bean id="user2" class="com.gregperlinli.domain.User">
        <property name="name" value="Lucy"/>
        <property name="address" value="Shanghai"/>
    </bean>
    <bean id="user3" class="com.gregperlinli.domain.User">
        <property name="name" value="Jerry"/>
        <property name="address" value="Guangzhou"/>
    </bean>
    <bean id="userService" class="com.gregperlinli.service.impl.UserServiceImpl">
        <constructor-arg name="userDao" ref="userDao"></constructor-arg>
    </bean>

</beans>

9. 引入其他配置文件(分模块开发)

在实际开发中,Spring 的配置内容非常多,这就导致 Spring 的配置很繁杂且体积很大,所以,可以将部分配置拆解到其他配置文件中,而在 Spring 住配置文件通过 import 标签进行加载。

<import resource="applicationContext-xxx.xml"/>

10. Spring 重点配置(重点)

<bean> 标签

id 属性:在容器中 Bean 实例的唯一标识,不允许重复

class 属性:要实例化的 Bean 的全限定名

scope 属性:Bean 的作用范围,常用是 singleton(默认)和 prototype

<property> 标签:属性注入

name 属性:属性名称

value 属性:注入的普通属性值

ref 属性:注入的对象引用值

<list> 标签

<map> 标签

<properties> 标签

<constructor-arg> 标签:有参构造注入

<import> 标签:导入其他的 Spring 的分配置文件



文章作者: gregPerlinLi
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 gregPerlinLi !
  目录