Spring基础知识(3)- Spring IoC、IoC 容器、Spring配置文件


1. IoC 简介

    IoC (Inversion of Control) 被译为“控制反转”,它不是一门技术,而是一种设计思想,是一个重要的面向对象编程法则,能够指导我们如何设计出松耦合、更优良的程序。

    IoC 是从思想层面上发生了 “主从换位” 的改变。原本调用者是主动的一方,它想要使用什么资源就会主动出击,自己创建;但在 Spring 中,IoC 容器掌握着主动权,调用者则变成了被动的一方,被动的等待 IoC 容器创建它所需要的对象(Spring Bean)。

    这个过程在职责层面发生了控制权的反转,把原本调用者通过代码实现的对象的创建,反转给 IoC 容器来帮忙实现,因此我们将这个过程称为 Spring 的 “控制反转”。

2. IoC 的工作原理

    在 Java 软件开发过程中,系统中的各个对象之间、各个模块之间、软件系统和硬件系统之间,或多或少都存在一定的耦合关系。

    若一个系统的耦合度过高,那么就会造成难以维护的问题,但完全没有耦合的代码几乎无法完成任何工作,这是由于几乎所有的功能都需要代码之间相互协作、相互依赖才能完成。
    
    因此在程序设计时,所秉承的思想一般都是在不影响系统功能的前提下,最大限度的降低耦合度。

    IoC 底层通过工厂模式、Java 反射机制、XML 解析等技术,将代码的耦合度降低到最低限度,其主要步骤如下:
        
        1) 在配置文件(例如 spring-beans.xml)中,对各个对象以及它们之间的依赖关系进行配置;
        2) 可以把 IoC 容器当做一个工厂,这个工厂的产品就是 Spring Bean;
        3) 容器启动时会加载并解析配置文件,得到对象的基本信息以及它们之间的依赖关系;
        4) IoC 利用 Java 的反射机制,根据类名生成相应的对象(即 Spring Bean),并根据依赖关系将这个对象注入到依赖它的对象中。

    由于对象的基本信息、对象之间的依赖关系都是在配置文件中定义的,并没有在代码中紧密耦合,因此即使对象发生改变,我们也只需要在配置文件中进行修改即可,而无须对 Java 代码进行修改,这就是 Spring IoC 实现解耦的原理。

3. IoC 容器

    IoC 思想是基于 IoC 容器实现的,IoC 容器是 Spring 框架中最重要的核心组件之一,它贯穿了 Spring 从诞生到成长的整个过程。

    IOC 容器具有依赖注入功能的容器,它可以创建对象,IOC 容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。通常 new 一个实例,控制权由程序员控制,而 "控制反转" 是指 new 实例工作不由程序员来做而是交给 Spring 容器来做。

    Spring 框架为我们提供了两种不同类型 IoC 容器,它们分别是 BeanFactory 和 ApplicationContext。

    1) BeanFactory 容器

        BeanFactory 是 IoC 容器的基本实现,也是 Spring 提供的最简单的 IoC 容器,它提供了 IoC 容器最基本的功能,由 org.springframework.beans.factory.BeanFactory 接口定义。

        BeanFactory 采用懒加载(lazy-load)机制,容器在加载配置文件时并不会立刻创建 Java 对象,只有程序中获取(使用)这个对象时才会创建。

        示例:

 1     package com.example;
 2 
 3     import org.springframework.context.BeanFactory;
 4     import org.springframework.context.support.ClassPathXmlApplicationContext;
 5 
 6     public class App {
 7         public static void main(String[] args) {
 8 
 9            BeanFactory context1 = new ClassPathXmlApplicationContext("spring-beans.xml");
10            Test01 obj1 = context1.getBean("Test01", Test01.class);
11 obj1.getMessage(); 12 } 13 }

 

        *注:示例代码对应的 Spring 版本是 4.3.9.RELEASE,在 spring 4.0 之后不在支持使用 XmlBeanFactory 创建 factory 加载配置文件。HelloWorld 和 spring-beans.xml 参考 “Spring基础知识(2)- 创建 Spring 程序”  里创建的 SpringBasic 程序。

    2) ApplicationContext 容器

        ApplicationContext 是 BeanFactory 接口的子接口,是对 BeanFactory 的扩展。ApplicationContext 在 BeanFactory 的基础上增加了许多企业级的功能,例如 AOP(面向切面编程)、国际化、事务支持等。

        最常被使用的 ApplicationContext 接口实现:

            实现类                                        描述
            ClassPathXmlApplicationContext        在类路径 ClassPath 下加载配置文件中已被定义的 bean。
            FileSystemXmlApplicationContext       在指定的文件系统路径中加载配置文件中已被定义的 bean。
            WebXmlApplicationContext              在 Web 应用程序的范围内加载配置文件中已被定义的 bean。

        示例:

 1    package com.example;
 2 
 3    import org.springframework.context.ApplicationContext;
 4    import org.springframework.context.support.ClassPathXmlApplicationContext;
 5    import org.springframework.context.support.FileSystemXmlApplicationContext;
 6 
 7    public class App {
 8        public static void main(String[] args) {
 9 
10            ApplicationContext context1 = new ClassPathXmlApplicationContext("spring-beans.xml");
11            Test01 obj1 = context1.getBean("Test01", Test01.class);
12 obj1.getMessage(); 13 14 ApplicationContext context2 = new FileSystemXmlApplicationContext("d:\\Temp\\spring-beans.xml"); 15 Test01 obj2 = context2.getBean("Test01", Test01.class);
16 obj2.getMessage(); 17 } 18 }


        *注:在 Win10 下测试 FileSystemXmlApplicationContext() 加载手动放置的配置文件 d:\\Temp\\spring-beans.xml 成功。


4. Spring 配置文件

    Spring 配置文件是 Java 资源文件的一种,遵循 Java 资源文件的管理方式。

    Maven 项目,代码文件放在 src/main/java 路径下,资源文件放在 src/main/resources 路径下,打包 jar 或 war 包时,class文件存放在 target/classes 目录下,resource 资源下的文件会拷贝一份到 target/classes 目录 (classpath) 下。

    这里默认 src/main/resources 是 Spring 配置文件的存放路径。

 

    1) Spring 配置文件格式

        (1) Properties 文件格式。
            
            Properties 配置文件主要以 key-value 键值对的形式存在,只能赋值,不能进行其他操作,适用于简单的属性配置。

        (2) XML 文件格式

            XML 配置文件采用树形结构,结构清晰,相较于 Properties 文件更加灵活。但是 XML 配置比较繁琐,适用于大型的复杂的项目。


    2) Beans 配置文件(主配置文件)

        以上文中的 spring-beans.xml 为例,内容如下:

 1      <?xml version="1.0" encoding="UTF-8"?>
 2      <beans xmlns="http://www.springframework.org/schema/beans"
 3             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4             xmlns:context="http://www.springframework.org/schema/context"
 5             xsi:schemaLocation="http://www.springframework.org/schema/beans
 6                                http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
 7                                http://www.springframework.org/schema/context
 8                                http://www.springframework.org/schema/context/spring-context-4.0.xsd">
 9 
10           <bean id="Test01" class="com.example.Test01">
11               <property name="message" value="Test01 Hello World!" />
12           </bean>
13 
14      </beans>


        (1) beans 标签

属性 描述
xmlns 声明 XML 文件默认的命名空间,表示未使用其他命名空间的所有标签的默认命名空间。
xmlns:xsi 声明 XML Schema 实例,声明后就可以使用 schemaLocation 属性。
xmlns:context 声明 context 命名空间,声明后就可以使用 context:component-scan 等标签。
xsi:schemaLocation 指定 Schema 的位置这个属性必须结合命名空间使用。这个属性有两个值,第一个值表示需要使用的命名空间。第二个值表示供命名空间使用的XML schema 的位置。


    (2) bean 标签

属性 描述
id Bean 的唯一标识符,id 的值必须以字母开始,可以使用字母、数字、下划线等符号。
class Bean 的具体实现类,它必须是一个完整的类名,即类的全限定名。
name Bean 的名称,我们可以通过 name 属性为同一个 Bean 同时指定多个名称,每个名称之间用逗号或分号隔开。
scope Bean 的作用域,可选值:singleton(默认值)、prototype、request、session 和 global Session。
init-method Bean 的初始化方法,容器加载 Bean 时调用。
destroy-method Bean 的清理方法,容器删除 Bean 时调用,只在 scope 是 singleton 时有效。
lazy-init 懒加载,容器在首次请求时才会创建 Bean 实例(值为 true时),只在 scope 是 singleton 时有效。

 

子标签 描述
property 用于调用 Bean 实例中的 setter 方法对属性进行赋值,从而完成属性的注入。
constructor-arg 通过该元素将构造参数传入,以实现 Bean 的实例化。


        (3) property 标签

  属性 描述
name 用于指定 Bean 实例中相应的属性名。
ref 用于指定对某个 Bean 实例的引用,即 <bean> 元素中的 id 或 name 属性。
value 字符串或字符串数值。

 

    3) 其它配置文件

        ApplicationContext 容器使用 ClassPathXmlApplicationContext 类的构造函数读取 Beans 配置文件(主配置文件,spring-beans.xml),那如何读取其它配置文件? 比如 config.properties。

        Properties 文件 config.properties,内容如下:

            message=hello spring


        (1) 使用 class.getClassLoader().getResourceAsStream(String name) 读取

            默认从 classpath 找文件,name 不能带 "/",否则会抛空指针。相对路径 "/" 相当于当前进程的根目录,即项目根目录。

            示例:

 1         package com.example;
 2 
 3         import java.io.InputStream;
 4         import java.util.Properties;
 5 
 6         public class App {
 7              public static void main( String[] args ) {
 8 
 9                   try {
10 
11                        InputStream in = App.class.getClassLoader().getResourceAsStream("config.properties");
12                        Properties properties = new Properties();
13                        properties.load(in);
14                        System.out.println("message: " + properties.getProperty("message"));
15                   } catch (IOException e) {
16                        //e.printStackTrace();
17                   }
18              }
19         }


        (2) 使用 class.getResourceAsStream(String name) 读取

            class.getResourceAsStream(String name) 是使用绝对路径,绝对路径是相对于 classpath 根目录的路径,"/" 就代表着 classpath,所以 name 属性前面加上 "/"。

            示例:

 1          package com.example;
 2 
 3          import java.io.InputStream;
 4          import java.util.Properties;
 5 
 6          public class App {
 7               public static void main( String[] args ) {
 8 
 9                   try {
10 
11                       InputStream in = App.class.getResourceAsStream("/config.properties");
12                       Properties properties = new Properties();
13                       properties.load(in);
14                       System.out.println("message: " + properties.getProperty("message"));
15                   } catch (IOException e) {
16                       //e.printStackTrace();
17                   }
18               }
19          }


        (3)使用 Spring 配置方式读取

            可以在 Beans 配置文件中读取属性值,赋值类成员变量。
            
            修改 Beans 配置文件:

 1     <?xml version="1.0" encoding="UTF-8"?>
 2     <beans xmlns="http://www.springframework.org/schema/beans"
 3            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4            xmlns:context="http://www.springframework.org/schema/context"
 5            xsi:schemaLocation="http://www.springframework.org/schema/beans
 6                              http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
 7                              http://www.springframework.org/schema/context
 8                              http://www.springframework.org/schema/context/spring-context-4.0.xsd">
 9 
10         <context:property-placeholder location="classpath:config.properties" ignore-unresolvable="true"/>
11 
12         <bean id="Test01" class="com.example.Test01">
13             <property name="message" value="${message}" />
14         </bean>
15 
16     </beans>


            代码示例:

 1          package com.example;
 2 
 3          import org.springframework.context.ApplicationContext;
 4          import org.springframework.context.support.ClassPathXmlApplicationContext;
 5 
 6          public class App {
 7              public static void main(String[] args) {
 8 
 9                   ApplicationContext context1 = new ClassPathXmlApplicationContext("spring-beans.xml");
10                   Test01 obj1 = context1.getBean("Test01", Test01.class);
11 obj1.getMessage(); 12 } 13 } 14 15 class Test01 { 16 private String message; 17 18 public void setMessage(String message) { 19 this.message = message; 20 } 21 22 public void getMessage() { 23 System.out.println("Message: " + message); 24 } 25 }


        (4)使用 Spring 注解方式读取

            使用注解获取 properties 文件中的属性值。
  
            修改 Beans 配置文件:

 1     <?xml version="1.0" encoding="UTF-8"?>
 2     <beans xmlns="http://www.springframework.org/schema/beans"
 3       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4       xmlns:context="http://www.springframework.org/schema/context"
 5       xsi:schemaLocation="http://www.springframework.org/schema/beans
 6         http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
 7         http://www.springframework.org/schema/context
 8         http://www.springframework.org/schema/context/spring-context-4.0.xsd">
 9 
10       <context:component-scan base-package="com.example"/>
11       <context:property-placeholder location="classpath:config.properties" ignore-unresolvable="true"/>
12 
13   <!-- <bean id="Test01" class="com.example.Test01">
14         <property name="message" value="${message}" />
15       </bean> -->
16 
17     </beans>


       代码示例:

 1         package com.example;
 2 
 3         import org.springframework.stereotype.Component;
 4         import org.springframework.beans.factory.annotation.Value;
 5 
 6         import org.springframework.context.ApplicationContext;
 7         import org.springframework.context.support.ClassPathXmlApplicationContext;
 8 
 9         public class App {
10             public static void main(String[] args) {
11 
12                 ApplicationContext context1 = new ClassPathXmlApplicationContext("spring-beans.xml");
13                 Test02 obj2 = context1.getBean("Test02", Test02.class);
14 obj2.getMessage(); 15 } 16 } 17 18 @Component("Test02")
19 class Test02 { 20 @Value("${message}") 21 private String message; 22 23 public void setMessage(String message) { 24 this.message = message; 25 } 26 27 public void getMessage() { 28 System.out.println("Message: " + message); 29 } 30 }

 

posted @ 2022-03-05 17:26  垄山小站  阅读(126)  评论(0编辑  收藏  举报