spring应用手册-IOC(XML配置实现)第一部分

758 阅读6分钟

1、IOC(XML配置实现)

1.1IOC介绍

IoC 也称为依赖注入(DI)。它是一个 process,其中 objects 仅通过构造函数 arguments,工厂方法的 arguments 或者属性的 properties 来定义它们的依赖项(即,它们使用的其他 objects)。在构造或从工厂方法返回后,在 object 实例上设置。然后容器在创建 bean 时注入这些依赖项。这个 process 基本上是 bean 本身控制实例化的逆(因此 name,控制反转)或者通过使用 classes 的直接构造或诸如 Service Locator pattern 之类的机制来确定其依赖关系的位置。

1587193951021.png

1.2 spring的helloworld应用

[1]准备

创建项目:spring-st

添加依赖:

 <dependencies>
     <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-context</artifactId>
         <version>5.1.3.RELEASE</version>
     </dependency>
     <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>4.12</version>
         <scope>test</scope>
     </dependency>
 </dependencies>

添加AccountDAO类:

 package com.boxuewa.dk.demo1.dao;
 ​
 /**
  * @author 戴着假发的程序员
  * @description
  */
 public class AccountDAO {
     public int save(String name){
         System.out.println("AccountDAO-save->保存账户:"+name);
         return 1;
     }
 }

添加AccountService类:

 package com.boxuewa.dk.demo1.service;
 ​
 import com.boxuewa.dk.demo1.dao.AccountDAO;
 ​
 /**
  * @author 戴着假发的程序员
  *  
  * @description
  */
 public class AccountService {
     private AccountDAO accountDAO;
     public void setAccountDAO(AccountDAO accountDAO) {
         this.accountDAO = accountDAO;
     }
     public int save(String name){
         System.out.println("AccountService-save->保存用户:"+name);
         return accountDAO.save(name);
     }
 }

AccountService中依赖了AccountDAO,提供setAccountDAO方法,spring会通过这个方法注入accountDAO对象。 添加spring配置文件,并且注册AccountService和AccountDAO

 <?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">
     <!-- 注册accountDAO -->
     <bean id="accountDAO" class="com.boxuewa.dk.demo1.dao.AccountDAO">
     </bean>
     <!-- 注册accountService -->
     <bean id="accountService" class="com.boxuewa.dk.demo1.service.AccountService">
         <!-- 给accountService注入属性accountDAO -->
         <property name="accountDAO" ref="accountDAO"/>
     </bean>
 </beans>

项目整体结构如下:

1585717789619.png 添加测试类,创建spring容器进行测试:

 /**
  * @author 戴着假发的程序员
  *  
  * @description
  */
 public class SpringTest1 {
     @Test
     public void testSpringHellowrod(){
         //创建spring容器
         ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
         AccountService bean = ac.getBean(AccountService.class);
         bean.save("卡卡西");
     }
 }

测试结果:

1585717847290.png

1.3Helloword程序解读

[1]概述

spring是一个对象工厂(容器),我可以将我们的编写的类交给spring管理,spring最终会将我们的类创建好对象存在一个map缓存中。并且为每一个对象设置一个对应的key。 我们可以通过spring工厂提供的api(getBean)获取spring为我们创建的对象。

[2]配置文件

spring的配置文件的根节点是其中的namespace和schemaLocation建议直接从文档上复制。

其中的bean标签就是配置或者叫注册我们自己的class。

id属性就是我们希望的spring缓存对象的key,class标签配置我们的类的全限定类名。一个bean标签就是给spring容器中注册了一个class。 当然如果我们没有指定id属性,spring会给一个默认的id。

注意:id必须是唯一的,绝对不能重复出现。

property是注入属性的配置,我们上面的配置中,就是通知spring帮我们注入属性accountDAO属性。name就是属性的名称(这里注意要遵循javaBean规范)。ref就是要注入的其他对象的引用(id)。

[3]spring容器创建

ApplicationContext是集合和各种功能的spring工厂之一,我们创建工厂时使用的ClassPathXmlApplicationContext。将我们的配置文件的名称传入工厂。和ClassPathXmlApplicationContext为孪生兄弟的FileSystemXmlApplicationContext也可以创建spring工厂对象。区别在于ClassPathXmlApplicationContext是读取classPath下的配置文件,而FileSystemXmlApplicationContext是加载操作系统中的其他配置文件。

ClassPathXmlApplicationContext的构造参数可以传入多个配置文件,例如:

 new ClassPathXmlApplicationContext("applicationContext-dao.xml","applicationContext-service.xml");

或者

 new ClassPathXmlApplicationContext(new String[]{"applicationContext-dao.xml","applicationContext-service.xml"});

当然这就要求你有多个配置文件:

1585718689350.png 每个配置文件中配置一部分bean:

applicationContext-dao.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
         http://www.springframework.org/schema/beans/spring-beans.xsd">
     <!-- 注册accountDAO -->
     <bean id="accountDAO" class="com.boxuewa.dk.demo1.dao.AccountDAO">
     </bean>
 </beans>

applicationContext-service.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
         http://www.springframework.org/schema/beans/spring-beans.xsd">
     <!-- 注册accountService -->
     <bean id="accountService" class="com.boxuewa.dk.demo1.service.AccountService">
         <!-- 给accountService注入属性accountDAO -->
         <property name="accountDAO" ref="accountDAO"/>
     </bean>
 </beans>

这样作的目的就是方便我们分类管理这些bean的配置。

当然你也可以使用通配符“*”的方式进行配置文件的加载:

 new ClassPathXmlApplicationContext("applicationContext-*.xml");

[4]从spring容器中获取springBean的API

常用的有三种方式:

方式1:通过id获取springBean对象

 AccountService bean = (AccountService) ac.getBean("accountService");

这种方式获取的springBean对象是Object类型的,取出后需要类型转换。

方式2:按照类型获取

 AccountService bean = ac.getBean(AccountService.class);

这种方式取出的对象就是类型安全的,但是这种方式一定要确保整个spring容器中指定类型的bean只有一个存在,如果有多个就会报错。

方式3:同时按照类型和id获取

 AccountService bean = ac.getBean("accountService",AccountService.class);

这种方式可以类型安全的获取到我们指定id的springBean对象。往往适用与同一个类型在spring容器中有多个bean对象的情况。

1.4 import引入其他配置文件

我们可以通过import在一个配置文件中引入其他的配置文件。 例如:

 <?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">
     <import resource="applicationContext-service.xml"/>
     <import resource="applicationContext-dao.xml"/>
     <bean id="accountDAO_1" class="com.boxuewa.dk.demo1.dao.AccountDAO"/>
 </beans>

这时我们就可以这样创建容器了:

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

1.5 springBean的加载流程概述

Spring 作为 Ioc 框架,实现了依赖注入,由一个中心化的 Bean 工厂来负责各个 Bean 的实例化和依赖管理。各个 Bean 可以不需要关心各自的复杂的创建过程,达到了很好的解耦效果。

springBean的加载过程大致分为两个过程:解析注册,实例化

1585721755288.png spring先解析xml文件或者注解配置,读取所有要加载类信息。根据类信息创建对应的BeanDefinition对象,再根据Beandefination对象创建实例对象。

BeanDefinition是SpringBean的描述对象,主要封装了如下信息:

1585722000012.png 其中需要我们了解的属性,我们会在后面的解释中慢慢了解。

1.6 bean标签中的id属性

id属性在helloworld程序中已经做过解释,这里简单解释一下。

id属性

1585722535066.png spring会把每一个配置的类都翻译成BeanDefinition,存储在缓存中,这个缓存是一个map,存储对应的BeanDefinition的可以用的就是这里配置的ID,所以我们配置的所有bean的id是不能重复的。

当然id属性也不是必须的,如果我们不配置id,spring或默认生成一个id。一般默认值就是全限定类名#0。例如:com.boxuewa.dk.demo1.dao.AccountDAO#0。

1.7 bean标签中的name属性

name属性是给bean设置别名的。 我们通过spring的getBean获取bean对象时,可以通过id,同样也可以通过别名。

name的配置方式有如下几种:

 name="aserver,a@service,a+service"
 <!-- 注册accountDAO -->
 <bean id="accountDAO" name="adao,adao1,@adao,a+adao" class="com.dk.demo1.dao.AccountDAO">
 </bean>

可以使用“,”隔开同时配置多个,而且可以使用特殊符号。

当然你使用空格隔开,效果也是一样的

 <!-- 注册accountService -->
 <bean id="accountService" name="aservice a_service" class="com.dk.demo1.service.AccountService">
     <!-- 给accountService注入属性accountDAO -->
     <property name="accountDAO" ref="accountDAO"/>
 </bean>

我们可以通过别名获取bean:

 AccountService bean = (AccountService) ac.getBean("a@service");

id和name的区别:

id是唯一的,不能有特殊符号

name可以有多个,可以有特殊符号。

所有的别名最终会在beanFactory中使用map和id对应起来:

1587203017970.png

1.8 bean中的scop属性

scop属性用于指定bean的作用域。可以取一下几个值:

   singleton:单例模式(默认);    prototype:多例模式;    request:作用于web应用的请求范围;    session:作用于web应用的会话范围    global-session:作用于集群环境的会话范围;

其中使用比较多的是singleton,这个也是默认值。

spring在容器创建的同时就会创建所有scop为singleton的对象,我们从容器中获取同一个singleton对象无论多少次,获取的都是同一个对象。

 <!-- 注册accountService -->
 <bean id="accountService" scope="singleton" class="com.dk.demo1.service.AccountService">
     <!-- 给accountService注入属性accountDAO -->
     <property name="accountDAO" ref="accountDAO"/>
 </bean>

测试:

//创建spring容器
ApplicationContext ac =
        new ClassPathXmlApplicationContext("applicationContext.xml");
AccountService bean1 = (AccountService) ac.getBean("accountService");
AccountService bean2 = (AccountService) ac.getBean("accountService");
bean.save("bean1==bean2-->"+(bean1==bean2));

1587203410474.png 如果scop配置为prototype,那么spring容器初始化时,不会创建该对象,每次从容器中获取该对象时都会创建一个新的对象返回:

 <!-- 注册accountService -->
 <bean id="accountService" scope="prototype" class="com.dk.demo1.service.AccountService">
     <!-- 给accountService注入属性accountDAO -->
     <property name="accountDAO" ref="accountDAO"/>
 </bean>

1587203436234.png

未完待续........