Spring淺入淺出——不吹牛逼不裝逼
前言:
今天決定要開始總結架構了,雖然以前總結過兩篇,但是思維是變化的,而且也沒有什麼規定說總結過的東西就不能再總結了,是吧。這次總結我命名為淺入淺出,主要在于了解架構核心,輕松愉快使用架構。
核心思想
我們都學了面向對象,在生活中,當人們需要一件東西時,第一反應就是找東西,例如想吃面包,現在有兩種情況,第一種是沒有面包店,第二種是有面包店。第一種情況就是我們之前一直遇到的情況,在沒有面包店的情況下,最直覺的做法可能就是你按照自己的口味制作面包,也就是一個面包需要主動制作,誰想吃了就自己New。而我主要說的是第二種情況,就是有面包店,你想吃面包的時候找到面包店,把自己的口味告訴店家,店家就可以給你做符合你口味的面包了。注意:你并沒有制作面包,而是由店家制作,但是完全符合你的口味。
這是一個很生活的例子,大家都明白,但這裡包含了Spring中很重要的思想——控制反轉,就是把制作面包的主動權交給店家,面包就是對象,店家相當于一個大容器,你想要什麼對象,就讓大容器去給你生産,這就是控制反轉思想。
再詳細點,當某個Java對象(調用者,例如你)需要調用另一個Java對象(被調用者,即被依賴對象,例如面包)時,在傳統程式設計模式下,調用者通常會采用“New 被調用者”的代碼方式來建立對象(例如你自己制作面包)。這種方式會增加調用者與被調用者之間的耦合性,不利于後期代碼的更新和維護。
當Spring架構出現後,對象的執行個體不再由調用者來建立,而是由 Spring容器(例如面包店)來建立。Spring容器會負責控制程式之間的關系(例如面包店負責控制你與面包的關系),而不是由調用者的程式代碼直接控制。這樣,控制權由調用者轉移到Spring容器,控制權發生了反轉,這就是Spring的控制反轉。
在之前,我們需要用構造方法或者set()方法給一些成員變量指派,從Spring容器角度來看,Spring容器負責将被依賴對象指派給調用者的成員變量,相當于為調用者注入它所依賴的執行個體,這就是Spring的依賴注入。
綜上所述,控制反轉是一種通過描述(在Spring中可以是XML或注解)并通過第三方去産生或擷取特定對象的方式。在Spring中實作控制反轉的是IoC容器,其實作方法是依賴注入。
Spring IoC容器
看完上面所述,我們知道實作控制反轉的是Spring IoC容器。Spring IoC容器的設計主要是基于BeanFactory和ApplicationContext兩個接口。
先說BeanFactory,它提供了完整的IoC服務支援,是一個管理Bean的工廠,主要負責初始化各種Bean。BeanFactory接口有多個實作類,其中比較常用的是org.springframework.beans.factory.xml.XmlBeanFactory,該類會根據XML配置檔案中的定義來裝配Bean.由于BeanFactory執行個體加載Spring配置檔案在實際開發中并不多見,隻需了解即可,我也不過多解說了。
再說ApplicationContext,它是BeanFactory的子接口,也稱為應用上下文,ApplicationContext接口除了包含BeanFactory的所有功能以外,還添加了對國際化、資源通路、事件傳播等内容的支援。建立ApplicationContext接口執行個體通常有三種方法:
1、 通過ClassPathXmlApplicationContext建立
2、 通過FileSystemXmlApplicatonContext建立
3、 通過Web伺服器執行個體化ApplicationContext容器
作為一個初學者,我覺得先會用第一種就可以了,是以我主要解說第一種,别的等你自己入門後自己看,我隻做引導。
ClassPathXmlApplicationContext将從類路徑目錄(src根目錄)中尋找指定的XML配置檔案,如下代碼:
public class Test {
public static void main(String[] args) {
//初始化SPring容器,加載配置檔案
ApplicationContext appCon = new ClassPathXmlApplicationContext("spring-config.xml");
//通過容器獲得test執行個體
TestDao tt = (TestDao) appCon.getBean("test");
tt.sayHello();
}
}
複制
依賴注入的類型
在Spring中實作IoC容器的方法是依賴注入,依賴注入的作用是在使用Spring架構建立對象時動态地将其所依賴的對象(例如屬性值)注入Bean元件中,Spring架構的依賴注入通常有兩種實作方式,一種是使用構造方法注入,另一種是使用屬性的setter方法注入。具體且看執行個體示範
執行個體示範
一、在pom.xml中導入相應子產品
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<!--spring核心依賴-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
</dependencies>
複制
二、建立TestDao
package com.my.dao;
public interface TestDao {
public void sayHello();
}
複制
三、建立TestDaoImpl
package com.my.dao.impl;
import com.my.dao.TestDao;
public class TestDaoImpl implements TestDao {
@Override
public void sayHello() {
System.out.println("Hello Spring!!!");
}
}
複制
四、建立spring-config.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"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
">
<bean id="testDIDao" class="com.my.dao.impl.TestDaoImpl"/>
</beans>
複制
五、測試Test
package com.my.test;
import com.my.dao.TestDao;
import com.my.dao.impl.TestDaoImpl;
import com.my.service.TestService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
//調用者自己建立對象
TestDao testDao = new TestDaoImpl();
testDao.sayHello();
//初始化SPring容器,加載配置檔案
ApplicationContext appCon = new ClassPathXmlApplicationContext("spring-config.xml");
//通過容器獲得test執行個體
TestDao tt = (TestDao) appCon.getBean("testDIDao");
tt.sayHello();
}
}
複制
六、測試結果
七、建立TestService
package com.my.service;
public interface TestService {
public void sayHello();
}
複制
八、建立TestServiceImpl
package com.my.service.impl;
import com.my.dao.TestDao;
import com.my.service.TestService;
public class TestServiceImpl implements TestService {
private TestDao testDao;
//構造方法,用于實作依賴注入接口對象TestDao
public TestServiceImpl(TestDao testDao) {
this.testDao = testDao;
}
@Override
public void sayHello() {
testDao.sayHello();
}
}
複制
九、在spring-config.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"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
">
<!--将指定類TestDaoImpl配置給Spring,讓Spring建立其執行個體-->
<bean id="testDIDao" class="com.my.dao.impl.TestDaoImpl"/>
<!--使用構造方法注入-->
<bean id="testDIService" class="com.my.service.impl.TestServiceImpl" >
<!--将TestDIDao注入到TestDIServiceImpl類的屬性testDao上-->
<constructor-arg index="0" ref="testDIDao"/>
</bean>
</beans>
複制
十、測試Test
package com.my.test;
import com.my.dao.TestDao;
import com.my.dao.impl.TestDaoImpl;
import com.my.service.TestService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
//調用者自己建立對象
TestDao testDao = new TestDaoImpl();
testDao.sayHello();
//初始化SPring容器,加載配置檔案
ApplicationContext appCon = new ClassPathXmlApplicationContext("spring-config.xml");
//通過容器獲得test執行個體
TestDao tt = (TestDao) appCon.getBean("testDIDao");
tt.sayHello();
//通過容器擷取TestService執行個體,測試構造方法注入
TestService testService =(TestService) appCon.getBean("testDIService");
testService.sayHello();
}
}
複制
十一、測試結果
十二、使用屬性的setter方法注入
package com.my.service.impl;
import com.my.dao.TestDao;
import com.my.service.TestService;
public class TestServiceImpl implements TestService {
private TestDao testDao;
//添加testDao屬性的setter方法,用于實作依賴注入
public void setTestDao(TestDao testDao){
this.testDao=testDao;
}
@Override
public void sayHello() {
testDao.sayHello();
}
}
複制
十三、在spring-config.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"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
">
<!--将指定類TestDaoImpl配置給Spring,讓Spring建立其執行個體-->
<bean id="testDIDao" class="com.my.dao.impl.TestDaoImpl"/>
<!--使用setter方法注入-->
<bean id="testDIService" class="com.my.service.impl.TestServiceImpl">
<!--調用TestDIServiceImpl類的setter方法,将TestDao注入到TestServiceImpl類的屬性testDao上-->
<property name="testDao" ref="testDIDao"></property>
</bean>
</beans>
複制
十四、測試Test
package com.my.test;
import com.my.dao.TestDao;
import com.my.dao.impl.TestDaoImpl;
import com.my.service.TestService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
//調用者自己建立對象
TestDao testDao = new TestDaoImpl();
testDao.sayHello();
//初始化SPring容器,加載配置檔案
ApplicationContext appCon = new ClassPathXmlApplicationContext("spring-config.xml");
//通過容器獲得test執行個體
TestDao tt = (TestDao) appCon.getBean("testDIDao");
tt.sayHello();
//通過容器擷取TestService執行個體,測試setter方法注入
TestService testService =(TestService) appCon.getBean("testDIService");
testService.sayHello();
}
}
複制
十五、測試結果
注入說明
在Src根目錄下建立Spring配置檔案spring-config.xml(檔案名随意,注意字尾.xml)。在配置檔案中,constructor-arg元素用于定義類構造方法的參數,index用于定義參數的位置,ref指定某個執行個體的引用,如果參數是常量值,ref由value代替。