Spring框架是什麼?
spring安裝本人的理解就是一艘航空母艦,其擁有很多不同的作戰系統以及武器也可以與其他軍事力量組裝成一個航母戰鬥羣。對應着我們的spring,其擁有從企業級到雲計算等各個方面的技術棧,如下圖所示:
Spring擁有很多項目有如:Spring Boot 、Spring Framework、Spring Cloud等等,這裏就不在一一介紹,感興趣的同學們可以去官方網站查詢和了解。
Spring框架又是Spring技術棧的核心,Spring框架的IOC與AOP編程方式大大簡化了Java企業級開發並極大提高了開發效率,並且Spring框架優秀的低浸入式降低了代碼耦合性以及其他優秀的框架的集成,這些都讓Spring框架成爲一個非常受歡迎的Java開發框架。
Spring框架常用模塊
一個經典的Spring模塊圖如下所示:
- Test
Spring Test通過Junit與TestNG實現集成測試與單元測試。 - Core
核心容器(Core Container)由 Spring Bean、Spring Core、Spring Context、Spring expression四個模塊組成。
- Spring Bean 與Spring Core
提供了控制反轉(IOC)與依賴注入(DI)管理Java Bean對象,其底層使用的Bean Factory複雜工廠進行實現,使創建的對象與實際程序依賴進行解偶。 - Spring Context
Context繼承Bean模塊特性,擁有事件傳播、上下文創建、資源加載等,其中Spring-Context-Support集成第三方優秀框架,以使它們可以集成Spring的上下文中。 - Spring Expression
是一種強大的表達式,可以用來操作和查詢對象圖中使用。
- AOP Aspects
Spring Aop提供面向切面編程實現。 - Data Access、Integration
數據訪問、集成模塊包含JDBC、ORM、OXM、JMS、Transition模塊。
- Spring JDBC提供了一套模版,使用其可以很方便操作數據庫。
- Spring ORM 爲流行的對象關係映射提供API,如JPA與Hibernate。
- Spring JMS 提供了消息集成模塊如:生產消息與消費消息等。
- Spring OXM 提供了一個支持對象到XML關係映射的功能。
- Web
此模塊由Spring Web 、Spring-Webmvc、Spring-WebSocket、Spring-Portlet等模塊組成。
- Spring web 提供了一套面向web開發的集成功能如Servlet容器監聽、web應用程序上下文等。
- Spring servlet也稱Spring webmvc主要集成了Spring的MVC模塊與REST服務等功能。
- Spring webSocket基於webScoket協議開發的應用程序。
IOC
Spring通過IOC容器管理Java Bean對象的創建以及其依賴。軟件開發中經常會有寫耦合性強的代碼,通過Spring IOC可以很好幫我解決這個問題。IOC的核心是DI,通過DI可以設置不同Java Bean組件的依賴項,並在其整個生命週期都能管理這些依賴項。這些原先需要程序親自創建並管理的工作交給了Spring容器實現,所以稱爲“控制反轉”,IOC實現有兩種方式:一是依賴注入,另一種就是依賴查找。
- 配置元數據
使用Spring管理Java Bean對象之前需要我們配置元數據,Spring可以通過XML配置,也可採用註解或者基於Java類的配置,下面將介紹使用XML配置Java Bean的元數據配置和使用。
實例化Bean對象的幾種方式
使用無參構造函數實例化對象
這裏我們使用Maven構建我們的Spring應用,其依賴POM文件內容如下:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>5.2.5.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--引入Spring依賴包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>
</dependencies>
<build>
<finalName>Spring-FramerWork</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
創建簡單類Student如下:
@Data
public class Student {
private String name;
private Integer age;
private String gender;
private String address;
public Student() {
}
public Student(String name, Integer age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
}
Spring元數據配置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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="student1" class="com.codegeek.day1.Student">
<property name="address" value="上海"/>
<property name="name" value="小明"/>
<property name="age" value="23"/>
<property name="gender" value="男"/>
</bean>
</beans>
上面的XML文件中,Id屬性是標記一個bean對象的唯一標誌,類似於我們生活中每個人對應的身份證一樣,class屬性定義Bean的類型也就是類的全路徑。property屬性對應Java Bean中的屬性名稱,而value就是對應Bean屬性名的值。
新建Spring測試類如下:
public class SpringTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student1 = applicationContext.getBean("student1", Student.class);
System.out.println(student1);
}
}
ApplicationContext是高級工廠接口,能維護不同的Bean及其依賴項。其提供的getBean方法可以獲取一個Bean的實例對象。運行結果顯示我們確實獲得了一個Student對象,而這個對象是由Spring容器爲我們創建的。
整個項目結構如下所示:
思考🤔幾個問題?
- Student類在容器中何時創建?
當我們對Java對象的構造器代碼進行修改如下所示:
- 無參構造器修改
public Student() {
System.out.println("Student.... 空參");
}
- 有參構造器修改
public Student(String name, Integer age, String address) {
System.out.println("Student.... 有參");
this.name = name;
this.age = age;
this.address = address;
}
- 屬性方法修改
public void setAddress(String address) {
System.out.println("address 被設置了");
this.address = address;
}
- 測試類修改
運行結果如下:
結論
我們發現我們並沒有從容器取Student對象,但是其無參構造器執行一次,然後調用對象的屬性setter方法。故可知在容器初始化時Spring就已經爲我們創建好了Java Bean對象。
- 容器獲取一個不存在的對象會有什麼結果?
- 測試類修改
運行測試類後控制檯輸出如下:
-結論
若嘗試在IOC容器中獲取不存在的對象容器將會報NoSuchBeanDefinitionException
。
- 根據類類型獲取對象需要注意什麼?
xml中新增配置如下:
<bean id="student2" class="com.codegeek.day1.Student">
<property name="address" value="上海"/>
<property name="name" value="小紅"/>
<property name="age" value="24"/>
<property name="gender" value="女"/>
</bean>
- 測試類代碼如下:
運行結果如下所示: - 結論
程序報了No qualifying bean of type 'com.codegeek.day1.Student' available: expected single matching bean but found 2
的異常,根據類型獲取Java Bean對象,需要滿足Bean對象在IOC容器中具有唯一定義要求。
使用有參構造函數實例化對象
Xml配置元數據如下所示:
測試類如下所示:
運行結果:
當Xml中value屬性值類型與有參構造函數參數類型一致時可以省略name屬性如下:
運行結果不變,但是這樣配置可能出現一些問題,新增Xml元數據配置如下所示:
<bean id="student4" class="com.codegeek.day1.Student">
<constructor-arg value="張三"/>
<constructor-arg value="23"/>
<constructor-arg value="男"/>
<constructor-arg value="北京"/>
</bean>
運行類如下:
運行結果如下所示:
我們發現運行結果屬性名對應的屬性值明顯不符合實際生活邏輯,故xml可以改進如下所示:
再次運行測試類運行結果,一起正常如下所示:
靜態工廠方法實例化對象
當採用靜態工廠方法創建Bean時,除了指定class類型之外,還需要指定其工廠方法,以便容器初始化調用此方法完成類的初始化。
定義Xml數據如下:
定義實體類如下:
public class InstanceFactory {
public static Phone instance(String brandName, Double price, String producePlace) {
return new Phone(brandName,price,producePlace);
}
public Phone getPhone(String brandName,Double price,String producePlace) {
return new Phone(brandName,price,producePlace);
}
}
使用工廠方法實例化對象
此種配置需設置factory-bean
屬性,而此屬性的值必須是在IOC容器配置的,Xml配置如下所示:
測試類代碼:
以上代碼可在 codegeekgao.git 下載查看,下一章將重點學習和了解IOC容器依賴注入方式學習。