1、IOC(XML配置实现)
1.1IOC介绍
IoC 也称为依赖注入(DI)。它是一个 process,其中 objects 仅通过构造函数 arguments,工厂方法的 arguments 或者属性的 properties 来定义它们的依赖项(即,它们使用的其他 objects)。在构造或从工厂方法返回后,在 object 实例上设置。然后容器在创建 bean 时注入这些依赖项。这个 process 基本上是 bean 本身控制实例化的逆(因此 name,控制反转)或者通过使用 classes 的直接构造或诸如 Service Locator pattern 之类的机制来确定其依赖关系的位置。
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>
项目整体结构如下:
添加测试类,创建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("卡卡西");
}
}
测试结果:
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"});
当然这就要求你有多个配置文件:
每个配置文件中配置一部分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的加载过程大致分为两个过程:解析注册,实例化
spring先解析xml文件或者注解配置,读取所有要加载类信息。根据类信息创建对应的BeanDefinition对象,再根据Beandefination对象创建实例对象。
BeanDefinition是SpringBean的描述对象,主要封装了如下信息:
其中需要我们了解的属性,我们会在后面的解释中慢慢了解。
1.6 bean标签中的id属性
id属性在helloworld程序中已经做过解释,这里简单解释一下。
id属性
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对应起来:
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));
如果scop配置为prototype,那么spring容器初始化时,不会创建该对象,每次从容器中获取该对象时都会创建一个新的对象返回:
<!-- 注册accountService -->
<bean id="accountService" scope="prototype" class="com.dk.demo1.service.AccountService">
<!-- 给accountService注入属性accountDAO -->
<property name="accountDAO" ref="accountDAO"/>
</bean>
未完待续........