Spring簡介
Spring 意爲 春天,指的是給軟件行業帶來春天。在2002 年,首次推出了Spring框架的雛形interface21框架。Spring框架以interface21框架爲基礎,經過重新設計,並不斷豐富其內涵,於2004年3月24日,發佈了1.0正式版。
Spring 是個Java企業級應用的開源開發框架。Spring主要用來開發Java應用,但是有些擴展是針對構建J2EE平臺的web應用。
Spring 框架目標是:簡化Java企業級應用開發,並通過pojo爲基礎的編程模型促進良好的編程習慣。
Spring理念是:使現有的技術更加容易使用,它整合了現有的技術框架。
有關Spring的網址:
官網:https://spring.io/projects/spring-framework#overview
官方下載地址: http://repo.spring.io/release/org/springframework/spring
GitHub:https://github.com/spring-projects/spring-framework
Spring的依賴:
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
Spring的優點:
- Spring是一個開源的免費的框架(容器),支持事務的處理,支持框架整合。
- Spring是一個輕量級的、非入侵式的框架,基本的版本大約2MB。
- 控制反轉(IOC),Spring通過控制反轉實現了鬆散耦合,對象們給出它們的依賴,而不是創建或查找依賴的對象們。
- 面向切面編程(AOP),Spring支持面向切面的編程,並且把應用業務邏輯和系統服務分開。
- 容器,Spring 包含並管理應用中對象的生命週期和配置。
- MVC框架,Spring的WEB框架是個精心設計的框架,是Web框架的一個很好的替代品。
- 事務管理,Spring 提供一個持續的事務管理接口,可以擴展到上至本地事務下至全局事務。
- 異常處理,Spring 提供方便的API把具體技術相關的異常轉化爲一致的unchecked 異常。
Spring就是一個輕量級的控制反轉(IOC) 和麪向切面編程(AOP)的框架
Spring的組成:
IOC
IOC思想
搭建環境並測試:
- 編寫User實體類
- 編寫UserMapper接口
- 編寫UserMapperImpl實現類
- 編寫UserService業務接口
- 編寫UserServiceImpl 業務實現類
- 編寫測試類
在業務中,用戶的需求可能會發生改變,此時我們的代碼就需要對應地進行修改。如果程序的代碼量很大的話,修改一次的成本代價則會什麼昂貴。
在業務層處理時,是由程序員創建對象的,可以說主動權在程序員手中,程序員決定了程序調用什麼。
但是當使用一個set方法時,會發生革命性的變化。
利用set可以動態地實現值的注入。
對比:
- 沒使用set之前,程序是主動創建對象,控制權掌握在程序員手中。
- 使用set注入後,程序不再具有主動性,而是被動地接受對象。
動態的注入這種思想,從本質上解決了問題,我們不用管對象的創建了,同時系統的耦合性大大降低了。我們可以更加專注地在業務的實現上,這就是IOC 的原型。
IOC本質
IOC(Inverse of Control),控制反轉,是一種設計思想;DI(Dependency Injection),依賴注入則是顯示IOC的一種方法。在沒有IOC的程序中,我們使用面向對象編程,對象的創建和對象間的依賴關係完全硬編碼在程序中,對象的創建由程序自己控制,控制反轉後則將對象的創建轉移給第三方,所謂控制反轉可以理解爲:獲得依賴對象的方式反轉了。
採用xml方式配置bean的時候,bean的定義信息是和實現分離的,而採用註解的方式可以把兩者合爲一體,bean的定義信息直接以註解的形式定義在實現類中,從而達到了零配置的目的。
控制反轉是一種通過描述(XML或註解)並通過第三方去生產或獲取特定對象的方式。在Spring中實現控制反轉的是IoC容器,其實現方法是依賴注入(Dependency Injection,DI)。
第一個Spring程序
1. 導入Spring相關的jar包
Spring需要導入commons-logging進行日誌記錄 。我們使用maven , 他會自動下載對應的依賴項。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
2. 編寫相關的代碼
編寫一個Hello實體類
package com.llx.pojo;
public class Hello {
private String name;
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("Hello,"+name);
}
}
編寫我們的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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd ">
<bean id="hello" name="hello2 hello3 hello4" class="com.llx.pojo.Hello">
<property name="name" value="Spring"/>
</bean>
</beans>
測試
@Test
public void testHello(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Hello hello = (Hello) context.getBean("hello");
hello.show();
}
進行測試完之後,我們可以理解:
- Hello對象是由Spring創建的
- Hello對象的屬性是有Spring容器設置的
這個過程就叫做控制反轉。
控制:誰來控制對象的創建?傳統應用程序的對象是由程序本身控制創建的;使用Spring後,對象則是由Spring來創建的。
反轉:程序本身不創建對象,而變成被動地接受對象。
依賴注入:利用set方法來進行注入。
IOC是一種編程思想,由主動編程變爲被動接受。
理解了IOC之後,我們可以徹底不用再去程序中進行改動了,要實現不同的操作,只需要在xml配置文件中進行修改。所謂的IOC,即 對象由Spring來創建,管理和裝配。
IOC創建對象的方式
使用無參構造創建對象
可以使用無參構造創建對象,這是默認的方式。
使用有參構造創建對象
如果要使用有參構造來創建對象,有以下幾種方式:
-
下標賦值
<!--第一種,下標賦值!--> <bean id="user" class="com.llx.pojo.User"> <constructor-arg index="0" value="llx"/> </bean>
-
類型
<!--第二種方式:通過類型創建,不建議使用!--> <bean id="user" class="com.llx.pojo.User"> <constructor-arg type="java.lang.String" value="LLX"/> </bean>
-
參數名
<!--第三種,直接通過參數名來設置--> <bean id="user" class="com.kuang.pojo.User"> <constructor-arg name="name" value="LLX1"/> </bean>
在配置文件加載的時候,容器中管理的對象就已經初始化了!
Spring配置
別名
對對象設置別名,設置別名後,也可以通過別名獲取到這個對象。
<alias name="user" alias="userNew"/>
Bean的配置
bean標籤 中有幾個常用的屬性:
屬性 | 含義 |
---|---|
id | id是bean的唯一標識符,即相當於我們學的對象名 |
class | class是bean對象所對應的全限定名即 包名+類名 |
name | name是別名,而且name可以同時取多個別名 |
<bean id="hello" name="hello2 hello3 hello4" class="com.llx.pojo.Hello">
<property name="name" value="Spring"/>
</bean>
import
import,一般用於團隊開發,可以將多個配置文件導入合併爲一個。
將多個配置文件,使用import標籤,導入在applicationContext.xml中即可。
<import resource="user.xml"/>
<import resource="hello.xml"/>
<import resource="bean.xml"/>
在使用的時候,使用總的配置文件applicationContext.xml即可。
依賴注入
依賴注入的方式有好幾種:
- 構造器注入
- set方式注入
- p命令空間和c命令空間
set方式注入
set注入:
- 依賴:bean對象的創建依賴於容器
- 注入:bean對象中的所有屬性,由容器來注入
環境搭建
1、編寫一個Address類,複雜類型:
package com.llx.pojo;
public class Address {
private String address;
private com.llx.pojo.Student student;
public void setAddress(String address) {
this.address = address;
}
public String getAddress() {
return address;
}
}
2、編寫Student類,真實測試對象
package com.llx.pojo;
import java.util.*;
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> list;
private Map<String,String> map;
private Set<String> set;
private String wife ;// null
private Properties info;
public void setName(String name) {
this.name = name;
}
public void setAddress(Address address) {
this.address = address;
}
public void setBooks(String[] books) {
this.books = books;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
public void setSet(Set<String> set) {
this.set = set;
}
public void setWife(String wife) {
this.wife = wife;
}
public void setInfo(Properties info) {
this.info = info;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", address=" + address.getAddress() +
", books=" + Arrays.toString(books) +
", list=" + list +
", map=" + map +
", set=" + set +
", wife='" + wife + '\'' +
", info=" + info +
'}';
}
}
3、編寫student.xml配置文件,並將其導入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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="student" class="com.llx.pojo.Student">
<property name="name" value="llx"/>
</bean>
</beans>
4、測試類
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = (Student) context.getBean("student");
System.out.println(student.getName());
}
}
完整的注入信息如下:
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="addr" class="com.llx.pojo.Address">
<property name="address" value="西安"/>
</bean>
<bean id="student" class="com.llx.pojo.Student" scope="singleton">
<!--第一種,普通值注入,value-->
<property name="name" value="llx"/>
<!--第二種,Bean注入,ref-->
<property name="address" ref="addr"/>
<!--數組-->
<property name="books">
<array>
<value>西遊記</value>
<value>紅樓夢</value>
<value>水滸傳</value>
</array>
</property>
<!--List-->
<property name="list">
<list>
<value>list1</value>
<value>list2</value>
<value>list3</value>
</list>
</property>
<!--Map-->
<property name="map">
<map>
<entry key="key1" value="v1"/>
<entry key="key2" value="v2"/>
<entry key="key3" value="v3"/>
</map>
</property>
<!--Set-->
<property name="set">
<set>
<value>set1</value>
<value>set2</value>
<value>set3</value>
</set>
</property>
<!--null-->
<property name="wife">
<null/>
</property>
<!--Properties-->
<property name="info">
<props>
<prop key="id">122</prop>
<prop key="name">llx</prop>
<prop key="sex">female</prop>
</props>
</property>
</bean>
</beans>
拓展方式注入
可以使用 p命名空間和c命名空間進行注入。
<?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"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--p命名空間注入,可以直接注入屬性的值:property-->
<bean id="user" class="com.llx.pojo.User" p:name="llx" p:age="20"/>
<!--c命名空間注入,通過構造器注入:construct-args-->
<bean id="user2" class="com.llx.pojo.User" c:age="20" c:name="llx2"/>
</beans>
測試:
@Test
public void test2(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = context.getBean("user2", User.class);
System.out.println(user);
}
需要注意的是,p命名和c命名空間不能直接使用,需要導入xml約束纔可以。
xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
bean的作用域
單例模式
單例模式是Spring的默認機制。
<bean id="student" class="com.llx.pojo.Student" scope="singleton">
<property name="name" value="劉麗俠"/>
</bean>
原型模式
原型模式,每次從容器中get的時候,都會產生一個新的對象
<bean id="student" class="com.llx.pojo.Student" scope="prototype">
<property name="name" value="劉麗俠"/>
</bean>
其餘的 request、session、application,這些只能在web開發中使用到。
Bean的自動裝配
自動裝配是Spring滿足bean依賴的一種方式。
Spring會在上下文中自動尋找,並自動給bean裝配屬性。
在Spring中有三中配置的方式:
- 在xml配置文件中顯式地配置
- 在java中顯式地配置
- 隱式地自動裝配
自動裝配有兩種方式:ByName和ByType。
測試環境搭建:
以一個人有貓和狗兩個寵物爲例。
1、編寫實體類:
Cat類
package com.llx.entity;
public class Cat {
public void shout(){
System.out.println("miao ~");
}
}
Dog類
package com.llx.entity;
public class Dog {
public void shout(){
System.out.println("wang ~");
}
}
User類
package com.llx.entity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import javax.annotation.Resource;
public class User {
private String name;
private Cat cat;
private Dog dog;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
@Override
public String toString() {
dog.shout();
cat.shout();
return "User{" +
"name='" + name + '\'' +
", cat=" + cat +
", dog=" + dog +
'}';
}
}
2、編寫user.xml文件,並導入到applicationContext.xml中
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="cat" class="com.llx.entity.Cat"/>
<bean id="dog" class="com.llx.entity.Dog"/>
<bean id="user" class="com.llx.entity.User">
<property name="cat" ref="cat"/>
<property name="dog" ref="dog"/>
<property name="name" value="llx"/>
</bean>
</beans>
3、編寫測試類
@Test
public void test4(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) context.getBean("user");
System.out.println(user.toString());
}
ByName自動裝配
設置bean的autowire屬性爲byName。
byName:會自動在容器上下文中查找,和自己對象set方法後面的值對應的bean id。
<bean id="cat" class="com.llx.entity.Cat"/>
<bean id="dog" class="com.llx.entity.Dog"/>
<bean id="user" class="com.llx.entity.User" autowire="byName">
<property name="name" value="llx"/>
</bean>
ByType自動匹配
設置bean的autowire屬性爲byType。
byType:會自動在容器上下文中查找,和自己對象屬性類型相同的bean
<bean id="cat" class="com.llx.entity.Cat"/>
<bean id="dog" class="com.llx.entity.Dog"/>
<bean id="user" class="com.llx.entity.User" autowire="byType">
<property name="name" value="llx"/>
</bean>
總結:
- 使用byname的時候,需要保證所有bean的id唯一,並且這個bean需要和自動注入的屬性的set方法的值一致!
- 使用bytype的時候,需要保證所有bean的class唯一,並且這個bean需要和自動注入的屬性的類型一致!
使用註解實現自動裝配
使用註解的時候,需要導入約束(context約束);配置註解的支持<context:annotation-config/>
。
在xml文件中配置<context:annotation-config/>
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
</beans>
@Autowired註解
@Autowired註解可以直接在屬性上使用,也可以在set方法是使用。
@Autowired 通過byType的方式實現。
使用@Autowired註解,我們可以不用編寫set方法,但是前提是自動裝配的屬性在 IOC(Spring)容器中存在,且符合名字byname。
package com.llx.entity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import javax.annotation.Resource;
public class User {
private String name;
@Autowired
private Cat cat;
@Autowired
private Dog dog;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Cat getCat() {
return cat;
}
public Dog getDog() {
return dog;
}
@Override
public String toString() {
dog.shout();
cat.shout();
return "User{" +
"name='" + name + '\'' +
", cat=" + cat +
", dog=" + dog +
'}';
}
}
如果顯示定義了Autowired的required屬性爲false,說明這個對象可以爲null,否則不允許爲空。
如果 @Autowired 自動裝配的環境比較複雜,自動裝配無法通過一個註解(@Autowired)完成的時候,我們可以使用@Qualifier(value=“xxx”)去配合@Autowired的使用,指定一個唯一的bean對象注入!
@Autowired
@Qualifier("dog1") // 匹配指定對象,若沒有,則會報紅
private Dog dog;
<bean id="dog1" class="com.llx.entity.Dog"/>
<bean id="dog2" class="com.llx.entity.Dog"/>
@Resource註解
@Resource註解是java的註解,作用同 Autowired 和 Qualifier。
@ Resource 默認通過byname的方式實現。
@Resource(name = "cat2") // java 的註解 配置 作用同 Autowired 和 Qualifier
private Cat cat;
@Resource 和@ Autowired 的區別:
- 兩者都是用來自動裝配的,都可以放在屬性字段上
- @ Autowired 通過byType的方式實現,而且必須要求這個對象存在! 【常用】
- @ Resource 默認通過byname的方式實現,如果找不到名字,則通過byType實現!如果兩個都找不到的情況下,就報錯! 【常用】
- 執行順序不同:@ Autowired 通過byType的方式實現。@ Resource 默認通過byname的方式實現。