spring介紹和優勢
Spring:Spring是分層的 Java SE/EE應用 full-stack 輕量級開源框架,以 IoC(Inverse Of Control:反轉控制)和 AOP(Aspect Oriented Programming:面向切面編程)爲內核,提供了展現層 SpringMVC 和持久層 Spring JDBC 以及業務層事務管理等衆多的企業級應用技術,還能整合開源世界衆多著名的第三方框架和類庫,逐漸成爲使用最多的Java EE 企業應用開源框架
- spring 的優勢:
- 方便解耦,簡化開發
通過 Spring提供的 IoC容器,可以將對象間的依賴關係交由 Spring進行控制,避免硬編碼所造成的過度程序耦合。用戶也不必再爲單例模式類、屬性文件解析等這些很底層的需求編寫代碼,可以更專注於上層的應用 - AOP編程的支持
- 通過 Spring的 AOP 功能,方便進行面向切面的編程,許多不容易用傳統OOP 實現的功能可以通過 AOP 輕鬆應付
- 聲明式事務的支持
可以將我們從單調煩悶的事務管理代碼中解脫出來,通過聲明式方式靈活的進行事務的管理,
提高開發效率和質量 - 方便程序的測試
可以用非容器依賴的編程方式進行幾乎所有的測試工作,測試不再是昂貴的操作,而是隨手可
做的事情 - 方便集成各種優秀框架
Spring可以降低各種框架的使用難度,提供了對各種優秀框架(Struts、Hibernate、Hessian、Quartz等)的直接支持 - 降低 JavaEE API 的使用難度
Spring對 JavaEE API(如 JDBC、JavaMail、遠程調用等)進行了薄薄的封裝層,使這些 API 的
使用難度大爲降低 - Java 源碼是經典學習範例
Spring的源代碼設計精妙、結構清晰、匠心獨用,處處體現着大師對Java 設計模式靈活運用以
及對 Java技術的高深造詣。它的源代碼無意是 Java 技術的最佳實踐的範例
- 方便解耦,簡化開發
spring體系結構
控制反轉(IOC)
工廠模式解耦:在實際開發中我們可以把三層的對象都使用配置文件配置起來,當啓動服務器應用加載的時候,讓一個類中的
方法通過讀取配置文件,把這些對象創建出來 並存起來。在接下來的使用的時候,直接拿過來用就好了。那麼,這個讀取配置文件,創建和獲取三層對象的類就是工廠
spring的控制反轉(IOC)
由於我們是很多對象,肯定要找個集合來存。這時候有 Map 和 List 供選擇。因爲有查找需求,所以選 Map,在應用加載時,創建一個 Map,用於存放三層對象。我們把這個 map 稱之爲 容器
工廠:工廠就是負責給我們從容器中獲取指定對象的類。這時候我們獲取對象的方式發生了改變
原來獲取對象:
我們在獲取對象時,都是採用 new 的方式。是主動的。如下圖
現在獲取對象:
我們獲取對象時,同時跟工廠要,有工廠爲我們查找或者創建對象。是被動的,如下圖,這種被動接收的方式獲取對象的思想就是控制反轉,它是 spring 框架的核心之一
使用spring的IOC解決程序耦合(xml方式)
- 準備 spring 的開發包
- 官網:http://spring.io/
- 下載地址:http://repo.springsource.org/libs-release-local/org/springframework/spring
特別說明:
我們使用的版本是 是 spring5.0.2,spring5 版本是用 jdk8 編寫的,所以要求我們的 jdk 版本是 8 及以上時 同時 tomcat 的版本要求 8.5 及以上 - 解壓:(Spring 目錄結構:)
docs :API 和開發規範
libs :jar 包和源碼.
schema :約束.
- 創建業務層接口和實現類
package com.company.dao;
/**
* 賬戶的持久層接口
*/
public interface IAccountDao {
/**
* 模擬保存賬戶
*/
void saveAccount();
}
package com.company.dao.impl;
import com.company.dao.IAccountDao;
/**
* 賬戶的持久層實現類
*/
public class AccountDaoImpl implements IAccountDao {
public void saveAccount(){
System.out.println("保存了賬戶");
}
}
- 創建持久層接口和實現類
package com.company.service;
/**
* 賬戶業務層的接口
*/
public interface IAccountService {
/**
* 模擬保存賬戶
*/
void saveAccount();
}
package com.company.service.impl;
import com.company.dao.IAccountDao;
import com.company.service.IAccountService;
/**
* 賬戶的業務層實現類
*/
public class AccountServiceImpl implements IAccountService {
private IAccountDao accountDao ;
public AccountServiceImpl(){
System.out.println("對象創建了");
}
public void saveAccount(){
accountDao.saveAccount();
}
}
- **拷貝必備的 jar 包到工程的 lib 目錄中,並在類的根路徑下創建的 一個任意名稱的 xml 文件,在xml中導入約束 **
bean.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">
</beans>
- 讓 spring管理資源 ,在配置文件中配置 service 和dao
<?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 標籤:用於配置讓 spring 創建對象,並且存入 ioc 容器之中
id 屬性:對象的唯一標識。
class 屬性:指定要創建對象的全限定類名
-->
<!-- 配置 service -->
<bean id="accountService" class="com.company.service.impl.AccountServiceImpl"></bean>
<!-- 配置 dao -->
<bean id="accountDao" class="com.company.dao.impl.AccountDaoImpl"></bean>
</beans>
- 測試 配置是否成功
package com.company.ui;
import com.company.dao.IAccountDao;
import com.company.service.IAccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Client {
public static void main(String[] args) {
//1.使用 ApplicationContext 接口,就是在獲取 spring 容器
ApplicationContext applicationContext= new ClassPathXmlApplicationContext("bean.xml");
//2.根據 bean 的 id 獲取對象
IAccountService iAccountService = (IAccountService) applicationContext.getBean("accountService");
System.out.println(iAccountService);
IAccountDao iAccountDao = (IAccountDao) applicationContext.getBean("accountDao");
System.out.println(iAccountDao);
}
}
spring 中工廠的類結構圖
- BeanFactory 和 和 ApplicationContext 的區別
BeanFactory 纔是 Spring 容器中的頂層接口。
ApplicationContext 是它的子接口。
BeanFactory 和 ApplicationContext 的區別:
創建對象的時間點不一樣。
ApplicationContext:只要一讀取配置文件,默認情況下就會創建對象。
BeanFactory:什麼使用什麼時候創建對象
- ApplicationContext 接口
ClassPathXmlApplicationContext :
它是從類的根路徑下加載配置文件 推薦使用這種
FileSystemXmlApplicationContext :
它是從磁盤路徑上加載配置文件,配置文件可以在磁盤的任意位置。
AnnotationConfigApplicationContext:
當我們使用註解配置容器對象時,需要使用此類來創建 spring 容器。它用來讀取註解
bean 標籤
作用:
用於配置對象讓 spring 來創建的。
默認情況下它調用的是類中的無參構造函數。如果沒有無參構造函數則不能創建成功。
屬性:
id:給對象在容器中提供一個唯一標識。用於獲取對象。
class:指定類的全限定類名。用於反射創建對象。默認情況下調用無參構造函數。
scope:指定對象的作用範圍。
* singleton :默認值,單例的.
* prototype :多例的.
* request :WEB 項目中,Spring 創建一個 Bean 的對象,將對象存入到 request 域中.
* session :WEB 項目中,Spring 創建一個 Bean 的對象,將對象存入到 session 域中.
* global session :WEB 項目中,應用在 Portlet 環境.如果沒有 Portlet 環境那麼
globalSession 相當於 session.
init-method:指定類中的初始化方法名稱。
destroy-method:指定類中銷燬方法名稱
bean 的作用範圍和生命週期
單例對象:scope="singleton"
一個應用只有一個對象的實例。它的作用範圍就是整個引用。
生命週期:
對象出生:當應用加載,創建容器時,對象就被創建了。
對象活着:只要容器在,對象一直活着。
對象死亡:當應用卸載,銷燬容器時,對象就被銷燬了。
多例對象:scope="prototype"
每次訪問對象時,都會重新創建對象實例。
生命週期:
對象出生:當使用對象時,創建新的對象實例。
對象活着:只要對象在使用中,就一直活着。
對象死亡:當對象長時間不用時,被 java 的垃圾回收器回收了
實例化 Bean 的三種方式
第一種方式:使用默認無參構造函數
<!--在默認情況下:
它會根據默認無參構造函數來創建類對象。如果 bean 中沒有默認無參構造函數,將會創建失敗-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"/>
第二種方式:spring 管理靜態工廠- 使用靜態工廠的方法創建對象
/**
* 模擬一個靜態工廠,創建業務層實現類
*/
public class StaticFactory {
public static IAccountService createAccountService(){
return new AccountServiceImpl();
}
}
<!-- 此種方式是:
使用 StaticFactory 類中的靜態方法 createAccountService 創建對象,並存入 spring 容器
id 屬性:指定 bean 的 id,用於從容器中獲取
class 屬性:指定靜態工廠的全限定類名
factory-method 屬性:指定生產對象的靜態方法
-->
<bean id="accountService"
class="com.itheima.factory.StaticFactory"
factory-method="createAccountService"></bean>
第三種方式:spring 管理實例工廠- 使用實例工廠的方法創建對象
/**
* 模擬一個實例工廠,創建業務層實現類
* 此工廠創建對象,必須現有工廠實例對象,再調用方法
*/
public class InstanceFactory {
public IAccountService createAccountService(){
return new AccountServiceImpl();
}
}
<!-- 此種方式是:
先把工廠的創建交給 spring 來管理。
然後在使用工廠的 bean 來調用裏面的方法
factory-bean 屬性:用於指定實例工廠 bean 的 id。
factory-method 屬性:用於指定實例工廠中創建對象的方法。
-->
<bean id="instancFactory" class="com.itheima.factory.InstanceFactory"></bean>
<bean id="accountService"
factory-bean="instancFactory"
factory-method="createAccountService"></bean>
spring 的依賴注入
- 構造函數注入
顧名思義,就是使用類中的構造函數,給成員變量賦值。注意,賦值的操作不是我們自己做的,而是通過配置
的方式,讓 spring 框架來爲我們注入。具體代碼如下:
/**
*/
public class AccountServiceImpl implements IAccountService {
//如果是經常變化的數據,並不適用於注入的方式
private String name;
private Integer age;
private Date birthday;
public AccountServiceImpl(String name,Integer age,Date birthday){
this.name = name;
this.age = age;
this.birthday = birthday;
}
public void saveAccount(){
System.out.println("service中的saveAccount方法執行了。。。"+name+","+age+","+birthday);
}
}
<!-- 使用構造函數的方式,給 service 中的屬性傳值
要求:
類中需要提供一個對應參數列表的構造函數。
涉及的標籤:
constructor-arg
屬性:
index:指定參數在構造函數參數列表的索引位置
type:指定參數在構造函數中的數據類型
name:指定參數在構造函數中的名稱 用這個找給誰賦值
=======上面三個都是找給誰賦值,下面兩個指的是賦什麼值的==============
value:它能賦的值是基本數據類型和 String 類型
ref:它能賦的值是其他 bean 類型,也就是說,必須得是在配置文件中配置過的 bean
優勢:
在獲取bean對象時,注入數據是必須的操作,否則對象無法創建成功。
弊端:
改變了bean對象的實例化方式,使我們在創建對象時,如果用不到這些數據,也必須提供。
-->
<bean id="accountService" class="com.company.service.impl.AccountServiceImpl">
<constructor-arg name="name" value=" 張三 "></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
<constructor-arg name="birthday" ref="now"></constructor-arg>
</bean>
<bean id="now" class="java.util.Date"></bean>
- set 方法注入,實際開發中,此種方式用的較多
//顧名思義,就是在類中提供需要注入成員的 set 方法。具體代碼如下:
public class AccountServiceImpl implements IAccountService {
private String name;
private Integer age;
private Date birthday;
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public void saveAccount() {
System.out.println(name+","+age+","+birthday);
}
}
<!-- 通過配置文件給 bean 中的屬性傳值:使用 set 方法的方式
涉及的標籤:
property
屬性:
name:找的是類中 set 方法後面的部分
ref:給屬性賦值是其他 bean 類型的
value:給屬性賦值是基本數據類型和 string 類型的
實際開發中,此種方式用的較多。
優勢:
創建對象時沒有明確的限制,可以直接使用默認構造函數
弊端:
如果有某個成員必須有值,則獲取對象是有可能set方法沒有執行。
-->
<bean id="accountService" class="com.company.service.impl.AccountServiceImpl">
<property name="name" value="test"></property>
<property name="age" value="21"></property>
<property name="birthday" ref="now"></property>
</bean>
<bean id="now" class="java.util.Date"></bean>
- 注入集合屬性
顧名思義,就是給類中的集合成員傳值,它用的也是set方法注入的方式,只不過變量的數據類型都是集合。
我們這裏介紹注入數組,List,Set,Map,Properties。具體代碼如下:
public class AccountServiceImpl implements IAccountService {
private String[] myStrs;
private List<String> myList;
private Set<String> mySet;
private Map<String,String> myMap;
private Properties myProps;
public void setMyStrs(String[] myStrs) {
this.myStrs = myStrs;
}
public void setMyList(List<String> myList) {
this.myList = myList;
}
public void setMySet(Set<String> mySet) {
this.mySet = mySet;
}
public void setMyMap(Map<String, String> myMap) {
this.myMap = myMap;
}
public void setMyProps(Properties myProps) {
this.myProps = myProps;
}
@Override
public void saveAccount() {
System.out.println(Arrays.toString(myStrs));
System.out.println(myList);
System.out.println(mySet);
System.out.println(myMap);
System.out.println(myProps);
}
}
<!-- 注入集合數據
List 結構的:
array,list,set
Map 結構的
map,entry,props,prop
-->
<bean id="accountService" class="com.company.service.impl.AccountServiceImpl">
<!-- 在注入集合數據時,只要結構相同,標籤可以互換 -->
<!-- 給數組注入數據 -->
<property name="myStrs">
<set>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</set>
</property>
<!-- 注入 list 集合數據 -->
<property name="myList">
<array>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</array>
</property>
<!-- 注入 set 集合數據 -->
<property name="mySet">
<list>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</list>
</property>
<!-- 注入 Map 數據 -->
<property name="myMap">
<props>
<prop key="testA">aaa</prop>
<prop key="testB">bbb</prop>
</props>
</property>
<!-- 注入 properties 數據 -->
<property name="myProps">
<map>
<entry key="testA" value="aaa"></entry>
<entry key="testB">
<value>bbb</value>
</entry>
</map>
</property>
</bean>