javascript
控制反转_Spring:IOC 控制反转
Spring 概述
Spring 是什么
Spring 是分層的 Java SE/EE 應(yīng)用 full-stack (全棧式) 輕量級開源框架。
全棧式:對各種主流技術(shù)和框架都進(jìn)行了整合,同時(shí)對三層架構(gòu)都提供解決方案。
輕量級和重量級的劃分主要依據(jù)就是看它使用了多少服務(wù),啟動時(shí)需要加載的資源多少以及耦合度等等。
提供了表現(xiàn)層 Spring MVC 和持久層 Spring JDBC Template 以及業(yè)務(wù)層事務(wù)管理等眾多的企業(yè)級應(yīng)用技術(shù),還能整合開源世界眾多著名的第三方框架和類庫,逐漸成為使用最多的 Java EE 企業(yè)應(yīng)用開源框架。
Spring 兩大核心:
IOC - Inverse Of Control 控制反轉(zhuǎn):把對象的創(chuàng)建權(quán)交給 Spring
AOP - Aspect Oriented Programming 面向切面編程:在不修改源碼的情況下,對方法進(jìn)行增強(qiáng)
Spring 發(fā)展歷程
EJB - Enterprise Java Beans:
1997 年,IBM 提出了 EJB 的思想
1998 年,SUN 制定開發(fā)標(biāo)準(zhǔn)規(guī)范 EJB 1.0
1999 年,EJB 1.1 發(fā)布
2001 年,EJB 2.0 發(fā)布
2003 年,EJB 2.1 發(fā)布
2006 年,EJB 3.0 發(fā)布
Spring:
Rod Johnson( Spring 之父)改變 Java 世界的大師級人物
2002 年編著《Expert one on one J2EE design and development》
指出了 Java EE 和 EJB 組件框架中的存在的一些主要缺陷;提出普通 java 類依賴注入更為簡單的解決方案
2004 年編著《Expert one-on-one J2EE Development without EJB》闡述了 Java EE 開發(fā)時(shí)不使用 EJB 的解決方式(Spring 雛形),同年 4 月 spring 1.0 誕生
2006 年 10 月,發(fā)布 Spring 2.0
2009 年 12 月,發(fā)布 Spring 3.0
2013 年 12 月,發(fā)布 Spring 4.0
2017 年 9 月, 發(fā)布最新 Spring 5.0 通用版(GA)
Spring 優(yōu)勢
耦合:程序間的依賴關(guān)系
解耦:降低程序間的依賴關(guān)系;體現(xiàn)在編譯期不依賴,運(yùn)行期才依賴
JDBC 例子:
public?class?JDBCTest?{????@Test
????public?void?test1()?throws?ClassNotFoundException,?SQLException?{
????????//?1.注冊驅(qū)動
????????//?存在編譯期依賴:耦合重的體現(xiàn)
????????//?DriverManager.registerDriver(new?com.mysql.jdbc.Driver());
????????//?去掉?new?關(guān)鍵字:編譯期不依賴,運(yùn)行期才依賴。雖然解決了編譯期依賴,但是仍存在硬編碼問題
????????Class.forName("com.mysql.jdbc.Driver");
????????...
????}
}
解耦思路:配置文件 + 反射
Spring:
1)方便解耦,簡化開發(fā)
Spring 就是一個(gè)容器,可以將所有對象創(chuàng)建和關(guān)系維護(hù)交給 Spring 管理
什么是耦合度?對象之間的關(guān)系,通常說當(dāng)一個(gè)模塊 (對象) 更改時(shí)也需要更改其他模塊 (對象),這就是耦合,耦合度過高會使代碼的維護(hù)成本增加。要盡量解耦
2)AOP 編程的支持
Spring 提供面向切面編程,方便實(shí)現(xiàn)程序進(jìn)行權(quán)限攔截,運(yùn)行監(jiān)控等功能。
3)聲明式事務(wù)的支持
通過配置完成事務(wù)的管理,無需手動編程
4)方便測試,降低 Java EE API 的使用
Spring 對 Junit 4 支持,可以使用注解測試
5)方便集成各種優(yōu)秀框架
不排除各種優(yōu)秀的開源框架,內(nèi)部提供了對各種優(yōu)秀框架的直接支持
Spring 體系結(jié)構(gòu)
以下八大模塊可根據(jù)需求引入項(xiàng)目使用:
Data Access/Integration
JDBC
ORM
OXM
JMS
Transactions
Web
WebSocket
Servlet
Web
Portlet
AOP
Aspects
Instrumentation
Messaging
Core Container - 相當(dāng)于蓋房子的地基
Beans
Core
Context
SpEL
Test
初識 IOC
概述
控制反轉(zhuǎn)(Inverse Of Control)是一種設(shè)計(jì)思想,它的目的是指導(dǎo)我們設(shè)計(jì)出更加松耦合的程序。
控制:在 java 中指的是對象的控制權(quán)限(創(chuàng)建、銷毀)。
反轉(zhuǎn):指的是對象控制權(quán)從由“開發(fā)者在類中手動控制”反轉(zhuǎn)到由“ Spring 容器控制”。
例子:
傳統(tǒng)方式 - 需要一個(gè) userDao 實(shí)例,需要開發(fā)者自己手動創(chuàng)建 new UserDao();
IOC 方式 - 需要一個(gè) userDao 實(shí)例,直接從 spring 的 IOC 容器獲得,對象的創(chuàng)建權(quán)交給了spring 控制
自定義 IOC 容器
介紹
需求:實(shí)現(xiàn) Service 層與 Dao 層代碼解耦合
步驟分析:
創(chuàng)建 java 項(xiàng)目,導(dǎo)入自定義 IOC 相關(guān)坐標(biāo)
編寫 Dao 接口和實(shí)現(xiàn)類
編寫 Service 接口和實(shí)現(xiàn)類
編寫測試代碼
實(shí)現(xiàn)
創(chuàng)建 java 項(xiàng)目,導(dǎo)入自定義 IOC 相關(guān)坐標(biāo)
<?xml ?version="1.0"?encoding="UTF-8"?><project?xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0?http://maven.apache.org/xsd/maven-4.0.0.xsd">
????<modelVersion>4.0.0modelVersion>
????<groupId>com.rendagroupId>
????<artifactId>jdbc_springartifactId>
????<version>1.0-SNAPSHOTversion>
????
????<properties>
????????<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
????????<maven.compiler.encoding>UTF-8maven.compiler.encoding>
????????<java.version>1.11java.version>
????????<maven.compiler.source>1.11maven.compiler.source>
????????<maven.compiler.target>1.11maven.compiler.target>
????properties>
????<dependencies>
????????<dependency>
????????????<groupId>dom4jgroupId>
????????????<artifactId>dom4jartifactId>
????????????<version>1.6.1version>
????????dependency>
????????<dependency>
????????????<groupId>jaxengroupId>
????????????<artifactId>jaxenartifactId>
????????????<version>1.1.6version>
????????dependency>
????????<dependency>
????????????<groupId>junitgroupId>
????????????<artifactId>junitartifactId>
????????????<version>4.12version>
????????dependency>
????dependencies>
project>
編寫 Dao 接口和實(shí)現(xiàn)類
public?interface?IUserDao?{????void?save();
}
public?class?UserDaoImpl?implements?IUserDao?{
????@Override
????public?void?save()?{
????????System.out.println("UserDao:?Successfully?Saved.");
????}
}
編寫 Service 接口和實(shí)現(xiàn)類
public?interface?IUserService?{????void?save();
}
public?class?UserServiceImpl?implements?IUserService?{
????private?IUserDao?userDao?=?new?UserDaoImpl();
????@Override
????public?void?save()?{
????????userDao.save();
????}
}
編寫測試代碼
public?class?SpringTest?{????@Test
????public?void?test1()?{
????????//?獲取業(yè)務(wù)層對象
????????IUserService?userService?=?new?UserServiceImpl();
????????//?調(diào)用?save?方法
????????userService.save();
????}
}
問題:當(dāng)前 service 對象和 Dao 對象耦合度太高,而且每次 new 的都是一個(gè)新的對象,導(dǎo)致服務(wù)器壓力過大。
解耦合的原則是編譯期不依賴,而運(yùn)行期依賴就行了。
采用反射方式:
public?class?UserServiceImpl?implements?IUserService?{????private?IUserDao?userDao;
????public?UserServiceImpl()?throws?IllegalAccessException,?ClassNotFoundException,?InstantiationException?{
????????//?傳統(tǒng)方式使用?new?方式,導(dǎo)致編譯期依賴,耦合度太高
????????//?userDao?=?new?UserDaoImpl();
????????//?反射方式,存在硬編碼問題
????????userDao?=?(IUserDao)?Class.forName("com.renda.dao.impl.UserDaoImpl").newInstance();
????}
????@Override
????public?void?save()?{
????????userDao.save();
????}
}
測試代碼:
@Testpublic?void?test1()?throws?IllegalAccessException,?InstantiationException,?ClassNotFoundException?{
????IUserService?userService?=?new?UserServiceImpl();
????userService.save();
}
改造步驟分析:
準(zhǔn)備一個(gè)配置文件
編寫一個(gè)工廠工具類,工廠類使用 dom4j 來解析配置文件,獲取到類的全路徑
使用反射生成對應(yīng)類的實(shí)例對象,存到 Map 中,這個(gè) Map 就是 IOC 容器
為了解決反射方式的硬編碼問題,先編寫 beans.xml 配置文件
<beans>????
????<bean?id="userDao"?class="com.renda.dao.impl.UserDaoImpl">bean>
beans>
編寫 BeanFactory 工具類
public?class?BeanFactory?{????private?static?Map?iocMap?=?new?HashMap<>();//?程序啟動時(shí),初始化對象實(shí)例static?{//?讀取配置文件
????????InputStream?resourceAsStream?=?BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml");try?{//?解析?xml(dom4j)
????????????SAXReader?saxReader?=?new?SAXReader();
????????????Document?document?=?saxReader.read(resourceAsStream);//?編寫?xpath?表達(dá)式
????????????String?xpath?=?"//bean";//?獲取到所有的?bean?標(biāo)簽
????????????List?list?=?document.selectNodes(xpath);//?遍歷并使用反射創(chuàng)建對象實(shí)例,存到?map?集合(ioc?容器)中for?(Element?element?:?list)?{
????????????????String?id?=?element.attributeValue("id");
????????????????String?className?=?element.attributeValue("class");//?使用反射生成實(shí)例對象
????????????????Object?o?=?Class.forName(className).newInstance();//?存到?map?中:key-id,value-o
????????????????iocMap.put(id,?o);
????????????}
????????}?catch?(DocumentException?|?InstantiationException?|?IllegalAccessException?|?ClassNotFoundException?e)?{
????????????e.printStackTrace();
????????}
????}public?static?Object?getBean(String?beanId)?{return?iocMap.get(beanId);
????}
}
修改 UserServiceImpl 實(shí)現(xiàn)類
public?UserServiceImpl()?throws?IllegalAccessException,?ClassNotFoundException,?InstantiationException?{????//?傳統(tǒng)方式使用?new?方式,導(dǎo)致編譯期依賴,耦合度太高
????//?userDao?=?new?UserDaoImpl();
????//?反射方式,存在硬編碼問題
????//?userDao?=?(IUserDao)?Class.forName("com.renda.dao.impl.UserDaoImpl").newInstance();
????//?反射方式?+?配置文件
????userDao?=?(IUserDao)?BeanFactory.getBean("userDao");
}
小結(jié)
其實(shí)升級后的 BeanFactory 就是一個(gè)簡單的 Spring 的 IOC 容器所具備的功能。
之前需要一個(gè) userDao 實(shí)例,開發(fā)者自己手動創(chuàng)建 new UserDao();
現(xiàn)在需要一個(gè) userDao 實(shí)例,直接從 spring 的 IOC 容器獲得,對象的創(chuàng)建權(quán)交給了 spring 控制
最終目標(biāo):代碼解耦合
Spring 快速入門
介紹
需求:借助 spring 的 IOC 實(shí)現(xiàn) service 層與 DAO 層代碼解耦合
步驟分析:
創(chuàng)建 java 項(xiàng)目,導(dǎo)入 spring 開發(fā)基本坐標(biāo)
編寫 DAO 接口和實(shí)現(xiàn)類
創(chuàng)建 spring 核心配置文件
在 spring 配置文件中配置 UserDaoImpl
使用 spring 相關(guān) API 獲得 Bean 實(shí)例
實(shí)現(xiàn)
創(chuàng)建 java 項(xiàng)目,導(dǎo)入 spring 開發(fā)基本坐標(biāo)
<dependencies>????<dependency>
????????<groupId>org.springframeworkgroupId>
????????<artifactId>spring-contextartifactId>
????????<version>5.1.5.RELEASEversion>
????dependency>
????<dependency>
????????<groupId>junitgroupId>
????????<artifactId>junitartifactId>
????????<version>4.12version>
????dependency>
dependencies>
編寫 Dao 接口和實(shí)現(xiàn)類
public?interface?IUserDao?{????void?save();
}
public?class?UserDaoImpl?implements?IUserDao?{
????@Override
????public?void?save()?{
????????System.out.println("UserDao:?save...");
????}
}
創(chuàng)建 spring 核心配置文件 applicationContext.xml,并在 spring 配置文件中配置 UserDaoImpl 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"xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beans
????????http://www.springframework.org/schema/beans/spring-beans.xsd">
????
????<bean?id="userDao"?class="com.renda.dao.impl.UserDaoImpl"/>
beans>
使用 spring 相關(guān) API 獲得 Bean 實(shí)例
@Testpublic?void?test1(){
????//?獲取到了?spring?上下文對象,借助上下文對象可以獲取到?IOC?容器中的?bean?對象?,加載的同時(shí)就創(chuàng)建了?bean?對象存到容器中
????//?ApplicationContext?XmlApplicationContext?=?new?FileSystemXmlApplicationContext("D:\\gitee_repository\\stage-6-module-2\\code\\spring_quickstart\\src\\main\\resources\\applicationContext.xml");
????ApplicationContext?XmlApplicationContext?=?new?ClassPathXmlApplicationContext("applicationContext.xml");
????//?使用上下文對象從?IOC?容器中獲取到了?bean?對象
????//?方法一:根據(jù)?bean?id?在容器中找對應(yīng)的?bean?對象
????//?IUserDao?userDao?=?(IUserDao)?XmlApplicationContext.getBean("userDao");
????//?方法二:根據(jù)類型從容器中匹配?Bean?實(shí)例,當(dāng)容器中相同類型的?Bean?有多個(gè)時(shí),則此方法會報(bào)錯(cuò)。
????//?IUserDao?userDao?=?XmlApplicationContext.getBean(IUserDao.class);
????//?方法三:根據(jù)?Bean?的?id?和類型獲得?Bean?實(shí)例,解決容器中相同類型?Bean?有多個(gè)情況。
????IUserDao?userDao?=?XmlApplicationContext.getBean("userDao",?IUserDao.class);
????//?調(diào)用方法
????userDao.save();
}
Spring 的開發(fā)步驟總結(jié)
導(dǎo)入坐標(biāo)
創(chuàng)建 Bean
創(chuàng)建 applicationContext.xml
在配置文件中進(jìn)行 Bean 配置
創(chuàng)建 ApplicationContext 對象,執(zhí)行 getBean
Spring 相關(guān) API
API 繼承體系介紹
Spring 的 API 體系異常龐大,現(xiàn)在只關(guān)注兩個(gè) BeanFactory 和 ApplicationContext
BeanFactory 是 ApplicationContext 的父接口,ApplicationContext 接口下又有 FileSystemXmlApplicationContext 和 ClassPathXmlApplicationContext 子接口
BeanFactory
BeanFactory 是 IOC 容器的核心接口,它定義了 IOC 的基本功能
特點(diǎn):在第一次調(diào)用 getBean() 方法時(shí),創(chuàng)建指定對象的實(shí)例
@Testpublic?void?test2(){
????//?核心接口,不會創(chuàng)建?bean?對象存到容器中
????BeanFactory?xmlBeanFactory?=?new?XmlBeanFactory(new?ClassPathResource("applicationContext.xml"));
????//?getBean?的時(shí)候才真正創(chuàng)建?bean?對象
????IUserDao?userDao?=?(IUserDao)?xmlBeanFactory.getBean("userDao");
????//?調(diào)用方法
????userDao.save();
}
ApplicationContext
代表應(yīng)用上下文對象,可以獲得 spring 中 IOC 容器的 Bean 對象
特點(diǎn):在 spring 容器啟動時(shí),加載并創(chuàng)建所有對象的實(shí)例
常用實(shí)現(xiàn)類:
ClassPathXmlApplicationContext - 它是從類的根路徑下加載配置文件,推薦使用這種。
FileSystemXmlApplicationContext - 它是從磁盤路徑上加載配置文件,配置文件可以在磁盤的任意位置。
AnnotationConfigApplicationContext - 當(dāng)使用注解配置容器對象時(shí),需要使用此類來創(chuàng)建 spring 容器,它用來讀取注解。
常用方法:
Object getBean(String name); - 根據(jù) Bean 的 id 從容器中獲得 Bean 實(shí)例,返回是 Object,需要強(qiáng)轉(zhuǎn)。
T getBean(ClassrequiredType); - 根據(jù)類型從容器中匹配 Bean 實(shí)例,當(dāng)容器中相同類型的 Bean 有多個(gè)時(shí),則此方法會報(bào)錯(cuò)。
T getBean(String name,ClassrequiredType); - 根據(jù) Bean 的 id 和類型獲得 Bean 實(shí)例,解決容器中相同類型 Bean 有多個(gè)情況。
Spring 配置文件
Bean 標(biāo)簽基本配置
用于配置對象交由 Spring 來創(chuàng)建。
默認(rèn)情況下它調(diào)用的是類中的無參構(gòu)造函數(shù),如果沒有無參構(gòu)造函數(shù)則不能創(chuàng)建成功。
<bean?id=""?class=""/>
Bean 標(biāo)簽范圍配置
<bean?id=""?class=""?scope="">bean>scope 屬性指對象的作用范圍,取值如下:
singleton - 默認(rèn)值,單例的
prototype - 多例的
request - WEB 項(xiàng)目中,Spring 創(chuàng)建一個(gè) Bean 的對象,將對象存入到 request 域中
session - WEB 項(xiàng)目中,Spring 創(chuàng)建一個(gè) Bean 的對象,將對象存入到 session 域中
global session - WEB 項(xiàng)目中,應(yīng)用在 Portlet 環(huán)境,如果沒有 Portlet 環(huán)境那么 global Session 相當(dāng)于 session
測試 scope 屬性:
@Testpublic?void?test3(){
????ApplicationContext?classPathXmlApplicationContext?=?new?ClassPathXmlApplicationContext("applicationContext.xml");
????IUserDao?userDao_1?=?(IUserDao)?classPathXmlApplicationContext.getBean("userDao");
????IUserDao?userDao_2?=?(IUserDao)?classPathXmlApplicationContext.getBean("userDao");
????System.out.println(userDao_1);
????System.out.println(userDao_2);
}
當(dāng) scope 的取值為 singleton 時(shí):
-?Bean?的實(shí)例化個(gè)數(shù):1?個(gè)-?Bean?的實(shí)例化時(shí)機(jī):當(dāng)?Spring?核心文件被加載時(shí),實(shí)例化配置的?Bean?實(shí)例
-?Bean?的生命周期:
????????+?對象創(chuàng)建:當(dāng)應(yīng)用加載,創(chuàng)建容器時(shí),對象就被創(chuàng)建了
????????+?對象運(yùn)行:只要容器在,對象一直活著
????????+?對象銷毀:當(dāng)應(yīng)用卸載,銷毀容器時(shí),對象就被銷毀了
當(dāng) scope 的取值為 prototype 時(shí):
-?Bean?的實(shí)例化個(gè)數(shù):多個(gè)-?Bean?的實(shí)例化時(shí)機(jī):當(dāng)調(diào)用?getBean()?方法時(shí)實(shí)例化?Bean
-?Bean?的生命周期:
??????????+?對象創(chuàng)建:當(dāng)使用對象時(shí),創(chuàng)建新的對象實(shí)例
??????????+?對象運(yùn)行:只要對象在使用中,就一直活著
??????????+?對象銷毀:當(dāng)對象長時(shí)間不用時(shí),被?Java?的垃圾回收器回收了
Bean 生命周期配置
applicationContext.xml
<bean?id="userDao"?class="com.renda.dao.impl.UserDaoImpl"?init-method="init"?destroy-method="destroy"/>init-method:指定類中的初始化方法名稱
destroy-method:指定類中銷毀方法名稱
????public?void?init()?{
????????System.out.println("UserDao:?Initialize...");
????}
????public?void?destroy()?{
????????System.out.println("UserDao:?Destroy");
????}
????...
}
測試代碼
@Testpublic?void?test4(){
????ClassPathXmlApplicationContext?classPathXmlApplicationContext?=?new?ClassPathXmlApplicationContext("applicationContext.xml");
????IUserDao?userDao_1?=?(IUserDao)?classPathXmlApplicationContext.getBean("userDao");
????IUserDao?userDao_2?=?(IUserDao)?classPathXmlApplicationContext.getBean("userDao");
????System.out.println(userDao_1);
????System.out.println(userDao_2);
????//?觸發(fā)?destroy?方法
????classPathXmlApplicationContext.close();
}
Bean 實(shí)例化三種方式
無參構(gòu)造方法實(shí)例化
它會根據(jù)默認(rèn)無參構(gòu)造方法來創(chuàng)建類對象,如果 bean 中沒有默認(rèn)無參構(gòu)造函數(shù),將會創(chuàng)建失敗
<bean?id="userDao"?class="com.renda.dao.impl.UserDaoImpl"/>工廠靜態(tài)方法實(shí)例化
應(yīng)用場景:依賴的 jar 包中有個(gè) A 類,A 類中有個(gè)靜態(tài)方法 m1,m1 方法的返回值是一個(gè) B 對象。如果頻繁使用 B 對象,此時(shí)可以將 B 對象的創(chuàng)建權(quán)交給 spring 的 IOC 容器,以后在使用 B 對象時(shí),無需調(diào)用 A 類中的 m1 方法,直接從 IOC 容器獲得。
public?class?StaticFactoryBean?{????public?static?IUserDao?createUserDao(){
????????return??new?UserDaoImpl();
????}
}
<?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:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beans
????????http://www.springframework.org/schema/beans/spring-beans.xsd">
????
????
????
????<bean?id="userDao"?class="com.renda.factory.StaticFactoryBean"?factory-method="createUserDao"/>
beans>
工廠普通方法實(shí)例化
應(yīng)用場景:依賴的 jar 包中有個(gè) A 類,A 類中有個(gè)普通方法 m1,m1 方法的返回值是一個(gè) B 對象。如果我們頻繁使用 B 對象,此時(shí)我們可以將 B 對象的創(chuàng)建權(quán)交給 spring 的 IOC 容器,以后我們在使用 B 對象時(shí),無需調(diào)用 A 類中的 m1 方法,直接從 IOC 容器獲得。
public?class?DynamicFactoryBean?{????public?IUserDao?createUserDao(){
????????return??new?UserDaoImpl();
????}
}
<?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:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beans
????????http://www.springframework.org/schema/beans/spring-beans.xsd">
????
????
????
????
????<bean?id="dynamicFactoryBean"?class="com.renda.factory.DynamicFactoryBean"/>
????<bean?id="userDao"?factory-bean="dynamicFactoryBean"?factory-method="createUserDao"/>
beans>
Bean 依賴注入方式
依賴注入 DI(Dependency Injection):它是 Spring 框架核心 IOC 的具體實(shí)現(xiàn)。
在編寫程序時(shí),通過控制反轉(zhuǎn),把對象的創(chuàng)建交給了 Spring,但是代碼中不可能出現(xiàn)沒有依賴的情況。IOC 解耦只是降低他們的依賴關(guān)系,但不會消除。例如:業(yè)務(wù)層仍會調(diào)用持久層的方法。
這種業(yè)務(wù)層和持久層的依賴關(guān)系,在使用 Spring 之后,就讓 Spring 來維護(hù)了。簡單的說,就是通過框架把持久層對象傳入業(yè)務(wù)層,而不用手動去獲取。
Bean 依賴注入方式
構(gòu)造方法
在 UserServiceImpl 中創(chuàng)建有參構(gòu)造
public?class?UserServiceImpl?implements?IUserService?{????IUserDao?userDao;
????public?UserServiceImpl(IUserDao?userDao)?{
????????this.userDao?=?userDao;
????}
????public?UserServiceImpl()?{
????}
????@Override
????public?void?save()?{
????????//?調(diào)用?dao?層的?save?方法
????????userDao.save();
????}
}
配置 Spring 容器調(diào)用有參構(gòu)造時(shí)進(jìn)行注入
<bean?id="userDao"?class="com.renda.dao.impl.UserDaoImpl"/><bean?id="userService"?class="com.renda.service.impl.UserServiceImpl">
????
????<constructor-arg?name="userDao"?ref="userDao"/>
bean>
`set` 方法
在 UserServiceImpl 中創(chuàng)建 set 方法
public?class?UserServiceImpl?implements?IUserService?{????IUserDao?userDao;
????public?UserServiceImpl(IUserDao?userDao)?{
????????this.userDao?=?userDao;
????}
????public?UserServiceImpl()?{
????}
????@Override
????public?void?save()?{
????????//?調(diào)用?dao?層的?save?方法
????????userDao.save();
????}
????public?void?setUserDao(IUserDao?userDao)?{
????????this.userDao?=?userDao;
????}
}
配置 Spring 容器調(diào)用 set 方法進(jìn)行注入
<bean?id="userDao"?class="com.renda.dao.impl.UserDaoImpl"/><bean?id="userService"?class="com.renda.service.impl.UserServiceImpl">
????
????
????
????
????<property?name="userDao"?ref="userDao">property>
bean>
P 命名空間注入
P 命名空間注入本質(zhì)也是 set 方法注入,但比起上述的 set 方法注入更加方便,主要體現(xiàn)在配置文件 applicationContext.xml 中。
首先,需要引入 P 命名空間:
xmlns:p="http://www.springframework.org/schema/p"其次,需要修改注入方式:
<bean?id="userDao"?class="com.renda.dao.impl.UserDaoImpl"/><bean?id="userService"?class="com.renda.service.impl.UserServiceImpl"?p:userDao-ref="userDao"/>
Bean 依賴注入的數(shù)據(jù)類型
上面操作,都是注入 Bean 對象,除了對象的引用可以注入,普通數(shù)據(jù)類型和集合都可以在容器中進(jìn)行注入。
注入數(shù)據(jù)的三種數(shù)據(jù)類型:
普通數(shù)據(jù)類型
引用數(shù)據(jù)類型
集合數(shù)據(jù)類型
之前的操作都是對 UserDao 對象的引用進(jìn)行注入的,屬于引用數(shù)據(jù)類型注入。下面將以 set 方法注入為例,演示普通數(shù)據(jù)類型和集合數(shù)據(jù)類型的注入。
注入普通數(shù)據(jù)類型
public?class?UserDaoImpl?implements?IUserDao?{????private?String?username;
????private?Integer?age;
????public?void?setUsername(String?username)?{
????????this.username?=?username;
????}
????public?void?setAge(Integer?age)?{
????????this.age?=?age;
????@Override
????public?void?save()?{
????????System.out.println(username);
????????System.out.println(age);
????????System.out.println("UserDao:?save...");
????}
}
<bean?id="userDao"?class="com.renda.dao.impl.UserDaoImpl">
????
????<property?name="username"?value="張人大"/>
????<property?name="age"?value="25"/>
bean>
注入集合數(shù)據(jù)類型
List 集合注入
public?class?User?{????private?String?username;
????private?Integer?age;
????public?void?setUsername(String?username)?{
????????this.username?=?username;
????}
????public?void?setAge(Integer?age)?{
????????this.age?=?age;
????}
}
public?class?UserDaoImpl?implements?IUserDao?{
????private?List?list;public?void?setList(List?list)?{this.list?=?list;
????}@Overridepublic?void?save()?{
????????System.out.println("List:"?+?list);
????}
}<bean?id="user"?class="com.renda.domain.User">
????<property?name="username"?value="布萊爾"/>
????<property?name="age"?value="18"/>
bean>
<bean?id="userDao"?class="com.renda.dao.impl.UserDaoImpl">
????<property?name="list">
????????<list>
????????????<value>aaavalue>
????????????<ref?bean="user"/>
????????list>
????property>
bean>
Set 集合注入
public?class?UserDaoImpl?implements?IUserDao?{????private?Set?set;public?void?setSet(Set?set)?{this.set?=?set;
????}@Overridepublic?void?save()?{
????????System.out.println("Set:"?+?set);
????}
}<bean?id="user"?class="com.renda.domain.User">
????<property?name="username"?value="布萊爾"/>
????<property?name="age"?value="18"/>
bean>
<bean?id="userDao"?class="com.renda.dao.impl.UserDaoImpl">
????<property?name="set">
????????<set>
????????????<value>bbbvalue>
????????????<ref?bean="user"/>
????????set>
????property>
bean>
Array 數(shù)組注入
public?class?UserDaoImpl?implements?IUserDao?{????private?Object[]?array;
????public?void?setArray(Object[]?array)?{
????????this.array?=?array;
????}
????@Override
????public?void?save()?{
????????System.out.println("Array:"?+?Arrays.toString(array));
????}
}
<bean?id="userDao"?class="com.renda.dao.impl.UserDaoImpl">
????<property?name="array">
????????<array>
????????????<value>cccvalue>
????????????<ref?bean="user"/>
????????array>
????property>
bean>
Map 集合注入
public?class?UserDaoImpl?implements?IUserDao?{????private?Map?map;public?void?setMap(Map?map)?{this.map?=?map;
????}@Overridepublic?void?save()?{
????????System.out.println("Map:"?+?map);
????}
}<bean?id="userDao"?class="com.renda.dao.impl.UserDaoImpl">
????<property?name="map">
????????<map>
????????????<entry?key="k1"?value="ddd"/>
????????????<entry?key="k2"?value-ref="user"/>
????????map>
????property>
bean>
Properties 配置注入
public?class?UserDaoImpl?implements?IUserDao?{????private?Properties?properties;
????public?void?setProperties(Properties?properties)?{
????????this.properties?=?properties;
????}
????@Override
????public?void?save()?{
????????System.out.println("Properties:"?+?properties);
????}
}
<bean?id="userDao"?class="com.renda.dao.impl.UserDaoImpl">
????<property?name="properties">
????????<props>
????????????<prop?key="k1">v1prop>
????????????<prop?key="k2">v2prop>
????????????<prop?key="k3">v3prop>
????????props>
????property>
bean>
配置文件模塊化
實(shí)際開發(fā)中,Spring 的配置內(nèi)容非常多,這就導(dǎo)致 Spring 配置很繁雜且體積很大,所以,可以將部分配置拆解到其他配置文件中,也就是所謂的配置文件模塊化。
并列的多個(gè)配置文件:
ApplicationContext?ac?=?new?ClassPathXmlApplicationContext("beans1.xml",?"beans2.xml",?"...");主從配置文件:
<import?resource="applicationContext-xxx.xml"/>注意:
同一個(gè) xml 中不能出現(xiàn)相同名稱的 bean,如果出現(xiàn)會報(bào)錯(cuò)。
多個(gè) xml 如果出現(xiàn)相同名稱的 bean,不會報(bào)錯(cuò),但是后加載的會覆蓋前加載的 bean。
小結(jié)
Spring 的重點(diǎn)配置
<bean>?標(biāo)簽:創(chuàng)建對象并放到?spring?的?IOC?容器????id?屬性:?在容器中?Bean?實(shí)例的唯一標(biāo)識,不允許重復(fù)
????class?屬性:?要實(shí)例化的?Bean?的全限定名
????scope?屬性:?Bean?的作用范圍,常用是?Singleton?(默認(rèn))?和?prototype
<constructor-arg>?標(biāo)簽:屬性注入
????name?屬性:屬性名稱
????value?屬性:注入的普通屬性值
????ref?屬性:注入的對象引用值
<property>?標(biāo)簽:屬性注入
????name?屬性:屬性名稱
????value?屬性:注入的普通屬性值
????ref?屬性:注入的對象引用值
????<list>
????<set>
????<array>
????<map>
????<properties>
<import>?標(biāo)簽:?導(dǎo)入其他的?Spring?的分文件
IOC 實(shí)戰(zhàn) - DbUtils
DbUtils 是什么?
DbUtils 是 Apache 的一款用于簡化 Dao 代碼的工具類,它底層封裝了 JDBC 技術(shù)。
核心對象:
QueryRunner?queryRunner?=?new?QueryRunner(DataSource?dataSource);核心方法:
int update() - 執(zhí)行增、刪、改語句
T query() - 執(zhí)行查詢語句
ResultSetHandler - 這是一個(gè)接口,主要作用是將數(shù)據(jù)庫返回的記錄封裝到實(shí)體對象
查詢數(shù)據(jù)庫所有賬戶信息到 Account 實(shí)體中:
public?class?DbUtilsTest?{????@Test
????public?void?findAllTest()?throws?Exception?{
????????//?創(chuàng)建?DBUtils?工具類,傳入連接池
????????QueryRunner?queryRunner?=?new?QueryRunner(JdbcUtils.getDataSource());
????????//?編寫?sql
????????String?sql?=?"select?*?from?account";
????????//?執(zhí)行?sql
????????List?list?=?queryRunner.query(sql,?new?BeanListHandler?(Account.class));//?打印結(jié)果for?(Account?account?:?list)?{
????????????System.out.println(account);
????????}
????}
}
Spring 的 `xml` 整合 `DbUtils`
介紹
需求:基于 Spring 的 xml 配置實(shí)現(xiàn)賬戶的 CRUD 案例
步驟分析:
準(zhǔn)備數(shù)據(jù)庫環(huán)境
創(chuàng)建 java 項(xiàng)目,導(dǎo)入坐標(biāo)
編寫 Account 實(shí)體類
編寫 AccountDao 接口和實(shí)現(xiàn)類
編寫 AccountService 接口和實(shí)現(xiàn)類
編寫 spring 核心配置文件
編寫測試代碼
實(shí)現(xiàn)
準(zhǔn)備數(shù)據(jù)庫環(huán)境
CREATE?DATABASE?`spring_db`;USE?`spring_db`;
CREATE?TABLE?`account`?(
????`id`?int(11)?NOT?NULL?AUTO_INCREMENT,
????`name`?varchar(32)?DEFAULT?NULL,
????`money`?double?DEFAULT?NULL,
????PRIMARY?KEY?(`id`)
);
insert??into?`account`(`id`,`name`,`money`)?values?(1,'tom',1000),
(2,'jerry',1000);
創(chuàng)建 java 項(xiàng)目,導(dǎo)入坐標(biāo)
<?xml ?version="1.0"?encoding="UTF-8"?><project?xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0?http://maven.apache.org/xsd/maven-4.0.0.xsd">
????<modelVersion>4.0.0modelVersion>
????<groupId>com.rendagroupId>
????<artifactId>spring_dbutilsartifactId>
????<version>1.0-SNAPSHOTversion>
????
????<properties>
????????<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
????????<maven.compiler.encoding>UTF-8maven.compiler.encoding>
????????<java.version>1.11java.version>
????????<maven.compiler.source>1.11maven.compiler.source>
????????<maven.compiler.target>1.11maven.compiler.target>
????properties>
????<dependencies>
????????<dependency>
????????????<groupId>mysqlgroupId>
????????????<artifactId>mysql-connector-javaartifactId>
????????????<version>5.1.47version>
????????dependency>
????????<dependency>
????????????<groupId>com.alibabagroupId>
????????????<artifactId>druidartifactId>
????????????<version>1.1.9version>
????????dependency>
????????<dependency>
????????????<groupId>commons-dbutilsgroupId>
????????????<artifactId>commons-dbutilsartifactId>
????????????<version>1.6version>
????????dependency>
????????<dependency>
????????????<groupId>org.springframeworkgroupId>
????????????<artifactId>spring-contextartifactId>
????????????<version>5.1.5.RELEASEversion>
????????dependency>
????????<dependency>
????????????<groupId>junitgroupId>
????????????<artifactId>junitartifactId>
????????????<version>4.12version>
????????dependency>
????????<dependency>
????????????<groupId>javax.annotationgroupId>
????????????<artifactId>javax.annotation-apiartifactId>
????????????<version>1.3.2version>
????????dependency>
????dependencies>
project>
編寫 Account 實(shí)體類
public?class?Account?{????private?Integer?id;
????private?String?name;
????private?Double?money;
????@Override
????public?String?toString()?{
????????return?"Account{"?+
????????????????"id="?+?id?+
????????????????",?name='"?+?name?+?'\''?+
????????????????",?money="?+?money?+
????????????????'}';
????}
????public?Integer?getId()?{
????????return?id;
????}
????public?void?setId(Integer?id)?{
????????this.id?=?id;
????}
????public?String?getName()?{
????????return?name;
????}
????public?void?setName(String?name)?{
????????this.name?=?name;
????}
????public?Double?getMoney()?{
????????return?money;
????}
????public?void?setMoney(Double?money)?{
????????this.money?=?money;
????}
}
編寫 AccountDao 接口和實(shí)現(xiàn)類
public?interface?AccountDao?{????List?findAll();
????Account?findById(Integer?id);
????void?save(Account?account);
????void?update(Account?account);
????void?delete(Integer?id);
}
public?class?AccountDaoImpl?implements?AccountDao?{
????private?QueryRunner?queryRunner;
????public?void?setQueryRunner(QueryRunner?queryRunner)?{
????????this.queryRunner?=?queryRunner;
????}
????@Override
????public?List?findAll()?{
????????List?list?=?null;//?編寫?sql
????????String?sql?=?"select?*?from?account";try?{//?執(zhí)行?sql
????????????list?=?queryRunner.query(sql,?new?BeanListHandler(Account.class));
????????}?catch?(SQLException?e)?{
????????????e.printStackTrace();
????????}return?list;
????}@Overridepublic?Account?findById(Integer?id)?{
????????Account?query?=?null;//?編寫?sql
????????String?sql?=?"select?*?from?account?where?id?=??";try?{
????????????query?=?queryRunner.query(sql,?new?BeanHandler(Account.class),?id);
????????}?catch?(SQLException?e)?{
????????????e.printStackTrace();
????????}return?query;
????}@Overridepublic?void?save(Account?account)?{
????????String?sql?=?"insert?into?account?values(null,??,??)";try?{
????????????queryRunner.update(sql,?account.getName(),?account.getMoney());
????????}?catch?(SQLException?e)?{
????????????e.printStackTrace();
????????}
????}@Overridepublic?void?update(Account?account)?{
????????String?sql?=?"update?`account`?set?`name`?=??,?`money`?=???where?`id`?=??";try?{
????????????queryRunner.update(sql,?account.getName(),?account.getMoney(),?account.getId());
????????}?catch?(SQLException?e)?{
????????????e.printStackTrace();
????????}
????}@Overridepublic?void?delete(Integer?id)?{
????????String?sql?=?"delete?from?`account`?where?`id`?=??";try?{
????????????queryRunner.update(sql,?id);
????????}?catch?(SQLException?e)?{
????????????e.printStackTrace();
????????}
????}
}
編寫 AccountService 接口和實(shí)現(xiàn)類
public?interface?AccountService?{????List?findAll();
????Account?findById(Integer?id);
????void?save(Account?account);
????void?update(Account?account);
????void?delete(Integer?id);
}
public?class?AccountServiceImpl?implements?AccountService?{
????private?AccountDao?accountDao;
????public?void?setAccountDao(AccountDao?accountDao)?{
????????this.accountDao?=?accountDao;
????}
????@Override
????public?List?findAll()?{
????????return?accountDao.findAll();
????}
????@Override
????public?Account?findById(Integer?id)?{
????????return?accountDao.findById(id);
????}
????@Override
????public?void?save(Account?account)?{
????????accountDao.save(account);
????}
????@Override
????public?void?update(Account?account)?{
????????accountDao.update(account);
????}
????@Override
????public?void?delete(Integer?id)?{
????????accountDao.delete(id);
????}
}
編寫 spring 核心配置文件
applicationContext.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"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
">
????
????<bean?id="dataSource"?class="com.alibaba.druid.pool.DruidDataSource">
????????<property?name="driverClassName"?value="com.mysql.jdbc.Driver"/>
????????<property?name="url"?value="jdbc:mysql:///spring_db?characterEncoding=utf8&useSSL=false"/>
????????<property?name="username"?value="root"/>
????????<property?name="password"?value="password"/>
????bean>
????
????<bean?id="queryRunner"?class="org.apache.commons.dbutils.QueryRunner">
????????<constructor-arg?name="ds"?ref="dataSource"/>
????bean>
????
????<bean?id="accountDao"?class="com.renda.dao.impl.AccountDaoImpl">
????????<property?name="queryRunner"?ref="queryRunner"/>
????bean>
????
????<bean?id="accountService"?class="com.renda.service.impl.AccountServiceImpl">
????????<property?name="accountDao"?ref="accountDao"/>
????bean>
beans>
編寫測試代碼
public?class?AccountServiceTest?{????ClassPathXmlApplicationContext?applicationContext?=?new?ClassPathXmlApplicationContext("applicationContext.xml");
????AccountService?accountService?=?(AccountService)?applicationContext.getBean("accountService");
????//?測試添加
????@Test
????public?void?testSave(){
????????Account?account?=?new?Account();
????????account.setName("renda");
????????account.setMoney(888d);
????????accountService.save(account);
????}
????//?測試查詢
????@Test
????public?void?testFindById(){
????????Account?account?=?accountService.findById(3);
????????System.out.println(account);
????}
????//?測試查詢所有
????@Test
????public?void?testFindAll(){
????????List?all?=?accountService.findAll();for?(Account?account?:?all)?{
????????????System.out.println(account);
????????}
????}//?測試更新@Testpublic?void?testUpdate(){
????????Account?account?=?new?Account();
????????account.setId(3);
????????account.setName("Blair");
????????account.setMoney(2000d);
????????accountService.update(account);
????}//?測試刪除@Testpublic?void?testDelete(){
????????accountService.delete(3);
????}
}
抽取 JDBC 配置文件
applicationContext.xml 加載 jdbc.properties 配置文件獲得連接信息。
首先,需要引入 context 命名空間和約束路徑:
????xmlns:context="http://www.springframework.org/schema/context"
*?約束路徑:
????http://www.springframework.org/schema/context?
????http://www.springframework.org/schema/context/spring-context.xsd
<context:property-placeholder?location="classpath:jdbc.properties"/>
<bean?id="dataSource"?class="com.alibaba.druid.pool.DruidDataSource">
????<property?name="driverClassName"?value="${jdbc.driverClassName}"/>
????<property?name="url"?value="${jdbc.url}"/>
????<property?name="username"?value="${jdbc.username}"/>
????<property?name="password"?value="${jdbc.password}"/>
bean>
小結(jié)
*?DataSource?的創(chuàng)建權(quán)交由?Spring?容器去完成*?QueryRunner?的創(chuàng)建權(quán)交由?Spring?容器去完成,使用構(gòu)造方法傳遞?DataSource
*?Spring?容器加載?properties?文件????
<context:property-placeholder?location="xx.properties"/>
<property?name=""?value="${key}"/>
Spring 注解開發(fā)
Spring 是輕代碼而重配置的框架,配置比較繁重,影響開發(fā)效率,所以注解開發(fā)是一種趨勢,注解代替 xml 配置文件可以簡化配置,提高開發(fā)效率。
Spring 常用注解
介紹
Spring 常用注解主要是替代 的配置
@Component - 使用在類上用于實(shí)例化 Bean
@Controller - 使用在 web 層類上用于實(shí)例化 Bean
@Service - 使用在 service 層類上用于實(shí)例化 Bean
@Repository - 使用在 dao 層類上用于實(shí)例化 Bean
@Autowired - 使用在字段上用于根據(jù)類型依賴注入;當(dāng)使用注解注入屬性時(shí),set 方法可以省略
@Qualifier - 結(jié)合 @Autowired 一起使用,根據(jù)名稱進(jìn)行依賴注入;在自動按照類型注入基礎(chǔ)之上,再按照 Bean 的 id 注入;它給字段注入時(shí)必須和 @Autowired 一起使用,但是給方法參數(shù)注入時(shí)可以獨(dú)立使用
@Resource - 相當(dāng)于 @Autowired + @Qualifier,按照名稱進(jìn)行注入
@Value - 注入普通屬性
@Scope - 標(biāo)注 Bean 的作用范圍
@PostConstruct - 使用在方法上標(biāo)注該方法是 Bean 的初始化方法
@PreDestroy - 使用在方法上標(biāo)注該方法是 Bean 的銷毀方法
說明:JDK 11 以后完全移除了 javax 擴(kuò)展導(dǎo)致不能使用 @resource 注解,如果要使用它需要在 Maven 引入依賴:
<dependency>????<groupId>javax.annotationgroupId>
????<artifactId>javax.annotation-apiartifactId>
????<version>1.3.2version>
dependency>
注意:使用注解進(jìn)行開發(fā)時(shí),需要在 applicationContext.xml 中配置組件掃描,作用是指定哪個(gè)包及其子包下的 Bean 需要進(jìn)行掃描以便識別使用注解配置的類、字段和方法。
<context:component-scan?base-package="com.renda">context:component-scan>
實(shí)現(xiàn)
Bean 實(shí)例化(IOC)
<bean?id="userDao1"?class="com.renda.dao.impl.UserDaoImpl">bean>使用 @Component 或 @Repository 標(biāo)識 UserDaoImpl 需要 Spring 進(jìn)行實(shí)例化。
//?@Component(value?=?"userDao")@Repository?//?如果沒有寫?value?屬性值,Bean?的?id?為:類名首字母小寫
public?class?UserDaoImpl?implements?UserDao?{
????...
}
屬性依賴注入(DI)
<bean?id="userService"?class="com.lagou.service.impl.UserServiceImpl">????<property?name="userDao"?ref="userDao1"/>
bean>
使用 @Autowired 或者 @Autowired + @Qulifier 或者 @Resource 進(jìn)行 userDao 的注入
@Servicepublic?class?UserServiceImpl?implements?UserService?{
????@Autowired
????//?@Qualifier("userDao1")
????//?@Resource(name?=?"userDao1")
????private?UserDao?userDao;
????public?void?setUserDao(UserDao?userDao)?{
????????this.uDao?=?userDao;
????}
}
`@Value`
使用 @Value 進(jìn)行字符串的注入,結(jié)合 SpEL (Spring Expression Language) 表達(dá)式獲得配置參數(shù)
@Servicepublic?class?UserServiceImpl?implements?UserService?{
????@Value("注入普通數(shù)據(jù)")
????private?String?str;
????@Value("${jdbc.driver}")
????private?String?driver;
}
`@Scope`
<bean?scope=""/>使用 @Scope 標(biāo)注 Bean 的范圍
@Service@Scope("singleton")
public?class?UserServiceImpl?implements?UserService?{
????...
}
`Bean` 生命周期
<bean?init-method="init"?destroy-method="destory"?/>使用 @PostConstruct 標(biāo)注初始化方法,使用 @PreDestroy 標(biāo)注銷毀方法
@PostConstructpublic?void?init(){
????System.out.println("初始化方法....");
}
@PreDestroy
public?void?destroy(){
????System.out.println("銷毀方法.....");
}
Spring 常用注解整合 `DbUtils`
步驟分析:
拷貝 xml 配置項(xiàng)目,改為注解配置項(xiàng)目
修改 AccountDaoImpl 實(shí)現(xiàn)類
修改 AccountServiceImpl 實(shí)現(xiàn)類
修改 Spring 核心配置文件
編寫測試代碼
修改 `AccountDaoImpl` 實(shí)現(xiàn)類
@Repositorypublic?class?AccountDaoImpl?implements?AccountDao?{
????@Autowired
????private?QueryRunner?queryRunner;
????...
}
修改 `AccountServiceImpl` 實(shí)現(xiàn)類
@Service(value?=?"accountService")public?class?AccountServiceImpl?implements?AccountService?{
????@Autowired
????private?AccountDao?accountDao;
????...
}
修改 spring 核心配置文件
<?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:component-scan?base-package="com.renda"/>
????
????<context:property-placeholder?location="classpath:jdbc.properties"/>
????
????<bean?id="dataSource"?class="com.alibaba.druid.pool.DruidDataSource">
????????<property?name="driverClassName"?value="${jdbc.driverClassName}"/>
????????<property?name="url"?value="${jdbc.url}"/>
????????<property?name="username"?value="${jdbc.username}"/>
????????<property?name="password"?value="${jdbc.password}"/>
????bean>
????
????<bean?id="queryRunner"?class="org.apache.commons.dbutils.QueryRunner">
????????<constructor-arg?name="ds"?ref="dataSource"/>
????bean>
beans>
Spring 新注解
使用上面的注解還不能全部替代 xml 配置文件,還需要使用注解替代的配置如下:
非自定義的?Bean?的配置:<bean>加載?properties?文件的配置:<context:property-placeholder>
組件掃描的配置:<context:component-scan>
引入其他文件:<import>
@Configuration - 用于指定當(dāng)前類是一個(gè) Spring 配置類,當(dāng)創(chuàng)建容器時(shí)會從該類上加載注解
@Bean - 使用在方法上,標(biāo)注將該方法的返回值存儲到 Spring 容器中
@PropertySource - 用于加載 properties 文件中的配置
@ComponentScan - 用于指定 Spring 在初始化容器時(shí)要掃描的包
@Import - 用于導(dǎo)入其他配置類
Spring 純注解整合 `DbUtils`
步驟分析:
編寫 Spring 核心配置類
編寫數(shù)據(jù)庫配置信息類
編寫測試代碼
編寫 Spring 核心配置類
@Configuration@ComponentScan("com.renda")
@Import(DataSourceConfig.class)
public?class?SpringConfig?{
????@Bean("queryRunner")
????public?QueryRunner?getQueryRunner(@Autowired?DataSource?dataSource){
????????return?new?QueryRunner(dataSource);
????}
}
編寫數(shù)據(jù)庫配置信息類
@PropertySource("classpath:jdbc.properties")public?class?DataSourceConfig?{
????@Value("${jdbc.driverClassName}")
????private?String?driver;
????@Value("${jdbc.url}")
????private?String?url;
????@Value("${jdbc.username}")
????private?String?username;
????@Value("${jdbc.password}")
????private?String?password;
????@Bean("dataSource")
????public?DataSource?getDataSource(){
????????DruidDataSource?druidDataSource?=?new?DruidDataSource();
????????druidDataSource.setDriverClassName(driver);
????????druidDataSource.setUrl(url);
????????druidDataSource.setUsername(username);
????????druidDataSource.setPassword(password);
????????return?druidDataSource;
????}
}
編寫測試代碼
public?class?AccountServiceTest?{????/*?ClassPathXmlApplicationContext?applicationContext?=?new?ClassPathXmlApplicationContext("com/renda/service/applicationContext.xml");
????AccountService?accountService?=?(AccountService)?applicationContext.getBean("accountService");?*/
????//?當(dāng)前改成了純注解形式
????AnnotationConfigApplicationContext?applicationContext?=?new?AnnotationConfigApplicationContext(SpringConfig.class);
????AccountService?accountService?=?(AccountService)?applicationContext.getBean("accountService");
????...
}
Spring 整合 Junit
普通 Junit 測試問題
在普通的測試類中,需要開發(fā)者手動加載配置文件并創(chuàng)建 Spring 容器,然后通過 Spring 相關(guān) API 獲得 Bean 實(shí)例;如果不這么做,那么無法從容器中獲得對象。
開發(fā)者可以讓 Spring Junit 負(fù)責(zé)創(chuàng)建 Spring 容器來簡化這個(gè)操作,直接在測試類注入 Bean 實(shí)例;但是需要將配置文件的名稱告訴它。
Spring 整合 Junit
步驟分析:
導(dǎo)入 spring 集成 Junit 的坐標(biāo)
使用 @Runwith 注解替換原來的運(yùn)行器
使用 @ContextConfiguration 指定配置文件或配置類
使用 @Autowired 注入需要測試的對象
創(chuàng)建測試方法進(jìn)行測試
導(dǎo)入 spring 集成 Junit 的坐標(biāo)
<dependency>????<groupId>org.springframeworkgroupId>
????<artifactId>spring-testartifactId>
????<version>5.1.5.RELEASEversion>
dependency>
<dependency>
????<groupId>junitgroupId>
????<artifactId>junitartifactId>
????<version>4.12version>
dependency>
使用 `@Runwith` 注解替換原來的運(yùn)行器
@RunWith(SpringJUnit4ClassRunner.class)public?class?AccountServiceTest?{
????...
}
使用 `@ContextConfiguration` 指定配置文件或配置類
@RunWith(SpringJUnit4ClassRunner.class)//?@ContextConfiguration(value?=?{"classpath:applicationContext.xml"})
@ContextConfiguration(classes?=?{SpringConfig.class})
public?class?AccountServiceTest?{
?????...???
}
使用 `@Autowired` 注入需要測試的對象
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes?=?{SpringConfig.class})
public?class?AccountServiceTest?{
????@Autowired
????private?AccountService?accountService;
????...???
}
總結(jié)
以上是生活随笔為你收集整理的控制反转_Spring:IOC 控制反转的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android模拟器上传,电脑文件怎么传
- 下一篇: ios13 无法传参_Win版iOS13