?作者簡介:2022年博客新星 第八。熱愛國學(xué)的Java后端開發(fā)者,修心和技術(shù)同步精進(jìn)。
??個(gè)人主頁:Java Fans的博客
??個(gè)人信條:不遷怒,不貳過。小知識(shí),大智慧。
??當(dāng)前專欄:SSM 框架從入門到精通
?特色專欄:國學(xué)周更-心性養(yǎng)成之路
??本文內(nèi)容:一文吃透 Spring 中的IOC和DI
Spring 中 IOC 和 DI
??IoC 容器是 Spring 的核心,也可以稱為 Spring 容器。Spring 通過 IoC 容器來管理對象的實(shí)例化和初始化,以及對象從創(chuàng)建到銷毀的整個(gè)生命周期。
??Spring 中使用的對象都由 IoC 容器管理,不需要我們手動(dòng)使用 new 運(yùn)算符創(chuàng)建對象。由 IoC 容器管理的對象稱為 Spring Bean,Spring Bean 就是 Java 對象,和使用 new 運(yùn)算符創(chuàng)建的對象沒有區(qū)別。
??Spring 通過讀取 XML 或 Java 注解中的信息來獲取哪些對象需要實(shí)例化。Spring 提供 2 種不同類型的 IoC 容器,即 BeanFactory 和 ApplicationContext 容器
1. BeanFactory 容器
??BeanFactory 是最簡單的容器,由 org.springframework.beans.factory.BeanFactory 接口定義,采用懶加載(lazy-load),所以容器啟動(dòng)比較快。BeanFactory 提供了容器最基本的功能,配置文件加載時(shí)不會(huì)創(chuàng)建對象,在獲取bean時(shí)才會(huì)創(chuàng)建對象
??為了能夠兼容 Spring 集成的第三方框架(如 BeanFactoryAware、InitializingBean、DisposableBean),所以目前仍然保留了該接口。簡單來說,BeanFactory 就是一個(gè)管理 Bean 的工廠,它主要負(fù)責(zé)初始化各種 Bean,并調(diào)用它們的生命周期方法。BeanFactory 接口有多個(gè)實(shí)現(xiàn)類 org.springframework.beans.factory.xml.XmlBeanFactory最常見
??使用 BeanFactory 需要?jiǎng)?chuàng)建 XmlBeanFactory 類的實(shí)例,通過 XmlBeanFactory 類的構(gòu)造函數(shù)來傳遞 Resource 對象。如下所示。
Resource resource = new ClassPathResource("applicationContext.xml");
BeanFactory factory = new XmlBeanFactory(resource);
2. ApplicationContext 容器
??ApplicationContext 繼承了 BeanFactory 接口,由 org.springframework.context.ApplicationContext 接口定義,對象在啟動(dòng)容器時(shí)加載。ApplicationContext 在 BeanFactory 的基礎(chǔ)上增加了很多企業(yè)級(jí)功能,例如 AOP、國際化、事件支持等。
ApplicationContext 接口有兩個(gè)常用的實(shí)現(xiàn)類,具體如下。
【1】ClassPathXmlApplicationContext
??該類從類路徑 ClassPath 中尋找指定的 XML 配置文件,并完成 ApplicationContext 的實(shí)例化工作,具體如下所示。
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(String configLocation);
配置文件加載,則創(chuàng)建對象
??在上述代碼中,configLocation 參數(shù)用于指定 Spring 配置文件的名稱和位置,如 Beans.xml。
【2】FileSystemXmlApplicationContext
??該類從指定的文件系統(tǒng)路徑中尋找指定的 XML 配置文件,并完成 ApplicationContext 的實(shí)例化工作,具體如下所示。
ApplicationContext applicationContext = new FileSystemXmlApplicationContext(String configLocation);
??二者的主要區(qū)別在于,如果 Bean 的某一個(gè)屬性沒有注入,使用 BeanFacotry 加載后,第一次調(diào)用 getBean() 方法時(shí)會(huì)拋出異常,而 ApplicationContext 則會(huì)在初始化時(shí)自檢,這樣有利于檢查所依賴的屬性是否注入。
??因此,在實(shí)際開發(fā)中,通常都選擇使用 ApplicationContext,只有在系統(tǒng)資源較少時(shí),才考慮使用 BeanFactory。
【3】spring容器加載多個(gè)配置文件
- 使用字符串參數(shù),逗號(hào)分隔
//加載spring的配置文件 啟動(dòng)spring容器
ApplicationContext ac = new ClassPathXmlApplicationContext("config/student.xml","config/springConfig.xml");
- 使用字符串?dāng)?shù)組
String[] config = {"config/student.xml","config/springConfig.xml"};
//加載spring的配置文件 啟動(dòng)spring容器
ApplicationContext ac = new ClassPathXmlApplicationContext(config);
- 使用導(dǎo)入
<?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="student.xml"/>
<import resource="springConfig.xml"/>
</beans>
//加載spring的配置文件 啟動(dòng)spring容器
ApplicationContext ac = new ClassPathXmlApplicationContext("config/applicationContext.xml");
3. Spring Bean定義
??由 Spring IoC 容器管理的對象稱為 Bean,Bean 根據(jù) Spring 配置文件中的信息創(chuàng)建。
??可以把 Spring IoC 容器看作是一個(gè)大工廠,Bean 相當(dāng)于工廠的產(chǎn)品,如果希望這個(gè)大工廠生產(chǎn)和管理 Bean,則需要告訴容器需要哪些 Bean,以及需要哪種方式裝配 Bean。
Spring 配置文件支持兩種格式,即 XML 文件格式和 Properties 文件格式。
- Properties 配置文件主要以 key-value 鍵值對的形式存在,只能賦值,不能進(jìn)行其他操作,適用于簡單的屬性配置。
- XML 配置文件是樹形結(jié)構(gòu),相對于 Properties 文件來說更加靈活。XML 配置文件結(jié)構(gòu)清晰,但是內(nèi)容比較繁瑣,適用于大型復(fù)雜的項(xiàng)目。
??通常情況下,Spring 的配置文件使用 XML 格式。XML 配置文件的根元素是 ,該元素包含了多個(gè)子元素 。每一個(gè) 元素都定義了一個(gè) Bean,并描述了該 Bean 如何被裝配到 Spring 容器中 元素中可以包含很多屬性,其常用屬性如下表所示。
屬性名稱 | 描述 |
---|---|
id | Bean 的唯一標(biāo)識(shí)符,Spring 容器對 Bean 的配置和管理都通過該屬性完成。id 的值必須以字母開始,可以使用字母、數(shù)字、下劃線等符號(hào)。 |
name | name 屬性中可以為 Bean 指定多個(gè)名稱,每個(gè)名稱之間用逗號(hào)或分號(hào)隔開。Spring 容器可以通過 name 屬性配置和管理容器中的 Bean。 |
class | 該屬性指定了 Bean 的具體實(shí)現(xiàn)類,它必須是一個(gè)完整的類名,即類的全限定名。 |
scope | 用于設(shè)定 Bean 實(shí)例的作用域,屬性值可以為 singleton(單例)、prototype(原型)、request、session 和 global Session。其默認(rèn)值是 singleton |
constructor-arg | 元素的子元素,可以使用此元素傳入構(gòu)造參數(shù)進(jìn)行實(shí)例化。該元素的 index 屬性指定構(gòu)造參數(shù)的序號(hào)(從 0 開始),type 屬性指定構(gòu)造參數(shù)的類型 |
property | 元素的子元素,用于調(diào)用 Bean 實(shí)例中的 setter 方法來屬性賦值,從而完成依賴注入。該元素的 name 屬性用于指定 Bean 實(shí)例中相應(yīng)的屬性名 |
ref | 和 等元素的子元索,該元素中的 bean 屬性用于指定對某個(gè) Bean 實(shí)例的引用 |
value | 和 等元素的子元素,用于直接指定一個(gè)常量值 |
list | 用于封裝 List 或數(shù)組類型的依賴注入 |
set | 用于封裝 Set 類型的依賴注入 |
map | 用于封裝 Map 類型的依賴注入 |
entry | |
init-method | 容器加載 Bean 時(shí)調(diào)用該方法,類似于 Servlet 中的 init() 方法 |
destroy-method | 容器刪除 Bean 時(shí)調(diào)用該方法,類似于 Servlet 中的 destroy() 方法。該方法只在 scope=singleton 時(shí)有效 |
lazy-init | 懶加載,值為 true,容器在首次請求時(shí)才會(huì)創(chuàng)建 Bean 實(shí)例;值為 false,容器在啟動(dòng)時(shí)創(chuàng)建 Bean 實(shí)例。該方法只在 scope=singleton 時(shí)有效 |
4. IOC創(chuàng)建對象的方式
【1】無參構(gòu)造器創(chuàng)建對象 (默認(rèn))
【2】有參構(gòu)造創(chuàng)建對象
- 使用下標(biāo)傳遞參數(shù)
<!-- 使用索引匹配參數(shù)-->
<bean id="student" class="cn.kgc.spring.entity.Student">
<constructor-arg index="0" value="20"/>
<constructor-arg index="1" value="李四"/>
<constructor-arg index="2" value="20210814"/>
<constructor-arg index="3" value="2021/08/14"/>
</bean>
- 使用數(shù)據(jù)類型傳遞參數(shù)
<!--使用數(shù)據(jù)類型匹配參數(shù) 有相同的參數(shù)類型可配合索引一起使用-->
<bean id="student" class="cn.kgc.spring.entity.Student">
<constructor-arg type="int" value="20"/>
<constructor-arg type="java.lang.String" index="1" value="李四"/>
<constructor-arg type="java.lang.String" value="20210814"/>
<constructor-arg type="java.util.Date" value="2021/08/14"/>
</bean>
- 通過屬性名傳遞參數(shù)
<!--使用屬性名賦值-->
<bean id="student" class="cn.kgc.spring.entity.Student">
<constructor-arg name="age" value="20"/>
<constructor-arg name="name" value="李四"/>
<constructor-arg name="stuNo" value="20210814"/>
<constructor-arg name="birth" value="2021/08/14" />
</bean>
【3】創(chuàng)建對象時(shí)屬性的其它注入方式
- set注入
<bean id="studentService" class="cn.kgc.spring.service.StudentServiceImpl">
<!-- 屬性是引用類型 賦值時(shí)使用ref-->
<property name="studentDao" ref="studentDao"/>
<!-- 屬性是基本類型 String類型 Date類型 賦值時(shí)使用value -->
<property name="age" value="20"/>
<property name="stuName" value="張三"/>
<property name="price" value="20.4"/>
<property name="score" value="80.3"/>
<property name="birth" value="2021/8/13"/>
<property name="str" >
<array>
<value>張三</value>
<value>李四</value>
<value>王五</value>
</array>
</property>
<property name="lis">
<list>
<value>抽煙</value>
<value>喝酒</value>
<value>燙頭</value>
</list>
</property>
<!-- spring容器中組件默認(rèn)都是單例的 全局共享一個(gè)對象-->
<property name="lis2">
<list>
<ref bean="studentDao"></ref>
<ref bean="studentDao"></ref>
<ref bean="studentDao"></ref>
</list>
</property>
<property name="books">
<set>
<value>java</value>
<value>php</value>
<value>c#</value>
</set>
</property>
<property name="scores">
<map>
<entry key="math" value="89" ></entry>
<entry key="english" value="90" ></entry>
<entry key="java" value="80" ></entry>
</map>
</property>
<property name="map">
<map>
<entry key="01" value-ref="studentDao"></entry>
<entry key="02" value-ref="studentDao"></entry>
<entry key="03" value-ref="studentDao"></entry>
</map>
</property>
<property name="ps">
<props>
<prop key="driver">com.mysql.jdbc.Driver</prop>
<prop key="url">jdbc:mysql:///mybatis</prop>
<prop key="username">root</prop>
<prop key="password">rooot</prop>
</props>
</property>
</bean>
??使用set注入,每個(gè)屬性必須含有對應(yīng)的set方法,否則無法進(jìn)行屬性的注入
- Spring的依賴注入之p命名空間和c命名空間
??p命名空間是set注入的一種快捷實(shí)現(xiàn)方式,想要使用p命名空間注入,需要注意一下幾點(diǎn)。
- 實(shí)體類中必須有set方法;
- 實(shí)體類中必須有無參構(gòu)造器(默認(rèn)存在);
- 必須導(dǎo)入p命名空間注入方式依賴。
??xml依賴代碼:
xmlns:p="http://www.springframework.org/schema/p"
??導(dǎo)入后即可使用
<bean id="user" class="com.yd.pojo.User" p:age="18" p:name="老王"/>
<!--需要有屬性的set方法-->
<bean id="student" class="cn.kgc.spring.entity.Student" p:age="20" p:name="lisi" p:birth="2021/1/1" p:stuNo="20210814001"></bean>
??c命名空間是構(gòu)造器注入的一種快捷實(shí)現(xiàn)方式,想要使用c命名空間,需要注意一下幾點(diǎn)。
- 實(shí)體類中必須存在有參構(gòu)造器;
- 必須導(dǎo)入c命名空間注入方式依賴。
??xml依賴代碼:
xmlns:c="http://www.springframework.org/schema/c"
??導(dǎo)入后即可使用
<bean id="user2" class="com.yd.pojo.User" c:age="23" c:name="中王"/>
<!--需要有有參構(gòu)造方法-->
<bean id="student" class="cn.kgc.spring.entity.Student" c:age="30" c:name="王五" c:birth="1991/12/08" c:stuNo="20210814001"></bean>
類型轉(zhuǎn)換器的使用:
??作用:自定義注入?yún)?shù)和實(shí)體類中類型的匹配方式
import org.springframework.core.convert.converter.Converter;
public class MyConverter implements Converter<String, Date> {
@Override
public Date convert(String source) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
try {
Date parse = simpleDateFormat.parse(source);
return parse;
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
??xml文件配置:
<bean id="convert" class="cn.kgc.spring.basic.convert.MyConverter"></bean>
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="convert"></ref>
</set>
</property>
</bean>
5. Bean的自動(dòng)裝配
【1】autowire="byName"在容器的上下文中尋找與類中屬性對應(yīng)的set方法名字相同的id屬性值進(jìn)行裝配
<bean id="teacher" class="cn.kgc.spring.entity.Teacher">
<property name="name" value="李老師"/>
<property name="teaNo" value="001"/>
</bean>
<bean id="classRoom1" class="cn.kgc.spring.entity.ClassRoom">
<property name="address" value="學(xué)思樓1樓"/>
<property name="classNo" value="1"/>
</bean>
<bean id="student" class="cn.kgc.spring.entity.Student" autowire="byName" ></bean>
【2】autowire="byType"在容器的上下文中尋找與類中屬性類型相同的Bean進(jìn)行裝配
<bean id="teacher" class="cn.kgc.spring.entity.Teacher">
<property name="name" value="李老師"/>
<property name="teaNo" value="001"/>
</bean>
<bean id="classRoom1" class="cn.kgc.spring.entity.ClassRoom">
<property name="address" value="學(xué)思樓1樓"/>
<property name="classNo" value="1"/>
</bean>
<bean id="student" class="cn.kgc.spring.entity.Student" autowire="byType" ></bean>
【3】使用注解自動(dòng)裝配
- 導(dǎo)入context約束
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd" >
- 開啟注解支持
<context:annotation-config/>
public class Student {
@Value("2021")
private String stuNo;
@Value("wangwu")
private String name;
@Value("20")
private int age;
@Value("2021/12/08")
private Date birth;
@Autowired
private Teacher teacher;
@Resource
private ClassRoom classRoom;
}
??獲取配置文件中的值
public class Aoo {
@Value("${test.boolean}")
private Boolean testBoolean;
@Value("${test.string}")
private String testString;
@Value("${test.integer}")
private Integer testInteger;
@Value("${test.long}")
private Long testLong;
@Value("${test.float}")
private Float testFloat;
@Value("${test.double}")
private Double testDouble;
@Value("#{'${test.array}'.split(',')}")
private String[] testArray;
@Value("#{'${test.list}'.split(',')}")
private List<String> testList;
@Value("#{'${test.set}'.split(',')}")
private Set<String> testSet;
@Value("#{${test.map}}")
private Map<String, Object> testMap;
}
??配置文件 properties
test.boolean=true
test.string=abc
test.integer=123
test.long=123
test.float=1.2345678123456
test.double=1.2345678123456
test.array=1,3,4,5,6,1,2,3
test.list=1,3,4,5,6,1,2,3
test.set=1,3,4,5,6,1,2,3
test.map={name:"zhangsan", age:18}
6. spring中復(fù)雜對象的創(chuàng)建
【1】FactoryBean
public class ConnectionFactoryBean implements FactoryBean<Connection> {
@Override
public Connection getObject() throws Exception {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql:///java2215?serverTimezone=UTC", "root", "root");
return connection;
}
@Override
public Class<?> getObjectType() {
return Connection.class;
}
@Override
public boolean isSingleton() {
return false;
}
}
??xml配置方式:
<bean id="conn" class="cn.kgc.spring.ioc.entity.ConnectionFactoryBean"></bean>
【2】實(shí)例工廠
public class ConnectionFactoryBean {
public Connection getConnection() throws Exception {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql:///java2215?serverTimezone=UTC&useSSL=false", "root", "root");
return connection;
}
}
??xml配置方式:
<bean id="conn" class="cn.kgc.spring.ioc.entity.ConnectionFactoryBean"></bean>
<bean id="connection" factory-bean="conn" factory-method="getConnection"></bean>
【3】靜態(tài)工廠
public class ConnectionFactoryBean {
public static Connection getConnection() throws Exception {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql:///java2215?serverTimezone=UTC&useSSL=false", "root", "root");
return connection;
}
}
??xml配置方式:
<bean id="conn" class="cn.kgc.spring.ioc.entity.ConnectionFactoryBean" factory-method="getConnection"></bean>
??碼文不易,本篇文章就介紹到這里,如果想要學(xué)習(xí)更多Java系列知識(shí),點(diǎn)擊關(guān)注博主,博主帶你零基礎(chǔ)學(xué)習(xí)Java知識(shí)。與此同時(shí),對于日常生活有困擾的朋友,歡迎閱讀我的第四欄目:《國學(xué)周更—心性養(yǎng)成之路》,學(xué)習(xí)技術(shù)的同時(shí),我們也注重了心性的養(yǎng)成。文章來源:http://www.zghlxwxcb.cn/news/detail-824634.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-824634.html
到了這里,關(guān)于一文吃透 Spring 中的IOC和DI的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!