1.0 再次強調(diào)
IOC解耦只是削減計算機的耦合癞揉,但是不能消除,只能降低。
2.0 新建一個項目
填充基本的代碼:
pom.xml
<?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.0</modelVersion>
<groupId>com.edp</groupId>
<artifactId>second_project_spring</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
</dependencies>
</project>
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">
<!-- 把對象的創(chuàng)建交給spring來管理-->
<!-- id:獲取時的唯一標志-->
<!-- class:反射要創(chuàng)建的權(quán)限定位名稱-->
<bean id="accountService" class="com.edp.service.impl.IAccountServiceImpl"></bean>
<bean id="accountDao" class="com.edp.dao.impl.AccountDaoImpl"></bean>
</beans>
AccountDaoImpl.java
package com.edp.dao.impl;
import com.edp.dao.IAccountDao;
/**
* @author EdPeng
* @Title:
* @Package
* @Description: 賬戶持久層實現(xiàn)類
* @date 2020/2/23下午 5:45
*/
public class AccountDaoImpl implements IAccountDao {
public void saveAccount() {
System.out.println("保存了賬戶喊熟。");
}
}
IAccountDao.java
package com.edp.dao.impl;
import com.edp.dao.IAccountDao;
public class AccountDaoImpl implements IAccountDao {
public void saveAccount() {
System.out.println("保存了賬戶柏肪。");
}
}
IAccountServiceImpl .java
package com.edp.service.impl;
import com.edp.dao.impl.AccountDaoImpl;
import com.edp.service.IAccountService;
import com.edp.dao.IAccountDao;
public class IAccountServiceImpl implements IAccountService {
public IAccountServiceImpl(){
System.out.println("IAccountServiceImpl對象創(chuàng)建了!");
}
public void saveAccount() {
System.out.println("IAccountService中的saveAccount方法執(zhí)行了……");
}
}
IAccountService .java
package com.edp.service;
public interface IAccountService {
void saveAccount();
}
Client .java
package com.edp.ui;
import com.edp.service.IAccountService;
import com.edp.dao.IAccountDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class Client {
public static void main(String[] args) {
//1.獲取核心容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
//根據(jù)id獲取bean對象
IAccountService accountService = (IAccountService) applicationContext.getBean("accountService");
System.out.println(accountService);
accountService.saveAccount();
}
}
3.0 spring對bean對象管理的細節(jié)——創(chuàng)建bean的三種方式
3.1 第一種方式:使用默認構(gòu)造函數(shù)創(chuàng)建
在spring的配置文件中使用bean標簽芥牌,配以id和class屬性之后烦味,且沒有其他屬性和標簽時,采用的就是默認構(gòu)造函數(shù)創(chuàng)造bean對象壁拉,此時如果類中沒有默認構(gòu)造函數(shù)谬俄,則對象無法創(chuàng)建。
比如我們修改IAccountServiceImpl .java
public class IAccountServiceImpl implements IAccountService {
public IAccountServiceImpl(String value){
System.out.println("IAccountServiceImpl對象創(chuàng)建了扇商!");
}
public void saveAccount() {
System.out.println("IAccountService中的saveAccount方法執(zhí)行了……");
}
}
將原來的默認構(gòu)造函數(shù)修改為有參構(gòu)造函數(shù)凤瘦,意味著構(gòu)造函數(shù)沒有了宿礁,運行Client類:
而且案铺,這樣沒有無參構(gòu)造函數(shù)的情況下,bean.xml都在會編譯環(huán)境下報錯:
3.2 第二種方式:使用普通工廠中的方法創(chuàng)建對象(使用某個類中的方法創(chuàng)建梆靖,并存入spring容器)
這個方法解決加入需要配置的類在class字節(jié)碼中(即集成的jar包中的類控汉。)
創(chuàng)建一個模擬的工廠類
InstanceFactory.java
package com.edp.factory;
import com.edp.service.IAccountService;
import com.edp.service.impl.IAccountServiceImpl;
/**
* @author EdPeng
* @Title: 模擬一個工廠類
* @Package
* @Description:模擬工廠類(該類可能是存在于jar包中的,我們無法通過修改源碼的方式來提供默認構(gòu)造函數(shù))
* @date 2020/2/29下午 5:46
*/
public class InstanceFactory {
public IAccountService getAccountService(){
return new IAccountServiceImpl();
}
}
這時候返吻,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">
<bean id="instanceFactory" class="com.edp.factory.InstanceFactory"></bean>
<bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>
</beans>
運行:
成功運行姑子,證明這樣配置沒有問題。
3.3 第三種方式:使用工廠中的靜態(tài)方法創(chuàng)建對象(使用某個類中的靜態(tài)方法創(chuàng)建對象测僵,并存入spring容器)
新建一個StaticFactory.java類:
package com.edp.factory;
import com.edp.service.IAccountService;
import com.edp.service.impl.IAccountServiceImpl;
/**
* @author EdPeng
* @Title:模擬一個工廠類
* @Package
* @Description:模擬工廠類(該類可能是存在于jar包中的街佑,我們無法通過修改源碼的方式來提供默認構(gòu)造函數(shù))
* @date 2020/2/29下午 9:00
*/
public class StaticFactory {
public static IAccountService getAccountService() {
return new IAccountServiceImpl();
}
}
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">
<bean id="accountService" class="com.edp.factory.StaticFactory" factory-method="getAccountService"></bean>
</beans>
運行:
注意,上面看上去兩個Factory類其實已經(jīng)耦合了捍靠,但是我們只是在模擬jar包中的類沐旨,jar包中有普通方法也有靜態(tài)方法,spring都給我們提供配置的方法榨婆。
在jar包中的類都是“.class”文件磁携,是無法改動的,當我們需要獲得某個方法的返回值存入spring容器中良风,就需要用到以上3種中的第2谊迄、3種bean對象創(chuàng)建方法。
4.0 spring對bean對象管理的細節(jié)——bean對象的作用范圍
4.1 spring的bean對象默認情況下就是單例的烟央。
重置一下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">
<bean id="accountService" class="com.edp.service.impl.IAccountServiceImpl"></bean>
</beans>
修改Client.java類測試一下:
public class Client {
public static void main(String[] args) {
//1.獲取核心容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
//根據(jù)id獲取bean對象
IAccountService accountService = (IAccountService) applicationContext.getBean("accountService");
IAccountService accountService2 = (IAccountService) applicationContext.getBean("accountService");
System.out.println(accountService);
System.out.println(accountService2);
accountService.saveAccount();
accountService2.saveAccount();
System.out.println(accountService==accountService2);
}
}
執(zhí)行:
4.2 bean標簽的scope屬性
修改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">
<!--bean標簽的scope屬性
作用:用于指定bean的作用范圍
取值:singleton:單例的(默認值统诺,常用)
prototype:多例的(常用)
request:作用于web應(yīng)用的請求范圍
session:作用于web應(yīng)用的會話范圍
global-session:作用于集群環(huán)境的會話范圍(全局會話范圍),當不是集群環(huán)境時疑俭,它就是session
-->
<bean id="accountService" scope="prototype" class="com.edp.service.impl.IAccountServiceImpl"></bean>
</beans>
執(zhí)行:
其中
global-session:作用于集群環(huán)境的會話范圍(全局會話范圍)篙议,當不是集群環(huán)境時,它就是session
,一般情況下接觸不到這個方面鬼贱,但在此做以解釋移怯。
當我們用戶訪問服務(wù)器時,服務(wù)器往往都有一個訪問地址这难,比如“192.168.0.1”舟误,但在超大型項目中,一個服務(wù)器往往扛不住這么大的數(shù)據(jù)訪問量姻乓,當在集群環(huán)境時嵌溢,往往會有多個服務(wù)器ip地址供用戶訪問。
當我們訪問一個大型網(wǎng)站蹋岩,比如淘寶時赖草,首先訪問的是“https://www.taobao.com/”,用戶打開的是一個login.jsp頁面剪个,然后網(wǎng)頁就會尋找空閑的服務(wù)器ip地址提供數(shù)據(jù)服務(wù)秧骑。(專業(yè)名詞叫“負載均衡”)
在用戶注冊賬戶時,將由一個空閑的服務(wù)器進行數(shù)據(jù)存儲扣囊,但當用戶登錄的時候乎折,服務(wù)器的情況已經(jīng)瞬息萬變,再次訪問的時候侵歇,注冊時的物理服務(wù)器已經(jīng)不是現(xiàn)在登錄的物理服務(wù)器骂澄,而這個時候,新的服務(wù)器不會存儲用戶的賬戶信息惕虑。
這時候就需要一個全局的集群環(huán)境的會話范圍坟冲,能夠讓用戶找到服務(wù)器所在信息的調(diào)度。這個會話模式在spring中的配置屬性就是global-session溃蔫。
5.0 spring對bean對象管理的細節(jié)——bean對象的生命周期
bean對象的生命周期
- 單例對象
- 出生:當容器創(chuàng)建時對象出生
- 活著:只要容器還在健提,對象一直活著
- 死亡:容器銷毀,對象消亡
- 總結(jié):單例對象的生命周期和容器相同
- 多例對象
- 出生:當我們使用對象時酒唉,spring框架為我們創(chuàng)建
- 活著:對象在使用過程中矩桂,一直活著
- 死亡:當對象長時間不用,且沒有別的對象引用時痪伦,由java的垃圾回收器回收
6.0 Spring的依賴注入
6.1 什么是依賴注入(Dependency Injection)侄榴?
- IOC的作用:降低程序間的耦合(依賴關(guān)系),也就是降低程序間的依賴關(guān)系,而依賴關(guān)系的管理网沾,以后都交給spring來維護癞蚕。
- 在當前類需要用到其他類的對象,由spring為我們提供辉哥,我們只需要在配置文件中說明桦山。
- 而針對這依賴關(guān)系的維護攒射,就稱之為依賴注入。
6.2 依賴注入分為三類
依賴注入能注入的數(shù)據(jù)分為三類:
- 基本類型和String
- 其他bean類型(在配置文件中或者注解配置過的bean)
- 復(fù)雜類型/集合類型
6.3 依賴注入的注入方式
總共有3種:
- 第1種:使用構(gòu)造函數(shù)提供
- 第2種:使用set方法提供
- 第3種:使用注解提供
7.0 使用構(gòu)造注入
首先在類中恒水,定義一些可注入的變量会放。
修改IAccountServiceImpl.java
public class IAccountServiceImpl implements IAccountService {
//如果是經(jīng)常變換的數(shù)據(jù),并不適用于注入的方式
private String name;
private Integer age;
private Date birthday;
public IAccountServiceImpl(String name, Integer age, Date birthday) {
this.name = name;
this.age = age;
this.birthday = birthday;
}
public void saveAccount() {
System.out.println("IAccountService中的saveAccount方法執(zhí)行了……"+name+" , "+age+" , "+birthday);
}
}
當然钉凌,我們不應(yīng)該關(guān)注這些變量是不是應(yīng)該出現(xiàn)在Dao層咧最,只是說作為一個對象,以一種方便理解的方式命名御雕。
配置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">
<!--構(gòu)造函數(shù)注入:
使用的標簽:constructor-arg
標簽出現(xiàn)的位置:bean標簽內(nèi)部
標簽中的屬性
type:用于指定要注入的數(shù)據(jù)的數(shù)據(jù)類型矢沿,同時該數(shù)據(jù)類型也是構(gòu)造函數(shù)中某個或某些參數(shù)的類型
index:用于指定要注入的數(shù)據(jù)給構(gòu)造函數(shù)中指定索引位置的參數(shù)賦值。索引的位置是從0開始的
name:用于指定給構(gòu)造函數(shù)中指定名稱的參數(shù)賦值(常用)
==============================以上三個用于指定給構(gòu)造函數(shù)中那個參數(shù)賦值==============================
value:用于提供基本類型和String類型的數(shù)據(jù)
ref:用于指定其他的bean類型數(shù)據(jù)酸纲,指的是在spring的IOC核心容器中出現(xiàn)過得bean對象
優(yōu)勢:
在獲取bean對象時捣鲸,注入數(shù)據(jù)是必須的操作,否則對象無法創(chuàng)建成功闽坡。
弊端:
改變了bean對象的是開花方式栽惶,使我們在創(chuàng)建對象時,如果用不到這些數(shù)據(jù)无午,也必須提供媒役。
-->
<bean id="accountService" class="com.edp.service.impl.IAccountServiceImpl">
<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>
</beans>
運行:
發(fā)現(xiàn)祝谚,沒有出現(xiàn)亂碼宪迟,這就是Spring的強大之處:能把涉及到的可能的它能處理的細節(jié)都提前替我們處理。
8.0 set方法注入
注入只需要set方法交惯,不需要get方法次泽。
創(chuàng)建一個com.edp.service.impl.IAccountServiceImpl2 .java
public class IAccountServiceImpl2 implements IAccountService {
//如果是經(jīng)常變換的數(shù)據(jù),并不適用于注入的方式
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;
}
public void saveAccount() {
System.out.println("IAccountService中的saveAccount方法執(zhí)行了……"+name+" , "+age+" , "+birthday);
}
}
配置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">
<!--配置一個日期對象-->
<bean id="now" class="java.util.Date"></bean>
<!--set方法注入:
設(shè)計的標簽:property
標簽出現(xiàn)的位置:bean標簽內(nèi)部
標簽中的屬性
name:用于指定注入時所調(diào)用的set方法名稱
value:用于提供基本類型和String類型的數(shù)據(jù)
ref:用于指定其他的bean類型數(shù)據(jù)席爽,指的是在spring的IOC核心容器中出現(xiàn)過得bean對象
優(yōu)勢:
創(chuàng)建對象時意荤,沒有明確的限制≈欢停可以直接使用默認構(gòu)造函數(shù)
弊端:
如果有某個成員必須有值玖像,則獲取對象時,有可能set方法沒有執(zhí)行
-->
<bean id="accountService2" class="com.edp.service.impl.IAccountServiceImpl2">
<property name="name" value="泰斯特"></property>
<property name="age" value="18"></property>
<property name="birthday" ref="now"></property>
</bean>
</beans>
修改Client.java
public class Client {
public static void main(String[] args) {
//1.獲取核心容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
IAccountService accountService = (IAccountService) applicationContext.getBean("accountService2");
accountService.saveAccount();
}
}
執(zhí)行:
set方法注入的優(yōu)勢就是就是構(gòu)造函數(shù)注入的弊端齐饮,當然set方法注入的弊端就是構(gòu)造函數(shù)注入的優(yōu)勢捐寥,但我們更常用的方式是set方法注入。
9.0 復(fù)雜類型的注入
創(chuàng)建com.edp.service.impl.IAccountServiceImpl3.java
package com.edp.service.impl;
import com.edp.service.IAccountService;
import java.util.*;
public class IAccountServiceImpl3 implements IAccountService {
private String[] myStr;
private List<String> myList;
private Set<String> mySet;
private Map<String, String> myMap;
private Properties myProps;
public void setMyStr(String[] myStr) {
this.myStr = myStr;
}
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 String toString() {
return "IAccountServiceImpl3{" +
"\n myStr=" + Arrays.toString(myStr) +
",\n myList=" + myList +
",\n mySet=" + mySet +
",\n myMap=" + myMap +
",\n myProps=" + myProps +
'}';
}
public void saveAccount() {
System.out.println( toString());
}
}
修改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">
<bean id="accountService3" class="com.edp.service.impl.IAccountServiceImpl3">
<property name="myStr">
<array>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</array>
</property>
</bean>
</beans>
修改Client.java
public class Client {
public static void main(String[] args) {
//1.獲取核心容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
IAccountService accountService = (IAccountService) applicationContext.getBean("accountService3");
accountService.saveAccount();
}
}
執(zhí)行:
繼續(xù)完善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">
<bean id="accountService3" scope="prototype" class="com.edp.service.impl.IAccountServiceImpl3">
<property name="myStr">
<array>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</array>
</property>
<property name="myList">
<list>
<value>DDD</value>
<value>EEE</value>
<value>FFF</value>
</list>
</property>
<property name="mySet">
<set>
<value>GGG</value>
<value>HHH</value>
<value>III</value>
</set>
</property>
<property name="myMap">
<map>
<entry key="testA" value="aaaa"></entry>
<entry key="testB">
<value>bbbb</value>
</entry>
<entry key="testC" value="cccc"></entry>
</map>
</property>
<property name="myProps">
<props>
<prop key="testD"></prop>
<prop key="testE"></prop>
<prop key="testF"></prop>
</props>
</property>
</bean>
</beans>
執(zhí)行:
接下來祖驱,我們?nèi)缦虏僮魑湛遥薷腷ean.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="accountService3" scope="prototype" class="com.edp.service.impl.IAccountServiceImpl3">
<property name="myStr">
<set>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</set>
</property>
<property name="myList">
<array>
<value>DDD</value>
<value>EEE</value>
<value>FFF</value>
</array>
</property>
<property name="mySet">
<list>
<value>GGG</value>
<value>HHH</value>
<value>III</value>
</list>
</property>
<property name="myMap">
<props>
<prop key="testD"></prop>
<prop key="testE"></prop>
<prop key="testF"></prop>
</props>
</property>
<property name="myProps">
<map>
<entry key="testA" value="aaaa"></entry>
<entry key="testB">
<value>bbbb</value>
</entry>
<entry key="testC" value="cccc"></entry>
</map>
</property>
</bean>
</beans>
執(zhí)行:
將標簽內(nèi)的對應(yīng)關(guān)系打亂,發(fā)現(xiàn)還是可以運行捺僻。
復(fù)雜類型(集合類型)的注入乡洼,用于給List結(jié)構(gòu)集合注入的標簽有:list崇裁、array、set束昵;用于給map結(jié)構(gòu)集合注入的標簽有:map拔稳、props,結(jié)構(gòu)相同的锹雏,標簽可以互換壳炎。
10.0 使用注解注入
【Java中級】27.0 SSM之Spring框架(三)——注解注入
END