写完了第一个Spring的程序,相信已经对spring已经有所了解了,那么我们这节来了解一下,IOC是如何创建对象,什么时候创建对象的。
Spring 提供了两种 IoC 容器,分别为 BeanFactory 和 ApplicationContext
我们先对两种进行介绍一下
BeanFactory 是基础类型的 IoC 容器,简单来说,BeanFactory 就是一个管理 Bean的工厂,它主要负责初始化各种 Bean,并调用它们的生命周期方法。
BeanFactory 接口有多个实现类,最常见的是 XmlBeanFactory类,它是根据 XML 配置文件中的定义装配 Bean 的。
创建 BeanFactory 实例时,需要提供 Spring 所管理容器的详细配置信息,这些信息通常采用 XML 文件形式管理。其加载配置信息的代码具体如下所示
BeanFactory beanFactory = new XmlBeanFactory(new FileSystemResource("D://applicationContext.xml"));
ApplicationContext 是 BeanFactory 的子接口,也被称为应用上下文,它不仅提供了 BeanFactory 的所有功能,还添加了对 i18n(国际化)、资源访问、事件传播等方面的良好支持。
ApplicationContext 接口有两个常用的实现类,具体如下。
1)ClassPathXmlApplicationContext(重点认识)
该类从类路径 ClassPath 中寻找指定的 XML 配置文件,找到并装载完成 ApplicationContext 的实例化工作,具体如下所示。
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(String configLocation);
2)FileSystemXmlApplicationContext(知道就行)
该类从指定的文件系统路径中寻找指定的 XML 配置文件,找到并装载完成 ApplicationContext 的实例化工作,具体如下所示。
ApplicationContext applicationContext = new FileSystemXmlApplicationContext(String configLocation);
在使用 Spring 框架时,可以通过实例化其中任何一个类创建 Spring 的 ApplicationContext 容器。
BeanFactory
BeanFactory在启动的时候不会去实例化Bean,中有从容器中拿Bean的时候才会去实例化;
ApplicationContext
ApplicationContext在启动的时候就把所有的Bean全部实例化了。
所以我们可以得知,对象在什么时候创建,我们使用的是ApplicationContext,所以在Spring启动的时候就已经把所有的Bean对象给创建好了。
先快后慢
应用启动的时候占用资源很少;对资源要求较高的应用,比较有优势;
先慢后快
1. 所有的Bean在启动的时候都加载,在后续的操作中系统运行的速度快;
2. 在启动的时候所有的Bean都加载了,我们就能在系统启动的时候,尽早的发现系统中的配置问题
(1)我们给实体类中加了一个无参构造方法、还有带一个参数的构造方法。
package com.kuang.pojo;
public class Hello {
private String str;
public Hello() {
System.out.println("这是一个无参构造!");
}
public Hello(String str) {
this.str = str;
System.out.println("这是一个带有一个参数的构造器!");
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
@Override
public String toString() {
return "Hello{" +
"str='" + str + '\'' +
'}';
}
}
(2)配置xml中的bean
<?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="hello" class="com.kuang.pojo.Hello">
<property name="str" value="Hello Spring!"/>
</bean>
</beans>
(3)编写业务层代码
package com.kuang.service;
import com.kuang.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class HelloService {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
Hello hello = context.getBean("hello", Hello.class);
System.out.println(hello);
}
}
运行之后,默认调用的是无参的构造方法
我们可以得到一个结论:
如果不做专门的配置,那么bean是通过无参构造来进行创建对象的
如果想要对实体类进行有参构造的创建怎么实现呢?
IOC创建有参构造器对象的三种方式
这三种方式同样,推荐大家一定要上spring的官方进行查看,说的非常清楚了。
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
</bean>
在文档中说明,通过index(从0开始),对对应位置的构造参数进行设置value,即可通过有参构造器构建对象
(1)写一个User类,中有四个构造函数,有参,一个构造参数…,
package com.kuang.pojo;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
@Getter
@Setter
@ToString
public class User {
private int id;
private String userName;
private String password;
public User() {
System.out.println("无参构造进行创建对象!");
}
public User(int id) {
this.id = id;
System.out.println("一个参数构造的进行创建对象");
}
public User(int id, String userName) {
this.id = id;
this.userName = userName;
System.out.println("两个参数构造进行创建对象");
}
public User(int id, String userName, String password) {
this.id = id;
this.userName = userName;
this.password = password;
System.out.println("三个参数构造进行创建对象");
}
}
(2)xml文件通过下标的方式配置bean,只设置了一个参数
<?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="user" class="com.kuang.pojo.User">
<constructor-arg index="0" value="1"/>
</bean>
</beans>
(3)然后通过ApplicationContext启动Spring容器
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
User user = context.getBean("user",User.class);
}
(4)运行结果
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="java.lang.String" value="42"/>
</bean>
在文档中说明,通过type(引用类型要写全限定名),对对应类型的构造参数进行设置value,即可通过有参构造器构建对象
有一个问题,如果多个构造参数都是同一个类型呢?
答:会根据标签的顺序对同一类型的参数进行从前到后赋值。
(1)前面的User类不变
(2)通过类型配置bean创建对象
<?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="user" class="com.kuang.pojo.User">
<constructor-arg type="int" value="1"/>
<constructor-arg type="java.lang.String" value="userName"/>
<constructor-arg type="java.lang.String" value="password"/>
</bean>
</beans>
(3)启动Spring,如上
(4)查看运行结果
<beans>
<bean id="thingOne" class="x.y.ThingOne">
<constructor-arg ref="thingTwo"/>
<constructor-arg ref="thingThree"/>
</bean>
<bean id="thingTwo" class="x.y.ThingTwo"/>
<bean id="thingThree" class="x.y.ThingThree"/>
</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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.kuang.pojo.User">
<constructor-arg name="id" value="1"/>
<constructor-arg name="userName" value="root"/>
<constructor-arg name="password" value="123456"/>
</bean>
</beans>
查看运行结果
(1)编写实体类User
package com.kuang.pojo;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class User {
private int id;
private String userName;
private String password;
}
(2)在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">
<bean id="user" class="com.kuang.pojo.User"/>
</beans>
(3)根据同一个bean取出多个对象
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
User user = context.getBean("user",User.class);
User user2 = context.getBean("user",User.class);
System.out.println(user==user2);
}
(4)运行结果
结论: IOC默认创建对象都是单例模式的,一个类只能拿到一个实例