1、环境搭建
导入spring使用最基本的坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
在resources下创建一个applicationContext.xml文件,配置所需对象的ioc 。
通常一个类对应一个bean标签,指定【唯一id标识】和【全类名】。
<?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">
<!--将创建某个service对象的控制权交给框架-->
<bean id="accountService" class="com.service.impl.AccountServiceImpl"/>
</beans>
一旦配置了ioc,就会将对应的对象存入ioc容器中。ioc是一个键值对结构的容器,key值就是唯一id标识,value值就是通过全类名反射创建的对象。所以,通过唯一标识就可以定位到对应的对象。
底层创建Bean对象的三种设计方式
- 第一种:【使用默认构造函数创建】。在spring的配置文件中,使用bean标签,且除了id和class属性外没有其他属性时,使用的就是该种方式。此时如果Bean类中没有默认构造函数,将无法创建对象。(基本上每个类都会有默认的构造方法)
- 第二种:【根据某个类中的方法来获取返回值对象】,比如在某个A类中有一个方法,该方法会返回一个B类对象,如何获取B类对象?可以通过id创建A类对象再调用方法获取B类对象。但是如果想要直接通过id获取B类对象呢?要进行如下配置:
<!--配置通过某个类中的方法获取对象-->
<bean id="nameA" class="cao.zhanpeng.factory.FactoryDemo" />
<bean id="accountService" factory-bean="nameA" factory-method="getAccountService"/>
- 第三种:使用某个类中的静态方法来创建对象
<!--配置通过某个类中的静态方法获取对象-->
<bean id="accountService" class="com.factory.FactoryDemo" factory-method="getAccountService"/>
bean对象的作用范围
bean标签默认是配置使用【单例模式】创建bean对象的。可以通过scope属性来调整bean对象的作用范围,该属性有5种取值,常用的是前两种:
- singleton,默认值,表示单例的。
- prototype,多例模式。
- request,作用于web应用的请求范围。
- session,作用于web应用的会话范围。
- global-session,作用于集群环境的会话范围(全局会话范围),当不是集群环境时,和session一样。
bean对象的生命周期
单例对象
- 出生:容器创建时出生
- 存活:容器在,对象在
- 死亡:容器销毁(容器实现类对象.close()),对象销毁。
多例对象
- 出生:使用对象时出生
- 存活:对象只要在使用过程中就一直存活
- 死亡:spring无法识别是否要使用对象,只有当对象长时间不用,且没有别的对象引用时,由java垃圾回收器回收。
2、获取ioc中的对象
先获取ioc容器,再根据唯一id定位到相应的对象。
//获取核心容器对象ioc
ApplicationContext ca = new ClassPathXmlApplicationContext("applicationContext.xml");
//根据id获取对象的第一种方式,返回的是一个Object对象,需要强转一下
AccountService accountService1 = (AccountService) ca.getBean("accountService");
System.out.println(accountService1);//com.service.impl.AccountServiceImpl@6f45df59
//根据id获取对象的第二种方式,不需要强转
AccountService accountService2 = ca.getBean("accountService", AccountService.class);
System.out.println(accountService2);//com.service.impl.AccountServiceImpl@6f45df59
ApplicationContext对象的实现类
常用的有三个:
- ClassPathXmlApplicationContext,可以加载类路径下的配置文件,用得较多。
- FileSystemXmlApplicationContext,可以加载磁盘任意路径下的配置文件(前提是有访问权限),传递的是文件路径。
- AnnotationConfigApplicationContext,用于读取注解创建容器的。
ApplicationContext接口和BeanFactory接口的区别
- ApplicationContext接口是BeanFactory接口的子类接口
- ApplicationContext对象在创建核心容器时,采用的是立即加载的方式,只要一读取完配置文件,马上就创建文件中配置的对象。单例对象适用。用得较多。
- BeanFactory采取的是延迟加载的方式,什么时候根据id获取对象了,什么时候才真正地创建。多例对象适用。
- spring会通过识别单例还是多例来选择是立即加载还是延迟加载。单例就是立即加载;多例就是延迟加载。
3、依赖注入
构造函数注入
通过构造函数注入其实就是底层通过构造函数来给成员变量赋值。使用的是bean标签下的constructor-arg标签,该标签有5个属性
- 三个用来确定是哪一个参数的,一次只能存在一种
- 通过类型确定参数type,比如=java.lang.String,这种方式在有多个同类型参数时无法进行区分。
- 通过索引来确定参数index,索引从0开始,这种方式也不太灵活。
- 通过参数名称来确定参数name,这种方式可以唯一确定且更灵活。
- 一个用来为基本类型和String类型注入值的属性value,虽然配置的属性值都是字符串,但是spring可以将基本类型的字符串自动转成对应的基本类型。
- 一个用来引用Bean对象类型的属性ref,值=配置过的Bean对象的唯一id值。
<!--配置依赖注入-->
<bean id="accountService" class="cao.zhanpeng.service.impl.AccountServiceImpl">
<constructor-arg name="username" value="张三"></constructor-arg>
<constructor-arg name="age" value="25"></constructor-arg>
<constructor-arg name="birthday" ref="now"></constructor-arg>
</bean>
<!--配置日期对象的引用-->
<bean id="now" class="java.util.Date"></bean>
在创建bean对象时,注入数据是必须的操作,否则无法创建对象。
通过构造函数来注入有一个弊端,就是如果参数列表中有不需要的数据,也得注入。
set方法注入
相当于使用set方法为成员变量赋值。类中需要有对应变量的set方法(get方法随意)使用的是bean标签下的property标签,该标签有三个属性:
- name,指定对应set方法的属性名。
- value,同上。
- ref,同上。
<!--配置set方法依赖注入-->
<bean id="accountService" class="cao.zhanpeng.service.impl.AccountServiceImpl">
<property name="username" value="张三"></property>
<property name="age" value="25"></property>
<property name="birthday" ref="now"></property>
</bean>
<!--配置日期对象的引用-->
<bean id="now" class="java.util.Date"></bean>
注入复杂类型数据
数组,可以看做是单列集合
单列集合
- List
- Set
双列集合
- Map
- Properties
<!--配置set方法对复杂类型进行依赖注入-->
<bean id="accountService" class="com.service.impl.AccountServiceImpl">
<!--数组-->
<property name="str">
<array>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</array>
</property>
<!--List集合-->
<property name="list">
<list>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</list>
</property>
<!--Set集合-->
<property name="set">
<set>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</set>
</property>
<!--Map集合-->
<property name="map">
<map>
<entry key="aaa" value="AAA"></entry>
<entry key="bbb">
<value>BBB</value>
</entry>
</map>
</property>
<!--properties集合-->
<property name="prop">
<props>
<prop key="aaa">AAA</prop>
<prop key="bbb">BBB</prop>
</props>
</property>
</bean>
注意
- 数组、List集合和Set集合的标签是可以通用的。
- 双列集合之间的标签也是可以通用的,但是要注意map对应entry,props对应prop。
- entry键值对有两种写法。