1.1 案例:數(shù)據(jù)源對象管理
以后我們會用到很多第三方的bean,我們以數(shù)據(jù)源是Druid(德魯伊)
和C3P0
來配置舉個例子。
1.1.1 環(huán)境準備
先來準備下案例環(huán)境:
1.1.2 思路分析
需求:使用Spring的IOC容器來管理Druid連接池對象
1.使用第三方的技術,需要在pom.xml添加依賴
2.在配置文件中將【第三方的類】制作成一個bean,讓IOC容器進行管理
3.數(shù)據(jù)庫連接需要基礎的四要素
驅動
、連接
、用戶名
和密碼
,【如何注入】到對應的bean中4.從IOC容器中獲取對應的bean對象,將其打印到控制臺查看結果
思考:
- 第三方的類指的是什么?
- 如何注入數(shù)據(jù)庫連接四要素?
1.1.3 實現(xiàn)Druid管理
帶著這兩個問題,把下面的案例實現(xiàn)下:
步驟1:導入druid
的依賴
pom.xml中添加依賴
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
步驟2:配置第三方bean
在applicationContext.xml配置文件中添加DruidDataSource
的配置
<!--管理DruidDataSource對象-->
<bean class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/spring_db"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
說明:
- driverClassName:數(shù)據(jù)庫驅動
- url:數(shù)據(jù)庫連接地址
- username:數(shù)據(jù)庫連接用戶名
- password:數(shù)據(jù)庫連接密碼
- 數(shù)據(jù)庫連接的四要素要和自己使用的數(shù)據(jù)庫信息一致。
步驟3:從IOC容器中獲取對應的bean對象
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
DataSource dataSource = (DataSource) ctx.getBean("dataSource");
System.out.println(dataSource);
}
}
步驟4:運行程序
打印如下結果: 說明第三方bean對象已經(jīng)被spring的IOC容器進行管理
做完案例后,我們可以將剛才思考的兩個問題答案說下:
-
第三方的類指的是什么?
DruidDataSource
-
如何注入數(shù)據(jù)庫連接四要素?
setter注入
1.1.4 實現(xiàn)C3P0管理
完成了DruidDataSource的管理,接下來我們再來加深下練習,這次我們來管理C3P0
數(shù)據(jù)源,具體的實現(xiàn)步驟是什么呢?
需求:使用Spring的IOC容器來管理C3P0連接池對象
實現(xiàn)方案和上面基本一致,重點要關注管理的是哪個bean對象`?
步驟1:導入C3P0
的依賴
pom.xml中添加依賴
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
對于新的技術,不知道具體的坐標該如何查找?
-
直接百度搜索
-
從mvn的倉庫
https://mvnrepository.com/
中進行搜索
步驟2:配置第三方bean
在applicationContext.xml配置文件中添加配置
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring_db"/>
<property name="user" value="root"/>
<property name="password" value="root"/>
<property name="maxPoolSize" value="1000"/>
</bean>
注意:
- ComboPooledDataSource的屬性是通過setter方式進行注入;
- 想注入屬性就需要在ComboPooledDataSource類或其上層類中有提供屬性對應的setter方法;
- C3P0的四個屬性和Druid的四個屬性是不一樣的;
步驟3:運行程序
程序會報錯,錯誤如下
報的錯為ClassNotFoundException,翻譯出來是類沒有發(fā)現(xiàn)的異常
,具體的類為com.mysql.jdbc.Driver
。錯誤的原因是缺少mysql的驅動包。
分析出錯誤的原因,具體的解決方案就比較簡單,只需要在pom.xml把驅動包引入即可。
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
添加完mysql的驅動包以后,再次運行App,就可以打印出結果:
注意:
- 數(shù)據(jù)連接池在配置屬性的時候,除了可以注入數(shù)據(jù)庫連接四要素外還可以配置很多其他的屬性,具體都有哪些屬性用到的時候再去查,一般配置基礎的四個,其他都有自己的默認值
- Druid和C3P0在沒有導入mysql驅動包的前提下,一個沒報錯一個報錯,說明Druid在初始化的時候沒有去加載驅動,而C3P0剛好相反
- Druid程序運行雖然沒有報錯,但是當調用DruidDataSource的getConnection()方法獲取連接的時候,也會報找不到驅動類的錯誤
1.2 加載properties文件
我們已經(jīng)完成兩個數(shù)據(jù)源druid
和C3P0
的配置,但是其中包含了一些問題,我們來分析下:
- 這兩個數(shù)據(jù)源中都使用到了一些固定的常量如數(shù)據(jù)庫連接四要素,把這些值寫在Spring的配置文件中不利于后期維護;
- 需要將這些值提取到一個外部的properties配置文件中;
- Spring框架如何從配置文件中讀取屬性值來配置就是接下來要解決的問題。
問題提出來后,具體該如何實現(xiàn)?
1.2.1 第三方bean屬性優(yōu)化
1.2.1.1 實現(xiàn)思路
需求:將數(shù)據(jù)庫連接四要素提取到properties配置文件,spring來加載配置信息并使用這些信息來完成屬性注入。
1.在resources下創(chuàng)建一個jdbc.properties(文件的名稱可以任意)
2.將數(shù)據(jù)庫連接四要素配置到配置文件中
3.在Spring的配置文件中加載properties文件
4.使用加載到的值實現(xiàn)屬性注入
其中第3,4步驟是需要大家重點關注,具體是如何實現(xiàn)。
1.2.1.2 實現(xiàn)步驟
步驟1:準備properties配置文件
resources下創(chuàng)建一個jdbc.properties文件,并添加對應的屬性鍵值對
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db
jdbc.username=root
jdbc.password=root
步驟2:開啟context
命名空間
在applicationContext.xml中開context
命名空間
步驟3:加載properties配置文件
在配置文件中使用context
命名空間下的標簽來加載properties配置文件
<context:property-placeholder location="jdbc.properties"/>
步驟4:完成屬性注入
使用${key}
來讀取properties配置文件中的內容并完成屬性注入
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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:property-placeholder location="jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>
至此,讀取外部properties配置文件中的內容就已經(jīng)完成。
1.2.2 讀取單個屬性
1.2.2.1 實現(xiàn)思路
對于上面的案例,效果不是很明顯,我們可以換個案例來演示下:
需求:從properties配置文件中讀取key為name的值,并將其注入到BookDao中并在save方法中進行打印。
1.在項目中添加BookDao和BookDaoImpl類
2.為BookDaoImpl添加一個name屬性并提供setter方法
3.在jdbc.properties中添加數(shù)據(jù)注入到bookDao中打印方便查詢結果
4.在applicationContext.xml添加配置完成配置文件加載、屬性注入(${key})
1.2.2.2 實現(xiàn)步驟
步驟1:在項目中添對應的類
BookDao和BookDaoImpl類,并在BookDaoImpl類中添加name
屬性與setter方法
public interface BookDao {
public void save();
}
public class BookDaoImpl implements BookDao {
private String name;
public void setName(String name) {
this.name = name;
}
public void save() {
System.out.println("book dao save ..." + name);
}
}
步驟2:完成配置文件的讀取與注入
在applicationContext.xml添加配置,bean的配置管理
、讀取外部properties
、依賴注入
:
<context:property-placeholder location="jdbc.properties"/>
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
<property name="name" value="${jdbc.driver}"/>
</bean>
</beans>
步驟3:運行程序
在App類中,從IOC容器中獲取bookDao對象,調用方法,查看值是否已經(jīng)被獲取到并打印控制臺
public class App {
public static void main(String[] args) throws Exception{
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
}
}
1.2.2.3 注意事項
至此,讀取properties配置文件中的內容就已經(jīng)完成,但是在使用的時候,有些注意事項:
-
問題一:鍵值對的key為
username
引發(fā)的問題1.在properties中配置鍵值對的時候,如果key設置為
username
username=root666
2.在applicationContext.xml注入該屬性
<context:property-placeholder location="jdbc.properties"/> <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"> <property name="name" value="${username}"/> </bean> </beans>
3.運行后,在控制臺打印的卻不是
root666
,而是自己電腦的用戶名4.出現(xiàn)問題的原因是
<context:property-placeholder/>
標簽會加載系統(tǒng)的環(huán)境變量,而且環(huán)境變量的值會被優(yōu)先加載,如何查看系統(tǒng)的環(huán)境變量?public static void main(String[] args) throws Exception{ Map<String, String> env = System.getenv(); System.out.println(env); }
大家可以自行運行,在打印出來的結果中會有一個USERNAME=XXX[自己電腦的用戶名稱]
5.解決方案
<context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/> </beans>
system-properties-mode:設置為NEVER,表示不加載系統(tǒng)屬性,就可以解決上述問題。
當然還有一個解決方案就是避免使用
username
作為屬性的key
。 -
問題二:當有多個properties配置文件需要被加載,該如何配置?
1.調整下配置文件的內容,在resources下添加
jdbc.properties
,jdbc2.properties
,內容如下:jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db jdbc.username=root jdbc.password=root
jdbc2.properties
username=root666
2.修改applicationContext.xml
<!--方式一 --> <context:property-placeholder location="jdbc.properties,jdbc2.properties" system-properties-mode="NEVER"/> <!--方式二--> <context:property-placeholder location="*.properties" system-properties-mode="NEVER"/> <!--方式三 --> <context:property-placeholder location="classpath:*.properties" system-properties-mode="NEVER"/> <!--方式四--> <context:property-placeholder location="classpath*:*.properties" system-properties-mode="NEVER"/> </beans>
說明:
- 方式一:可以實現(xiàn),如果配置文件多的話,每個都需要配置
- 方式二:
*.properties
代表所有以properties結尾的文件都會被加載,可以解決方式一的問題,但是不標準 - 方式三:標準的寫法,
classpath:
代表的是從根路徑下開始查找,但是只能查詢當前項目的根路徑 - 方式四:不僅可以加載當前項目還可以加載當前項目所依賴的所有項目的根路徑下的properties配置文件
1.2.3 加載properties文件小結
本節(jié)主要講解的是properties配置文件的加載,需要掌握的內容有:
-
如何開啟
context
命名空間 -
如何加載properties配置文件
<context:property-placeholder location="" system-properties-mode="NEVER"/>
-
如何在applicationContext.xml引入properties配置文件中的值
${key}
2,核心容器
這里所說的核心容器,可以把它簡單的理解為ApplicationContext
- 如何創(chuàng)建容器?
- 創(chuàng)建好容器后,如何從容器中獲取bean對象?
- 容器類的層次結構是什么?
- BeanFactory是什么?
2.1 環(huán)境準備
2.2 容器
2.2.1 容器的創(chuàng)建方式
案例中創(chuàng)建ApplicationContext
的方式為:
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
這種方式翻譯為:類路徑下的XML配置文件
除了上面這種方式,Spring還提供了另外一種創(chuàng)建方式為:
ApplicationContext ctx = new FileSystemXmlApplicationContext("applicationContext.xml");
這種方式翻譯為:文件系統(tǒng)下的XML配置文件
使用這種方式,運行,會出現(xiàn)如下錯誤:
從錯誤信息中能發(fā)現(xiàn),這種方式是從項目路徑下開始查找applicationContext.xml
配置文件的,所以需要將其修改為:
ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\workspace\\spring\\spring_10_container\\src\\main\\resources\\applicationContext.xml");
說明:寫自己的具體路徑。
這種方式雖能實現(xiàn),但是當項目的位置發(fā)生變化后,代碼也需要跟著改,耦合度較高,不推薦使用。
2.2.2 Bean的三種獲取方式
方式一,就是目前案例中獲取的方式:
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
這種方式存在的問題是每次獲取的時候都需要進行類型轉換,有沒有更簡單的方式呢?
方式二:
BookDao bookDao = ctx.getBean("bookDao",BookDao.class);
這種方式可以解決類型強轉問題,但是參數(shù)又多加了一個,相對來說沒有簡化多少。
方式三:
BookDao bookDao = ctx.getBean(BookDao.class);
這種方式就類似我們之前所學習依賴注入中的按類型注入。必須要確保IOC容器中該類型對應的bean對象只能有一個。
2.2.3 容器類層次結構
(1)在IDEA中雙擊shift
,輸入BeanFactory
(2)點擊進入BeanFactory類,ctrl+h,就能查看到如下結構的層次關系
從圖中可以看出,容器類也是從無到有根據(jù)需要一層層疊加上來的,大家重點理解下這種設計思想。
2.2.4 BeanFactory的使用
使用BeanFactory來創(chuàng)建IOC容器的具體實現(xiàn)方式為:
public class AppForBeanFactory {
public static void main(String[] args) {
Resource resources = new ClassPathResource("applicationContext.xml");
BeanFactory bf = new XmlBeanFactory(resources);
BookDao bookDao = bf.getBean(BookDao.class);
bookDao.save();
}
}
為了更好的看出BeanFactory
和ApplicationContext
之間的區(qū)別,在BookDaoImpl添加如下構造函數(shù):
public class BookDaoImpl implements BookDao {
public BookDaoImpl() {
System.out.println("constructor");
}
public void save() {
System.out.println("book dao save ..." );
}
}
如果不去獲取bean對象,打印會發(fā)現(xiàn):
-
BeanFactory是延遲加載,只有在獲取bean對象的時候才會去創(chuàng)建
-
ApplicationContext是立即加載,容器加載的時候就會創(chuàng)建bean對象
-
ApplicationContext要想成為延遲加載,只需要按照如下方式進行配置
<?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="bookDao" class="com.itheima.dao.impl.BookDaoImpl" lazy-init="true"/> </beans>
2.2 核心容器總結
2.2.1 容器相關
- BeanFactory是IoC容器的頂層接口,初始化BeanFactory對象時,加載的bean延遲加載
- ApplicationContext接口是Spring容器的核心接口,初始化時bean立即加載
- ApplicationContext接口提供基礎的bean操作相關方法,通過其他接口擴展其功能
- ApplicationContext接口常用初始化類
- ClassPathXmlApplicationContext(常用)
- FileSystemXmlApplicationContext
2.2.2 bean相關
其實整個配置中最常用的就兩個屬性id和class。
2.2.3 依賴注入相關
文章來源:http://www.zghlxwxcb.cn/news/detail-785120.html
后記
????????美好的一天,到此結束,下次繼續(xù)努力!欲知后續(xù),請看下回分解,寫作不易,感謝大家的支持?。???????文章來源地址http://www.zghlxwxcb.cn/news/detail-785120.html
到了這里,關于從入門到精通:掌握Spring IOC/DI配置管理第三方bean的技巧的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!