Spring IOC

Spring IOC

主要內(nèi)容

Spring 框架

Spring 框架概念

? Spring 是眾多開(kāi)源java項(xiàng)目中的一員,基于分層的javaEE應(yīng)用一站式輕量級(jí)開(kāi)源框架,主要核心是 IOC(控制反轉(zhuǎn)/依賴注入)與 AOP(面向切面)兩大技術(shù),實(shí)現(xiàn)項(xiàng)目在開(kāi)發(fā)過(guò)程中的輕松解耦,提高項(xiàng)目的開(kāi)發(fā)效率。

? 在項(xiàng)目中引入 Spring 立即可以帶來(lái)下面的好處 降低組件之間的耦合度,實(shí)現(xiàn)軟件各層之間的解耦??梢允褂萌萜魈峁┑谋姸喾?wù),如:事務(wù)管理服務(wù)、消息服務(wù)等等。當(dāng)我們使用容器管理事務(wù)時(shí),開(kāi)發(fā)人員就不再需要手工控制事務(wù).也不需處理復(fù)雜的事務(wù)傳播。 容器提供單例模式支持,開(kāi)發(fā)人員不再需要自己編寫實(shí)現(xiàn)代碼。 容器提供了AOP技術(shù),利用它很容易實(shí)現(xiàn)如權(quán)限攔截、運(yùn)行期監(jiān)控等功能。

Spring 源碼架構(gòu)

? Spring 總共大約有20個(gè)模塊,由1300多個(gè)不同的文件構(gòu)成。而這些組件被分別整合在核心容器(Core Container)、Aop(Aspect Oriented Programming)和設(shè)備支持(Instrmentation)、數(shù)據(jù)訪問(wèn)及集成(Data Access/Integeration)、Web、報(bào)文發(fā)送(Messaging)、測(cè)試6個(gè)模塊集合中。

核心容器:Spring-beans 和 Spring-core 模塊是 Spring 框架的核心模塊,包含控制反轉(zhuǎn)(Inversion of Control, IoC)和依賴注入(Dependency Injection, DI),核心容器提供 Spring 框架的基本功能。核心容器的主要組件是 BeanFactory,工廠模式的實(shí)現(xiàn)。BeanFactory 使用控制反轉(zhuǎn)(IOC) 思想將應(yīng)用程序的配置和依賴性規(guī)范與實(shí)際的應(yīng)用程序代碼分開(kāi)。

Spring 上下文Spring Context:Spring 上下文是一個(gè)配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企業(yè)服務(wù),例如 JNDI、EJB、電子郵件、國(guó)際化、校驗(yàn)和調(diào)度功能。

Spring-Expression 模塊是統(tǒng)一表達(dá)式語(yǔ)言(unified EL)的擴(kuò)展模塊,可以查詢、管理運(yùn)行中的對(duì)象,同時(shí)也方便的可以調(diào)用對(duì)象方法、操作數(shù)組、集合等。它的語(yǔ)法類似于傳統(tǒng)EL,但提供了額外的功能,最出色的要數(shù)函數(shù)調(diào)用和簡(jiǎn)單字符串的模板函數(shù)。

Spring-AOP:Spring-aop是Spring的另一個(gè)核心模塊, 在Spring中,他是以JVM的動(dòng)態(tài)代理技術(shù)為基礎(chǔ),然后設(shè)計(jì)出了一系列的Aop橫切實(shí)現(xiàn),比如前置通知、返回通知、異常通知等。通過(guò)其配置管理特性,Spring AOP 模塊直接將面向切面的編程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何對(duì)象支持 AOP。

Spring Data Access(數(shù)據(jù)訪問(wèn)):由Spring-jdbc、Spring-tx、Spring-orm、Spring-jms和Spring-oxm 5個(gè)模塊組成 Spring-jdbc 模塊是 Spring 提供的JDBC抽象框架的主要實(shí)現(xiàn)模塊,用于簡(jiǎn)化 Spring JDBC。

Spring-tx 模塊是SpringJDBC事務(wù)控制實(shí)現(xiàn)模塊。使用Spring框架,它對(duì)事務(wù)做了很好的封裝,通過(guò)它的Aop配置,可以靈活的配置在任何一層。

Spring-Orm 模塊是ORM框架支持模塊,主要集成 hibernate, Java Persistence API (JPA) 和 Java Data Objects (JDO) 用于資源管理、數(shù)據(jù)訪問(wèn)對(duì)象(DAO)的實(shí)現(xiàn)和事務(wù)策略。

Spring-Jms 模塊(Java Messaging Service)能夠發(fā)送和接受信息。

Spring-Oxm 模塊主要提供一個(gè)抽象層以支撐OXM(OXM 是 Object-to-XML-Mapping 的縮寫,它是一個(gè)O/M-mapper,將java對(duì)象映射成 XML 數(shù)據(jù),或者將 XML 數(shù)據(jù)映射成 java 對(duì)象),例如:JAXB, Castor, XMLBeans, JiBX 和 XStream 等。

Web 模塊:由Spring-web、Spring-webmvc、Spring-websocket和Spring-webmvc-portlet 4個(gè)模塊組成,Web 上下文模塊建立在應(yīng)用程序上下文模塊之上,為基于 Web 的應(yīng)用程序提供了上下文。Web 模塊還簡(jiǎn)化了處理多部分請(qǐng)求以及將請(qǐng)求參數(shù)綁定到域?qū)ο蟮墓ぷ鳌?/p>

報(bào)文發(fā)送:即Spring-messaging模塊。

Spring-messaging是Spring4 新加入的一個(gè)模塊,主要職責(zé)是為Spring 框架集成一些基礎(chǔ)的報(bào)文傳送應(yīng)用。

單元測(cè)試:即Spring-test模塊。Spring-test模塊主要為測(cè)試提供支持

Spring 框架環(huán)境搭建

環(huán)境要求

? JDK 版本:

? JDK 1.7 及以上版本

? Spring版本:

? Spring 5.x版本

新建 Maven 項(xiàng)目

創(chuàng)建 Maven 的普通 Java 項(xiàng)目

設(shè)置項(xiàng)目的坐標(biāo)

設(shè)置項(xiàng)目的 Maven 環(huán)境

設(shè)置項(xiàng)目的名稱和存放的工作空間

調(diào)整項(xiàng)目環(huán)境

修改 JDK 版本

<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></properties>

修改單元測(cè)試 JUnit 版本

<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency>

build標(biāo)簽中的pluginManagement標(biāo)簽

<!--刪除build標(biāo)簽中的pluginManagement標(biāo)簽--><build></build>

添加 Spring 框架的依賴坐標(biāo)

Maven倉(cāng)庫(kù):https://mvnrepository.com/

<!-- 添加Spring框架的核心依賴 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.4.RELEASE</version></dependency>

編寫 Bean 對(duì)象

packagecom.xxxx.service;publicclassUserService{publicvoidtest(){System.out.println("Hello Spring!");}}

添加Spring 配置文件

在項(xiàng)目的src下創(chuàng)建文件夾 resources(Alt+insert)

將 resources 標(biāo)記為資源目錄

在 src\main\resources 目錄下新建 spring.xml 文件,并拷貝官網(wǎng)文檔提供的模板內(nèi)容到 xml 中。

配置 bean 到 xml 中,把對(duì)應(yīng) bean 納入到 Spring 容器來(lái)管理

spring.xml

<?xml version="1.0" encoding="UTF-8"?><beansxmlns="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"><!--

? ? ? ? xmlns 即 xml namespace? xml使用的命名空間

? ? ? ? xmlns:xsi 即xml schema instance xml 遵守的具體規(guī)范

? ? ? ? xsi:schemaLocation 本文檔xml遵守的規(guī)范 官方指定

? --><beanid="userService"class="com.xxxx.service.UserService"></bean></beans>

在 spring.xml 中配置 Bean 對(duì)象

<!--

id:bean對(duì)象的id,唯一標(biāo)識(shí)。一般是Bean對(duì)象的名稱的首字母小寫

class:bean對(duì)象的類路徑

--><beanid="userService"class="com.xxxx.service.UserService"></bean>

加載配置文件,獲取實(shí)例化對(duì)象

packagecom.xxxx;importcom.xxxx.service.UserService;importorg.springframework.context.ApplicationContext;importorg.springframework.context.support.ClassPathXmlApplicationContext;publicclassApp{publicstaticvoidmain(String[]args){// 獲取Spring上下文環(huán)境 (加載配置文件)ApplicationContext ac=newClassPathXmlApplicationContext("spring.xml");// 通過(guò)getBean方法得到Spring容器中實(shí)例化好的Bean對(duì)象 (實(shí)例化Bean對(duì)象)// userService代表的是配置文件中bean標(biāo)簽的id屬性值UserService userService=(UserService)ac.getBean("userService");// 調(diào)用方法 (使用實(shí)例化對(duì)象)userService.test();}}

Spring IOC 容器 Bean 對(duì)象實(shí)例化模擬

思路:

定義Bean 工廠接口,提供獲取bean方法

定義Bean工廠接口實(shí)現(xiàn)類,解析配置文件,實(shí)例化Bean對(duì)象

實(shí)現(xiàn)獲取Bean方法

定義 Bean 屬性對(duì)象

packagecom.xxxx.spring;/**

* bean對(duì)象

*? ? ? 用來(lái)接收配置文件中bean標(biāo)簽的id與class屬性值

*/publicclassMyBean{privateString id;// bean對(duì)象的id屬性值privateString clazz;// bean對(duì)象的類路徑publicMyBean(){}publicMyBean(String id,String clazz){this.id=id;this.clazz=clazz;}publicStringgetId(){returnid;}publicvoidsetId(String id){this.id=id;}publicStringgetClazz(){returnclazz;}publicvoidsetClazz(String clazz){this.clazz=clazz;}}

添加 dom4j 坐標(biāo)依賴

<!-- dom4j --><dependency><groupId>dom4j</groupId><artifactId>dom4j</artifactId><version>1.6.1</version></dependency><!-- XPath --><dependency><groupId>jaxen</groupId><artifactId>jaxen</artifactId><version>1.1.6</version></dependency>

準(zhǔn)備自定義配置文件

spring.xml

<?xml version="1.0" encoding="utf-8" ?><beans><beanid="userService"class="com.xxxx.service.UserService"></bean><beanid="accountService"class="com.xxxx.service.AccountService"></bean></beans>

定義 Bean 工廠接口

packagecom.xxxx.spring;/**

* Bean 工廠接口定義

*/publicinterfaceMyFactory{// 通過(guò)id值獲取對(duì)象publicObjectgetBean(String id);}

定義 Bean 接口的實(shí)現(xiàn)類

packagecom.xxxx.spring;importorg.dom4j.Document;importorg.dom4j.DocumentException;importorg.dom4j.Element;importorg.dom4j.XPath;importorg.dom4j.io.SAXReader;importjava.net.URL;importjava.util.ArrayList;importjava.util.HashMap;importjava.util.List;importjava.util.Map;/**

* 模擬Spring的實(shí)現(xiàn)

*? 1、通過(guò)構(gòu)造器得到相關(guān)配置文件

*? 2、通過(guò)dom4j解析xml文件,得到List? 存放id和class

*? 3、通過(guò)反射實(shí)例化得到對(duì)象? Class.forName(類的全路徑).newInstance(); 通過(guò)Map<id,Class>存儲(chǔ)

*? 4、得到指定的實(shí)例化對(duì)象

*/publicclassMyClassPathXmlApplicationContextimplementsBeanFactory{privateMap beans=newHashMap();// 實(shí)例化后的對(duì)象放入mapprivateList<MyBean>myBeans;// 存放已讀取bean 配置信息/* 1、通過(guò)構(gòu)造器得到相關(guān)配置文件 */publicMyClassPathXmlApplicationContext(String fileName){/* 2、通過(guò)dom4j解析xml文件,得到List (存放id和class) */this.parseXml(fileName);/* 3、通過(guò)反射實(shí)例化得到對(duì)象Class.forName(類路徑).newInstance();? 通過(guò)Map存儲(chǔ) */this.instanceBean();}/**

? ? * 通過(guò)dom4j解析xml文件,得到List? 存放id和class

? ? *? 1、獲取解析器

? ? *? 2、得到配置文件的URL

? ? *? 3、通過(guò)解析器解析xml文件(spring.xml)

? ? *? 4、通過(guò)xpath語(yǔ)法,獲取beans標(biāo)簽下的所有bean標(biāo)簽

? ? *? 5、通過(guò)指定語(yǔ)法解析文檔對(duì)象,返回集合

? ? *? 6、判斷集合是否為空,遍歷集合

? ? *? 7、獲取標(biāo)簽元素中的屬性

? ? *? 8、得到Bean對(duì)象,將Bean對(duì)象設(shè)置到集合中

? ? * @param fileName

? ? */privatevoidparseXml(String fileName){// 1、獲取解析器SAXReader reader=newSAXReader();// 2、得到配置文件的URLURL url=this.getClass().getClassLoader().getResource(fileName);try{// 3、通過(guò)解析器解析xml文件(spring.xml)Document document=reader.read(url);// 4、通過(guò)xpath語(yǔ)法,獲取beans標(biāo)簽下的所有bean標(biāo)簽XPath xPath=document.createXPath("beans/bean");// 通過(guò)指定語(yǔ)法解析文檔對(duì)象,返回集合List<Element>list=xPath.selectNodes(document);// 判斷集合是否為空,遍歷集合if(list!=null&&list.size()>0){myBeans=newArrayList<>();for(Element el:list){// 獲取標(biāo)簽元素中的屬性String id=el.attributeValue("id");// id 屬性值String clazz=el.attributeValue("class");// class 屬性值System.out.println(el.attributeValue("id"));System.out.println(el.attributeValue("class"));// 得到Bean對(duì)象MyBean bean=newMyBean(id,clazz);// 將Bean對(duì)象設(shè)置到集合中myBeans.add(bean);}}}catch(DocumentExceptione){e.printStackTrace();}}/**

? ? * 通過(guò)反射實(shí)例化得到對(duì)象?

? ? * Class.forName(類的全路徑).newInstance();?

? ? * 通過(guò)Map<id,Class>存儲(chǔ)

? ? */privatevoidinstanceBean(){// 判斷bean集合是否為空,不為空遍歷得到對(duì)應(yīng)Bean對(duì)象if(myBeans!=null&&myBeans.size()>0){for(MyBean bean:myBeans){try{// 通過(guò)類的全路徑實(shí)例化對(duì)象Object object=Class.forName(bean.getClazz()).newInstance();// 將id與實(shí)例化對(duì)象設(shè)置到map對(duì)象中beans.put(bean.getId(),object);}catch(Exceptione){e.printStackTrace();}}}}/**

? ? * 通過(guò)key獲取map中的指定value

? ? * @param id

? ? * @return

? ? */@OverridepublicObjectgetBean(String id){Object object=beans.get(id);returnobject;}}

測(cè)試自定義 IOC 容器

創(chuàng)建與配置文件中對(duì)應(yīng)的Bean對(duì)象

UserService.java

packagecom.xxxx.service;publicclassUserService{publicvoidtest(){System.out.println("UserService Test...");}}

AccountService.java

packagecom.xxxx.service;publicclassAccountService{publicvoidtest(){System.out.println("AccountService Test...");}}

測(cè)試是否可以獲取實(shí)例化的Bean對(duì)象

packagecom.xxxx;importcom.xxxx.spring.MyFactory;importcom.xxxx.spring.MyClassPathXmlApplicationContext;importcom.xxxx.service.AccountService;importcom.xxxx.service.UserService;publicclassApp{publicstaticvoidmain(String[]args){MyFactory factory=newMyClassPathXmlApplicationContext("spring.xml");// 得到實(shí)例化對(duì)象UserService userService=(UserService)factory.getBean("userService");userService.test();UserService userService2=(UserService)factory.getBean("userService");System.out.println(userService+"====="+userService2);AccountService accountService=(AccountService)factory.getBean("accountService");accountService.test();}}

? Spring 容器在啟動(dòng)的時(shí)候 讀取xml配置信息,并對(duì)配置的 bean 進(jìn)行實(shí)例化(這里模擬的比較簡(jiǎn)單,僅用于幫助大家理解),同時(shí)通過(guò)上下文對(duì)象提供的 getBean() 方法拿到我們配置的 bean 對(duì)象,從而實(shí)現(xiàn)外部容器自動(dòng)化維護(hù)并創(chuàng)建 bean 的效果。

Spring IOC 配置文件加載

Spring 配置文件加載

spring.xml

<?xml version="1.0" encoding="UTF-8"?><beansxmlns="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"><beanid="userService"class="com.xxxx.service.UserService"></bean></beans>

根據(jù)相對(duì)路徑加載資源

ApplicationContext ac=newClassPathXmlApplicationContext("spring.xml");

根據(jù)絕對(duì)路徑加載資源(了解)

ApplicationContext ac=newFileSystemXmlApplicationContext("C:/IdeaWorkspace/spring01/src/main/resources/spring.xml");

Spring 多配置文件加載

? Spring 框架啟動(dòng)時(shí)可以加載多個(gè)配置文件到環(huán)境中。對(duì)于比較復(fù)雜的項(xiàng)目,可能對(duì)應(yīng)的配置文件有多個(gè),項(xiàng)目在啟動(dòng)部署時(shí)會(huì)將多個(gè)配置文件同時(shí)加載進(jìn)來(lái)。

service.xml

<?xml version="1.0" encoding="UTF-8"?><beansxmlns="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"><beanid="userService"class="com.xxxx.service.UserService"></bean></beans>

dao.xml

<?xml version="1.0" encoding="UTF-8"?><beansxmlns="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"><beanid="userDao"class="com.xxxx.dao.UserDao"></bean></beans>

可變參數(shù),傳入多個(gè)文件名

// 同時(shí)加載多個(gè)資源文件ApplicationContext ac=newClassPathXmlApplicationContext("spring.xml","dao.xml");

通過(guò)總的配置文件import其他配置文件

spring.xml

<?xml version="1.0" encoding="UTF-8"?><beansxmlns="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"><!--導(dǎo)入需要包含的資源文件--><importresource="service.xml"/><importresource="dao.xml"/></beans>

加載時(shí)只需加載總的配置文件即可

// 加載總的資源文件ApplicationContext ac=newClassPathXmlApplicationContext("spring.xml");

Spring IOC 容器 Bean 對(duì)象實(shí)例化

構(gòu)造器實(shí)例化

注:通過(guò)默認(rèn)構(gòu)造器創(chuàng)建 空構(gòu)造方法必須存在 否則創(chuàng)建失敗

設(shè)置配置文件 spring.xml

<?xml version="1.0" encoding="UTF-8"?><beansxmlns="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"><beanid="userService"class="com.xxxx.service.UserService"></bean></beans>

獲取實(shí)例化對(duì)象

ApplicationContext ac=newClassPathXmlApplicationContext("spring.xml");UserService userService=(UserService)ac.getBean("userService");userService.test();

靜態(tài)工廠實(shí)例化(了解)

注:

要有該工廠類及工廠方法

工廠方法為靜態(tài)的

定義靜態(tài)工廠類

packagecom.xxxx.factory;importcom.xxxx.service.UserService;/**

* 定義靜態(tài)工廠類

*/publicclassStaticFactory{/**

? ? * 定義對(duì)應(yīng)的靜態(tài)方法,返回實(shí)例化對(duì)象

? ? * @return

? ? */publicstaticUserServicecreateUserService(){returnnewUserService();}}

設(shè)置配置文件 spring.xml

<?xml version="1.0" encoding="UTF-8"?><beansxmlns="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"><!--靜態(tài)工廠--><beanid="userService"class="com.xxxx.factory.StaticFactory"factory-method="createUserService"></bean></beans>

獲取實(shí)例化對(duì)象

ApplicationContext ac=newClassPathXmlApplicationContext("spring.xml");UserService userService=(UserService)ac.getBean("userService");userService.test();

? 當(dāng)我們指定Spring使用靜態(tài)工廠方法來(lái)創(chuàng)建Bean實(shí)例時(shí),Spring將先解析配置文件,并根據(jù)配置文件指定的信息,通過(guò)反射調(diào)用靜態(tài)工廠類的靜態(tài)工廠方法,并將該靜態(tài)工廠方法的返回值作為Bean實(shí)例,在這個(gè)過(guò)程中,Spring不再負(fù)責(zé)創(chuàng)建Bean實(shí)例,Bean實(shí)例是由用戶提供的靜態(tài)工廠方法提供的。

實(shí)例化工廠實(shí)例化(了解)

注:

工廠方法為非靜態(tài)方法

需要配置工廠bean,并在業(yè)務(wù)bean中配置factory-bean,factory-method屬性

定義工廠類

packagecom.xxxx.factory;importcom.xxxx.service.UserService;/**

* 定義工廠類

*/publicclassInstanceFactory{/**

? ? * 定義方法,返回實(shí)例化對(duì)象

? ? * @return

? ? */publicUserServicecreateUserService(){returnnewUserService();}}

設(shè)置配置文件 spring.xml

<?xml version="1.0" encoding="UTF-8"?><beansxmlns="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"><!--

實(shí)例化工廠

1.定義實(shí)例化工廠bean

? ? 2.引用工廠bean 指定工廠創(chuàng)建方法(方法為非靜態(tài))

--><beanid="instanceFactory"class="com.xxxx.factory.InstanceFactory"></bean><beanid="userService"factory-bean="instanceFactory"factory-method="createUserService"></bean></beans>

獲取實(shí)例化對(duì)象

ApplicationContext ac=newClassPathXmlApplicationContext("spring.xml");UserService userService=(UserService)ac.getBean("userService");userService.test();

Spring三種實(shí)例化Bean的方式比較

方式一:通過(guò)bean的缺省構(gòu)造函數(shù)創(chuàng)建,當(dāng)各個(gè)bean的業(yè)務(wù)邏輯相互比較獨(dú)立的時(shí)候或者和外界關(guān)聯(lián)較少的時(shí)候可以使用。

方式二:利用靜態(tài)factory方法創(chuàng)建,可以統(tǒng)一管理各個(gè)bean的創(chuàng)建,如各個(gè)bean在創(chuàng)建之前需要相同的初始化處理,則可用這個(gè)factory方法險(xiǎn)進(jìn)行統(tǒng)一的處理等等。

方式三:利用實(shí)例化factory方法創(chuàng)建,即將factory方法也作為了業(yè)務(wù)bean來(lái)控制,1可用于集成其他框架的bean創(chuàng)建管理方法,2能夠使bean和factory的角色互換。

??開(kāi)發(fā)中項(xiàng)目一般使用一種方式實(shí)例化bean,項(xiàng)目開(kāi)發(fā)基本采用第一種方式,交給Spring托管,使用時(shí)直接拿來(lái)使用即可。另外兩種了解

Spring IOC 注入

手動(dòng)實(shí)例化與外部引入

圖一:

圖二:

? 對(duì)比發(fā)現(xiàn):圖二中對(duì)于 UserDao 對(duì)象的創(chuàng)建并沒(méi)有像圖一那樣主動(dòng)的去實(shí)例化,而是通過(guò)帶參方法形式將UserDao 傳入過(guò)來(lái),從而實(shí)現(xiàn) UserService 對(duì)UserDao類 的依賴。

??而實(shí)際創(chuàng)建對(duì)象的幕后對(duì)象即是交給了外部來(lái)創(chuàng)建。

Spring IOC 手動(dòng)裝配(注入)

? Spring 支持的注入方式共有四種:set 注入、構(gòu)造器注入、靜態(tài)工廠注入、實(shí)例化工廠注入。

set方法注入

注:

屬性字段需要提供set方法

四種方式,推薦使用set方法注入

業(yè)務(wù)對(duì)象 JavaBean

屬性字段提供set方法

publicclassUserService{// 業(yè)務(wù)對(duì)象UserDao set注入(提供set方法)privateUserDao userDao;publicvoidsetUserDao(UserDao userDao){this.userDao=userDao;}}

配置文件的bean標(biāo)簽設(shè)置property標(biāo)簽

<?xml version="1.0" encoding="UTF-8"?><beansxmlns="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"><!--

? ? ? ? IOC通過(guò)property標(biāo)簽手動(dòng)裝配(注入):

? ? ? ? ? ? Set方法注入

? ? ? ? ? ? ? ? name:bean對(duì)象中屬性字段的名稱

? ? ? ? ? ? ? ? ref:指定bean標(biāo)簽的id屬性值

? ? --><beanid="userDao"class="com.xxxx.dao.UserDao"></bean><beanid="userService"class="com.xxxx.service.UserService"><!--業(yè)務(wù)對(duì)象 注入--><propertyname="userDao"ref="userDao"/></bean></beans>

常用對(duì)象和基本類型

屬性字段提供set方法

publicclassUserService{// 常用對(duì)象String? set注入(提供set方法)privateString host;publicvoidsetHost(String host){this.host=host;}// 基本類型Integer? set注入(提供set方法)privateInteger port;publicvoidsetPort(Integer port){this.port=port;}}

配置文件的bean標(biāo)簽設(shè)置property標(biāo)簽

<?xml version="1.0" encoding="UTF-8"?><beansxmlns="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"><!--

? ? ? ? IOC通過(guò)property標(biāo)簽手動(dòng)裝配(注入):

? ? ? ? ? ? Set方法注入

? ? ? ? ? ? ? ? name:bean對(duì)象中屬性字段的名稱

? ? ? ? ? ? ? ? value:具體的值(基本類型 常用對(duì)象|日期? 集合)

? ? --><beanid="userService"class="com.xxxx.service.UserService"><!--常用對(duì)象String 注入--><propertyname="host"value="127.0.0.1"/><!--基本類型注入--><propertyname="port"value="8080"/></bean></beans>

集合類型和屬性對(duì)象

屬性字段提供set方法

publicclassUserService{// List集合? set注入(提供set方法)publicList<String>list;publicvoidsetList(List<String>list){this.list=list;}// Set集合? set注入(提供set方法)privateSet<String>set;publicvoidsetSet(Set<String>set){this.set=set;}// Map set注入(提供set方法)privateMap<String,Object>map;publicvoidsetMap(Map<String,Object>map){this.map=map;}// Properties set注入(提供set方法)privateProperties properties;publicvoidsetProperties(Properties properties){this.properties=properties;}}

配置文件的bean標(biāo)簽設(shè)置property標(biāo)簽

<?xml version="1.0" encoding="UTF-8"?><beansxmlns="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"><!--

? ? ? ? IOC通過(guò)property標(biāo)簽手動(dòng)裝配(注入):

? ? ? ? ? ? Set方法注入

? ? ? ? ? ? ? ? name:bean對(duì)象中屬性字段的名稱

? ? ? ? ? ? ? ? value:具體的值(基本類型 常用對(duì)象|日期? 集合)

? ? --><!--List集合 注入--><propertyname="list"><list><value>上海</value><value>北京</value><value>杭州</value></list></property><!--Set集合注入--><propertyname="set"><set><value>上海SH</value><value>北京BJ</value><value>杭州HZ</value></set></property><!--Map注入--><propertyname="map"><map><entry><key><value>周杰倫</value></key><value>我是如此相信</value></entry><entry><key><value>林俊杰</value></key><value>可惜沒(méi)如果</value></entry><entry><key><value>陳奕迅</value></key><value>十年</value></entry></map></property><!--Properties注入--><propertyname="properties"><props><propkey="上海">東方明珠</prop><propkey="北京">天安門</prop><propkey="杭州">西湖</prop></props></property></beans>

測(cè)試代碼

UserService.java

publicclassUserService{// 業(yè)務(wù)對(duì)象UserDao set注入(提供set方法)privateUserDao userDao;publicvoidsetUserDao(UserDao userDao){this.userDao=userDao;}// 常用對(duì)象String? set注入(提供set方法)privateString host;publicvoidsetHost(String host){this.host=host;}// 基本類型Integer? set注入(提供set方法)privateInteger port;publicvoidsetPort(Integer port){this.port=port;}// List集合? set注入(提供set方法)publicList<String>list;publicvoidsetList(List<String>list){this.list=list;}// List集合輸出publicvoidprintList(){list.forEach(s->System.out.println(s));}// Set集合? set注入(提供set方法)privateSet<String>set;publicvoidsetSet(Set<String>set){this.set=set;}// Set集合輸出publicvoidprintSet(){set.forEach(s->System.out.println(s));}// Map set注入(提供set方法)privateMap<String,Object>map;publicvoidsetMap(Map<String,Object>map){this.map=map;}// Map輸出publicvoidprintMap(){map.forEach((k,v)->System.out.println(k+","+v));}// Properties set注入(提供set方法)privateProperties properties;publicvoidsetProperties(Properties properties){this.properties=properties;}// Properties輸出publicvoidprintProperties(){properties.forEach((k,v)->System.out.println(k+","+v));}publicvoidtest(){System.out.println("UserService Test...");userDao.test();studentDao.test();System.out.println("Host:"+host+",port:"+port);// List集合printList();// Set集合printSet();// MapprintMap();// PropertiesprintProperties();}}

spring.xml

<?xml version="1.0" encoding="UTF-8"?><beansxmlns="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"><!--

? ? ? ? IOC通過(guò)property標(biāo)簽手動(dòng)裝配(注入):

? ? ? ? ? ? Set方法注入

? ? ? ? ? ? ? ? name:bean對(duì)象中屬性字段的名稱

? ? ? ? ? ? ? ? ref:指定bean標(biāo)簽的id屬性值

? ? ? ? ? ? ? ? value:具體的值(基本類型 常用對(duì)象|日期? 集合)

? ? --><beanid="userDao"class="com.xxxx.dao.UserDao"></bean><beanid="userService"class="com.xxxx.service.UserService"><!--業(yè)務(wù)對(duì)象 注入--><propertyname="userDao"ref="userDao"/><propertyname="studentDao"ref="studentDao"/><!--常用對(duì)象String 注入--><propertyname="host"value="192.168.1.109"/><!--基本類型注入--><propertyname="port"value="8080"/><!--List集合 注入--><propertyname="list"><list><value>上海</value><value>北京</value><value>杭州</value></list></property><!--Set集合注入--><propertyname="set"><set><value>上海SH</value><value>北京BJ</value><value>杭州HZ</value></set></property><!--Map注入--><propertyname="map"><map><entry><key><value>周杰倫</value></key><value>我是如此相信</value></entry><entry><key><value>林俊杰</value></key><value>可惜沒(méi)如果</value></entry><entry><key><value>陳奕迅</value></key><value>十年</value></entry></map></property><!--Properties注入--><propertyname="properties"><props><propkey="上海">東方明珠</prop><propkey="北京">天安門</prop><propkey="杭州">西湖</prop></props></property></bean></beans>

構(gòu)造器注入

注:

提供帶參構(gòu)造器

單個(gè)Bean對(duì)象作為參數(shù)

Java 代碼

publicclassUserService{privateUserDao userDao;// JavaBean 對(duì)象publicUserService(UserDao userDao){this.userDao=userDao;}publicvoidtest(){System.out.println("UserService Test...");userDao.test();}}

XML配置

<?xml version="1.0" encoding="UTF-8"?><beansxmlns="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"><!--

? ? ? ? IOC通過(guò)構(gòu)造器注入:

? ? ? ? ? ? 通過(guò)constructor-arg標(biāo)簽進(jìn)行注入

? ? ? ? ? ? ? ? name:屬性名稱

? ? ? ? ? ? ? ? ref:指定bean標(biāo)簽的id屬性值

? ? --><beanid="userDao"class="com.xxxx.dao.UserDao"></bean><beanid="userService"class="com.xxxx.service.UserService"><constructor-argname="userDao"ref="userDao"></constructor-arg></bean></beans>

多個(gè)Bean對(duì)象作為參數(shù)

Java 代碼

publicclassUserService{privateUserDao userDao;// JavaBean 對(duì)象privateAccountDao accountDao// JavaBean 對(duì)象publicUserService(UserDao userDao,AccountDao accountDao){this.userDao=userDao;this.accountDao=accountDao;}publicvoidtest(){System.out.println("UserService Test...");userDao.test();accountDao.test();}}

XML配置

<?xml version="1.0" encoding="UTF-8"?><beansxmlns="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"><!--

? ? ? ? IOC通過(guò)構(gòu)造器注入:

? ? ? ? ? ? 通過(guò)constructor-arg標(biāo)簽進(jìn)行注入

? ? ? ? ? ? ? ? name:屬性名稱

? ? ? ? ? ? ? ? ref:指定bean標(biāo)簽的id屬性值

? ? --><beanid="userDao"class="com.xxxx.dao.UserDao"></bean><beanid="accountDao"class="com.xxxx.dao.AccountDao"></bean><beanid="userService"class="com.xxxx.service.UserService"><constructor-argname="userDao"ref="userDao"></constructor-arg><constructor-argname="accountDao"ref="accountDao"></constructor-arg></bean></beans>

Bean對(duì)象和常用對(duì)象作為參數(shù)

Java 代碼

publicclassUserService{privateUserDao userDao;// JavaBean 對(duì)象privateAccountDao accountDao;// JavaBean 對(duì)象privateString uname;// 字符串類型publicUserService(UserDao userDao,AccountDao accountDao,String uname){this.userDao=userDao;this.accountDao=accountDao;this.uname=uname;}publicvoidtest(){System.out.println("UserService Test...");userDao.test();accountDao.test();System.out.println("uname:"+uname);}}

XML配置

<?xml version="1.0" encoding="UTF-8"?><beansxmlns="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"><!--

? ? ? ? IOC通過(guò)構(gòu)造器注入:

? ? ? ? ? ? 通過(guò)constructor-arg標(biāo)簽進(jìn)行注入

? ? ? ? ? ? ? ? name:屬性名稱

? ? ? ? ? ? ? ? ref:指定bean標(biāo)簽的id屬性值

value:基本類型 常用對(duì)象的值

? ? ? ? ? ? ? ? index:構(gòu)造器中參數(shù)的下標(biāo),從0開(kāi)始

? ? --><beanid="userDao"class="com.xxxx.dao.UserDao"></bean><beanid="accountDao"class="com.xxxx.dao.AccountDao"></bean><beanid="userService"class="com.xxxx.service.UserService"><constructor-argname="userDao"ref="userDao"></constructor-arg><constructor-argname="accountDao"ref="accountDao"></constructor-arg><constructor-argname="uname"value="admin"></constructor-arg></bean></beans>

循環(huán)依賴問(wèn)題

循環(huán)問(wèn)題產(chǎn)生的原因:

? Bean通過(guò)構(gòu)造器注入,之間彼此相互依賴對(duì)方導(dǎo)致bean無(wú)法實(shí)例化。

問(wèn)題展示:

Java 代碼

publicclassAccountService{privateRoleService roleService;publicAccountService(RoleService roleService){this.roleService=roleService;}publicvoidtest(){System.out.println("AccountService Test...");}}publicclassRoleService{privateAccountService accountService;publicRoleService(AccountService accountService){this.accountService=accountService;}publicvoidtest(){System.out.println("RoleService Test...");}}

XML配置

<!--

? ? 如果多個(gè)bean對(duì)象中互相注入,則會(huì)出現(xiàn)循環(huán)依賴的問(wèn)題

? ? 可以通過(guò)set方法注入解決

--><beanid="accountService"class="com.xxxx.service.AccountService"><constructor-argname="roleService"ref="roleService"/></bean><beanid="roleService"class="com.xxxx.service.RoleService"><constructor-argname="accountService"ref="accountService"/></bean>

如何解決:將構(gòu)造器注入改為set方法注入

Java代碼

publicclassAccountService{privateRoleService roleService;/* public AccountService(RoleService roleService) {

? ? ? ? this.roleService = roleService;

? ? }*/publicvoidsetRoleService(RoleService roleService){this.roleService=roleService;}publicvoidtest(){System.out.println("AccountService Test...");}}publicclassRoleService{privateAccountService accountService;/* public RoleService(AccountService accountService) {

? ? ? ? this.accountService = accountService;

? ? }*/publicvoidsetAccountService(AccountService accountService){this.accountService=accountService;}publicvoidtest(){System.out.println("RoleService Test...");}}

XML配置

<!--

<bean id="accountService" class="com.xxxx.service.AccountService">

? ? <constructor-arg name="roleService" ref="roleService"/>

? ? </bean>

? ? <bean id="roleService" class="com.xxxx.service.RoleService">

? ? ? ? <constructor-arg name="accountService" ref="accountService"/>

? ? </bean>

--><!--修改為set方法注入--><beanid="accountService"class="com.xxxx.service.AccountService"><propertyname="roleService"ref="roleService"/></bean><beanid="roleService"class="com.xxxx.service.RoleService"><propertyname="accountService"ref="accountService"/></bean>

靜態(tài)工廠注入

定義靜態(tài)工廠類

publicclassStaticFactory{// 定義靜態(tài)方法publicstaticTypeDaocreateTypeDao(){returnnewTypeDao();}}

Java代碼

publicclassTypeService{privateTypeDao typeDao;publicvoidsetTypeDao(TypeDao typeDao){this.typeDao=typeDao;}publicvoidtest(){System.out.println("TypeService Test...");}}

XML配置

在配置文件中設(shè)置bean標(biāo)簽,指定工廠對(duì)象并設(shè)置對(duì)應(yīng)的方法

<beanid="typeService"class="com.xxxx.service.TypeService"><propertyname="typeDao"ref="typeDao"/></bean><!--

靜態(tài)工廠注入:

靜態(tài)工廠注入也是借助set方法注入,只是被注入的bean對(duì)象的實(shí)例化是通過(guò)靜態(tài)工廠實(shí)例化的

--><beanid="typeDao"class="com.xxxx.factory.StaticFactory"factory-method="createTypeDao"></bean>

實(shí)例化工廠注入

定義工廠類

publicclassInstanceFactory{publicTypeDaocreateTypeDao(){returnnewTypeDao();}}

Java代碼

publicclassTypeService{privateTypeDao typeDao;publicvoidsetTypeDao(TypeDao typeDao){this.typeDao=typeDao;}publicvoidtest(){System.out.println("TypeService Test...");}}

XML配置

聲明工廠bean標(biāo)簽,聲明bean對(duì)象,指明工廠對(duì)象和工廠方法

<beanid="typeService"class="com.xxxx.service.TypeService"><propertyname="typeDao"ref="typeDao"/></bean><!--

實(shí)例化工廠注入:

實(shí)例化工廠注入也是借助set方法注入,只是被注入的bean對(duì)象的實(shí)例化是通過(guò)實(shí)例化工廠實(shí)例化的

--><beanid="instanceFactory"class="com.xxxx.factory.InstanceFactory"></bean><beanid="typeDao"factory-bean="instanceFactory"factory-method="createTypeDao"></bean>

重點(diǎn)掌握set注入和構(gòu)造器注入,工廠方式了解即可。實(shí)際開(kāi)發(fā)中基本使用set方式注入bean。

注入方式的選擇

??開(kāi)發(fā)項(xiàng)目中set方式注入首選

? 使用構(gòu)造注入可以在構(gòu)建對(duì)象的同時(shí)一并完成依賴關(guān)系的建立,對(duì)象一建立則所有的一切也就準(zhǔn)備好了,但如果要建立的對(duì)象關(guān)系很多,使用構(gòu)造器注入會(huì)在構(gòu)建函數(shù)上留下一長(zhǎng)串的參數(shù),且不易記憶,這時(shí)使用Set注入會(huì)是個(gè)不錯(cuò)的選擇。

使用Set注入可以有明確的名稱,可以了解注入的對(duì)象會(huì)是什么,像setXXX()這樣的名稱會(huì)比記憶Constructor上某個(gè)參數(shù)的位置代表某個(gè)對(duì)象更好。

p名稱空間的使用

? spring2.5以后,為了簡(jiǎn)化setter方法屬性注入,引用p名稱空間的概念,可以將 子元素,簡(jiǎn)化為元素屬性配置。

屬性字段提供 set 方法

publicclassUserService{// 業(yè)務(wù)對(duì)象UserDao set注入(提供set方法)privateUserDao userDao;publicvoidsetUserDao(UserDao userDao){this.userDao=userDao;}// 常用對(duì)象String? set注入(提供set方法)privateString host;publicvoidsetHost(String host){this.host=host;}}

在配置文件 spring.xml 引入 p 名稱空間

xmlns:p="http://www.springframework.org/schema/p"

<?xml version="1.0" encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beans? ? ? ? https://www.springframework.org/schema/beans/spring-beans.xsd"><beanid="userDao"class="com.xxxx.dao.UserDao"></bean><!--

p:屬性名:="xxx" 引入常量值

p:屬性名-ref:="xxx" 引入其他Bean對(duì)象的id屬性值

--><beanid="userService"class="com.xxxx.service.UserService"p:userDao-ref="userDao"p:host="127.0.0.1"/></beans>

Spring IOC 自動(dòng)裝配(注入)

注解方式注入 Bean

? 對(duì)于 bean 的注入,除了使用 xml 配置以外,可以使用注解配置。注解的配置,可以簡(jiǎn)化配置文件,提高開(kāi)發(fā)的速度,使程序看上去更簡(jiǎn)潔。對(duì)于注解的解釋,Spring對(duì)于注解有專門的解釋器,對(duì)定義的注解進(jìn)行解析,實(shí)現(xiàn)對(duì)應(yīng)bean對(duì)象的注入。通過(guò)反射技術(shù)實(shí)現(xiàn)

準(zhǔn)備環(huán)境

修改配置文件

<beansxmlns="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? ? ? http://www.springframework.org/schema/context/spring-context.xsd">

開(kāi)啟自動(dòng)化注入

<!--開(kāi)啟自動(dòng)化裝配(注入)--><context:annotation-config/><beanid="userDao"class="com.xxxx.dao.UserDao"></bean><beanid="userService"class="com.xxxx.service.UserService"></bean>

給注入的bean對(duì)象添加注解

@Resource注解

@Resource注解實(shí)現(xiàn)自動(dòng)注入(反射)

默認(rèn)根據(jù)屬性字段名稱查找對(duì)應(yīng)的bean對(duì)象 (屬性字段的名稱與bean標(biāo)簽的id屬性值相等)

如果屬性字段名稱未找到,則會(huì)通過(guò)類型(Class類型)查找

屬性可以提供set方法,也可以不提供set方法

注解可以聲明在屬性級(jí)別 或 set方法級(jí)別

可以設(shè)置name屬性,name屬性值必須與bean標(biāo)簽的id屬性值一致;如果設(shè)置了name屬性值,就只會(huì)按照name屬性值查找bean對(duì)象

當(dāng)注入接口時(shí),如果接口只有一個(gè)實(shí)現(xiàn)則正常實(shí)例化;如果接口存在多個(gè)實(shí)現(xiàn),則需要使用name屬性指定需要被實(shí)例化的bean對(duì)象

代碼示例

默認(rèn)根據(jù)屬性字段名稱查找對(duì)應(yīng)的bean對(duì)象 (屬性字段的名稱與bean標(biāo)簽的id屬性值相等)

/**

* @Resource注解實(shí)現(xiàn)自動(dòng)注入(反射)

*? 默認(rèn)根據(jù)屬性字段名稱查找對(duì)應(yīng)的bean對(duì)象 (屬性字段的名稱與bean標(biāo)簽的id屬性值相等)

*/publicclassUserService{@ResourceprivateUserDao userDao;// 屬性字段的名稱與bean標(biāo)簽的id屬性值相等publicvoidsetUserDao(UserDao userDao){this.userDao=userDao;}publicvoidtest(){// 調(diào)用UserDao的方法userDao.test();}}

如果屬性字段名稱未找到,則會(huì)通過(guò)類型(Class類型)查找

/**

* @Resource注解實(shí)現(xiàn)自動(dòng)注入(反射)

*? 如果屬性字段名稱未找到,則會(huì)通過(guò)類型(Class類型)查找

*/publicclassUserService{@ResourceprivateUserDao ud;// 當(dāng)在配置文件中屬性字段名(ud)未找到,則會(huì)查找對(duì)應(yīng)的class(UserDao類型)publicvoidsetUd(UserDao ud){this.ud=ud;}publicvoidtest(){// 調(diào)用UserDao的方法ud.test();}}

屬性可以提供set方法,也可以不提供set方法

/**

* @Resource注解實(shí)現(xiàn)自動(dòng)注入(反射)

*? 屬性可以提供set方法,也可以不提供set方法

*/publicclassUserService{@ResourceprivateUserDao userDao;// 不提供set方法publicvoidtest(){// 調(diào)用UserDao的方法userDao.test();}}

注解可以聲明在屬性級(jí)別 或 set方法級(jí)別

/**

* @Resource注解實(shí)現(xiàn)自動(dòng)注入(反射)

*? 注解可以聲明在屬性級(jí)別 或 set方法級(jí)別

*/publicclassUserService{privateUserDao userDao;@Resource// 注解也可設(shè)置在set方法上publicvoidsetUserDao(UserDao userDao){this.userDao=userDao;}publicvoidtest(){// 調(diào)用UserDao的方法userDao.test();}}

可以設(shè)置name屬性,name屬性值必須與bean標(biāo)簽的id屬性值一致;如果設(shè)置了name屬性值,就只會(huì)按照name屬性值查找bean對(duì)象

/**

* @Resource注解實(shí)現(xiàn)自動(dòng)注入(反射)

*? 可以設(shè)置name屬性,name屬性值必須與bean的id屬性值一致;

*? 如果設(shè)置了name屬性值,就只會(huì)按照name屬性值查找bean對(duì)象

*/publicclassUserService{@Resource(name="userDao")// name屬性值與配置文件中bean標(biāo)簽的id屬性值一致privateUserDao ud;publicvoidtest(){// 調(diào)用UserDao的方法ud.test();}}

當(dāng)注入接口時(shí),如果接口只有一個(gè)實(shí)現(xiàn)則正常實(shí)例化;如果接口存在多個(gè)實(shí)現(xiàn),則需要使用name屬性指定需要被實(shí)例化的bean對(duì)象

定義接口類 IUserDao.java

packagecom.xxxx.dao;/**

* 定義接口類

*/publicinterfaceIUserDao{publicvoidtest();}

定義接口實(shí)現(xiàn)類 UserDao01.java

packagecom.xxxx.dao;/**

* 接口實(shí)現(xiàn)類

*/publicclassUserDao01implementsIUserDao{@Overridepublicvoidtest(){System.out.println("UserDao01...");}}

定義接口實(shí)現(xiàn)類 UserDao02.java

packagecom.xxxx.dao;/**

* 接口實(shí)現(xiàn)類

*/publicclassUserDao02implementsIUserDao{@Overridepublicvoidtest(){System.out.println("UserDao02...");}}

XML配置文件

<!--開(kāi)啟自動(dòng)化裝配(注入)--><context:annotation-config/><beanid="userService"class="com.xxxx.service.UserService"></bean><beanid="userDao01"class="com.xxxx.dao.UserDao01"></bean><beanid="userDao02"class="com.xxxx.dao.UserDao01"></bean>

使用注解 UserService.java

/**

* @Resource注解實(shí)現(xiàn)自動(dòng)注入(反射)

*? 當(dāng)注入接口時(shí),如果接口只有一個(gè)實(shí)現(xiàn)則正常實(shí)例化;如果接口存在多個(gè)實(shí)現(xiàn),則需要使用name屬性指定需要被實(shí)例化的bean對(duì)象

*/publicclassUserService{@Resource(name="userDao01")// name屬性值與其中一個(gè)實(shí)現(xiàn)類的bean標(biāo)簽的id屬性值一致privateIUserDao iUserDao;// 注入接口(接口存在多個(gè)實(shí)現(xiàn))publicvoidtest(){iUserDao.test();}}

@Autowired注解

@Autowired注解實(shí)現(xiàn)自動(dòng)化注入:

默認(rèn)通過(guò)類型(Class類型)查找bean對(duì)象 與屬性字段的名稱無(wú)關(guān)

屬性可以提供set方法,也可以不提供set方法

注解可以聲明在屬性級(jí)別 或 set方法級(jí)別

可以添加@Qualifier結(jié)合使用,通過(guò)value屬性值查找bean對(duì)象(value屬性值必須要設(shè)置,且值要與bean標(biāo)簽的id屬性值對(duì)應(yīng))

默認(rèn)通過(guò)類型(Class類型)查找bean對(duì)象 與屬性字段的名稱無(wú)關(guān)

/**

* @Autowired注解實(shí)現(xiàn)自動(dòng)化注入

*? 默認(rèn)通過(guò)類型(Class類型)查找bean對(duì)象? 與屬性字段的名稱無(wú)關(guān)

*/publicclassUserService{@AutowiredprivateUserDao userDao;// 默認(rèn)通過(guò)類型(Class類型)查找bean對(duì)象? 與屬性字段的名稱無(wú)關(guān)publicvoidsetUserDao(UserDao userDao){this.userDao=userDao;}publicvoidtest(){// 調(diào)用UserDao的方法userDao.test();}}

屬性可以提供set方法,也可以不提供set方法

/**

* @Autowired注解實(shí)現(xiàn)自動(dòng)化注入

*? 屬性可以提供set方法,也可以不提供set方法

*/publicclassUserService{@AutowiredprivateUserDao userDao;// 不提供set方法publicvoidtest(){// 調(diào)用UserDao的方法userDao.test();}}

注解可以聲明在屬性級(jí)別 或 set方法級(jí)別

/**

* @Autowired注解實(shí)現(xiàn)自動(dòng)化注入

*? 注解可以聲明在屬性級(jí)別 或 set方法級(jí)別

*/publicclassUserService{privateUserDao userDao;@Autowired// 注解可以聲明在set方法級(jí)別publicvoidsetUserDao(UserDao userDao){this.userDao=userDao;}publicvoidtest(){// 調(diào)用UserDao的方法userDao.test();}}

可以添加@Qualifier結(jié)合使用,通過(guò)value屬性值查找bean對(duì)象(value屬性值必須要設(shè)置,且值要與bean標(biāo)簽的id屬性值對(duì)應(yīng))

/**

* @Autowired注解實(shí)現(xiàn)自動(dòng)化注入

*? 可以添加@Qualifier結(jié)合使用,通過(guò)value屬性值查找bean對(duì)象

value屬性值必須要設(shè)置,且值要與bean標(biāo)簽的id屬性值對(duì)應(yīng)

*/publicclassUserService{@Autowired@Qualifier(value="userDao")// value屬性值必須要設(shè)置,且值要與bean標(biāo)簽的id屬性值對(duì)應(yīng)privateUserDao userDao;publicvoidtest(){userDao.test();}}

推薦使用**@Resource** 注解是屬于J2EE的,減少了與Spring的耦合。

Spring IOC 掃描器

? 實(shí)際的開(kāi)發(fā)中,bean的數(shù)量非常多,采用手動(dòng)配置bean的方式已無(wú)法滿足生產(chǎn)需要,Spring這時(shí)候同樣提供了掃描的方式,對(duì)掃描到的bean對(duì)象統(tǒng)一進(jìn)行管理,簡(jiǎn)化開(kāi)發(fā)配置,提高開(kāi)發(fā)效率。

Spring IOC 掃描器的配置

Spring IOC 掃描器

? 作用:bean對(duì)象統(tǒng)一進(jìn)行管理,簡(jiǎn)化開(kāi)發(fā)配置,提高開(kāi)發(fā)效率

? 1、設(shè)置自動(dòng)化掃描的范圍

? ? ? ? ? ? 如果bean對(duì)象未在指定包范圍,即使聲明了注解,也無(wú)法實(shí)例化

? 2、使用指定的注解(聲明在類級(jí)別)? ? bean對(duì)象的id屬性默認(rèn)是 類的首字母小寫

? ? ? ? Dao層:

? ? ? ? ? ? @Repository

? ? ? ? Service層:

? ? ? ? ? ? @Service

? ? ? ? Controller層:

? ? ? ? ? ? @Controller

? ? ? ? 任意類:

? ? ? ? ? ? @Component

? ? 注:開(kāi)發(fā)過(guò)程中建議按照指定規(guī)則聲明注解

設(shè)置自動(dòng)化掃描范圍

<?xml version="1.0" encoding="UTF-8"?><beansxmlns="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? ? ? http://www.springframework.org/schema/context/spring-context.xsd"><!-- 設(shè)置自動(dòng)化掃描的范圍 --><context:component-scanbase-package="com.xxxx"/></beans>

使用特定的注解

@Repository (Dao層)

@RepositorypublicclassResourceDao{publicvoidtest(){System.out.println("ResourceDao...");}}

@Service(Service層 )

@ServicepublicclassResourceService{@ResourceprivateResourceDao resourceDao;// service層注入dao層的bean對(duì)象publicvoidtest(){System.out.println("ResourceService...");resourceDao.test();}}

@Controller (Controller 層 )

@ControllerpublicclassResourceController{@AutowiredprivateResourceService resourceService;// Controller層注入service層的bean對(duì)象publicvoidtest(){System.out.println("ResourceController...");resourceService.test();}}

@Component (任意層)

@ComponentpublicclassPropertyUtils{publicvoidtest(){System.out.println("PropertyUtils...");}}

Spring 模擬用戶登錄流程

Dao層 (查詢用戶記錄)

定義JavaBean User.java

packagecom.xxxx.po;/**

* User 用戶實(shí)體類

*/publicclassUser{privateString userName;// 用戶名稱privateString userPwd;// 用戶密碼publicStringgetUserName(){returnuserName;}publicvoidsetUserName(String userName){this.userName=userName;}publicStringgetUserPwd(){returnuserPwd;}publicvoidsetUserPwd(String userPwd){this.userPwd=userPwd;}}

編寫Dao層 UserDao.java

packagecom.xxxx.dao;importcom.xxxx.po.User;importorg.springframework.stereotype.Repository;@RepositorypublicclassUserDao{privatefinalString USERNAME="admin";privatefinalString USERPWD="admin";/**

? ? * 通過(guò)用戶名稱查詢用戶對(duì)象

? ? * @param userName

? ? * @return

? ? */publicUserqueryUserByUserName(String userName){User user=null;// 判斷用戶名稱是否正確if(!USERNAME.equals(userName)){// 如果不正確,返回nullreturnnull;}// 如果正確,將用戶名稱和密碼設(shè)置到user對(duì)象中user=newUser();user.setUserName(USERNAME);user.setUserPwd(USERPWD);returnuser;}}

Service層 (業(yè)務(wù)邏輯處理)

定義業(yè)務(wù)處理返回消息模型 MessageModel.java

packagecom.xxxx.po.vo;/**

* 定義業(yè)務(wù)處理返回消息模型

*? ? 封裝返回結(jié)果

*/publicclassMessageModel{privateInteger resultCode=1;// 結(jié)果狀態(tài)碼? 1=成功,0=失敗privateString resultMsg="操作成功!";// 結(jié)果提示信息publicIntegergetResultCode(){returnresultCode;}publicvoidsetResultCode(Integer resultCode){this.resultCode=resultCode;}publicStringgetResultMsg(){returnresultMsg;}publicvoidsetResultMsg(String resultMsg){this.resultMsg=resultMsg;}}

編寫Service層 UserService.java

packagecom.xxxx.service;importcom.xxxx.dao.UserDao1;importcom.xxxx.po.User;importcom.xxxx.po.vo.MessageModel;importorg.springframework.stereotype.Service;importjavax.annotation.Resource;@ServicepublicclassUserService{@ResourceprivateUserDao userDao;/**

? ? * 驗(yàn)證用戶登錄

? ? * @param userName

? ? * @param userPwd

? ? * @return

? ? */publicMessageModeluserLoginCheck(String userName,String userPwd){// 定義業(yè)務(wù)處理返回消息模型MessageModel messageModel=newMessageModel();// 判斷用戶名稱是否非空if(null==userName||"".equals(userName.trim())){messageModel.setResultCode(0);messageModel.setResultMsg("用戶名不能為空!");returnmessageModel;}// 判斷用戶密碼是否為空if(null==userPwd||"".equals(userPwd.trim())){messageModel.setResultCode(0);messageModel.setResultMsg("密碼不能為空!");returnmessageModel;}// 通過(guò)用戶名稱查詢用戶對(duì)象User user=userDao.queryUserByUserName(userName);// 判斷用戶對(duì)象是否為空if(null==user){messageModel.setResultCode(0);messageModel.setResultMsg("該用戶不存在!");returnmessageModel;}// 如果用戶對(duì)象不為空,判斷密碼是否正確if(!user.getUserPwd().equals(userPwd)){messageModel.setResultCode(0);messageModel.setResultMsg("用戶密碼不正確!");returnmessageModel;}// 登錄成功messageModel.setResultMsg("登錄成功!");returnmessageModel;}}

Controller層 (接收請(qǐng)求)

編寫Controller層 UserController.java

packagecom.xxxx.controller;importcom.xxxx.po.vo.MessageModel;importcom.xxxx.service.UserService1;importorg.springframework.stereotype.Controller;importjavax.annotation.Resource;@ControllerpublicclassUserController{@ResourceprivateUserService userService;/**

? ? * 用戶登錄

? ? * @param userName

? ? * @param userPwd

? ? * @return

? ? */publicMessageModellogin(String userName,String userPwd){// 調(diào)用Dao層判斷用戶登錄操作,返回結(jié)果MessageModel messageModel=userService.userLoginCheck(userName,userPwd);returnmessageModel;}}

通過(guò) JUnit 進(jìn)行測(cè)試

packagecom.xxxx;importcom.xxxx.controller.UserController;importcom.xxxx.po.vo.MessageModel;importorg.junit.Test;importorg.springframework.context.ApplicationContext;importorg.springframework.context.support.ClassPathXmlApplicationContext;publicclassTestLogin{@Testpublicvoidtest(){// 得到Spring容器上下文環(huán)境ApplicationContext ac=newClassPathXmlApplicationContext("spring.xml");// 得到UserController實(shí)例化對(duì)象UserController userController=(UserController)ac.getBean("userController");// 傳入?yún)?shù)調(diào)用UserController的方法,返回封裝類MessageModel messageModel=userController.login("admin","admin");System.out.println("狀態(tài)碼:"+messageModel.getResultCode()+",提示信息:"+messageModel.getResultMsg());}}

Bean的作用域與生命周期

Bean的作用域

? 默認(rèn)情況下,我們從Spring容器中拿到的對(duì)象均是單例的,對(duì)于bean的作用域類型如下:

singleton 作用域

??注意: lazy-init是懶加載, 如果等于true時(shí)作用是指Spring容器啟動(dòng)的時(shí)候不會(huì)去實(shí)例化這個(gè)bean, 而是在程序調(diào)用時(shí)才去實(shí)例化. 默認(rèn)是false即Spring容器啟動(dòng)時(shí)實(shí)例化.

? 默認(rèn)情況下,被管理的bean只會(huì)IOC容器中存在一個(gè)實(shí)例,對(duì)于所有獲取該Bean的操作Spring容器將只返回同一個(gè)Bean。

??容器在啟動(dòng)的情況下就實(shí)例化所有singleton 的 bean對(duì)象,并緩存與容器中

lazy-init屬性(懶加載)

如果為false,則在IOC容器啟動(dòng)時(shí)會(huì)實(shí)例化bean對(duì)象,默認(rèn)false

? 如果為true,則IOC容器啟動(dòng)時(shí)不會(huì)實(shí)例化Bean對(duì)象,在使用bean對(duì)象時(shí)才會(huì)實(shí)例化

lazy-init設(shè)置為false有什么好處?

? 1)可以提前發(fā)現(xiàn)潛在的配置問(wèn)題

? 2)Bean 對(duì)象存在于緩存中,使用時(shí)不用再去實(shí)例化bean,加快程序運(yùn)行效率

什么對(duì)象適合作為單例對(duì)象?

? 一般來(lái)說(shuō)對(duì)于無(wú)狀態(tài)或狀態(tài)不可改變的對(duì)象適合使用單例模式。(不存在會(huì)改變對(duì)象狀態(tài)的成員變量)

? 比如:controller層、service層、dao層

什么是無(wú)狀態(tài)或狀態(tài)不可改變的對(duì)象?

? 實(shí)際上對(duì)象狀態(tài)的變化往往均是由于屬性值得變化而引起的,比如user類 姓名屬性會(huì)有變化,屬性姓名的變化一般會(huì)引起user對(duì)象狀態(tài)的變化。對(duì)于我們的程序來(lái)說(shuō),無(wú)狀態(tài)對(duì)象沒(méi)有實(shí)例變量的存在,保證了線程的安全性,service 層業(yè)務(wù)對(duì)象即是無(wú)狀態(tài)對(duì)象。線程安全的。

prototype 作用域

? 通過(guò)scope=“prototype” 設(shè)置bean的類型 ,每次向Spring容器請(qǐng)求獲取Bean都返回一個(gè)全新的Bean,相對(duì)于"singleton"來(lái)說(shuō)就是不緩存Bean,每次都是一個(gè)根據(jù)Bean定義創(chuàng)建的全新Bean。

Web應(yīng)用中的作用域

request作用域

表示每個(gè)請(qǐng)求需要容器創(chuàng)建一個(gè)全新Bean。比如提交表單的數(shù)據(jù)必須是對(duì)每次請(qǐng)求新建一個(gè)Bean來(lái)保持這些表單數(shù)據(jù),請(qǐng)求結(jié)束釋放這些數(shù)據(jù)。

session作用域

表示每個(gè)會(huì)話需要容器創(chuàng)建一個(gè)全新Bean。比如對(duì)于每個(gè)用戶一般會(huì)有一個(gè)會(huì)話,該用戶的用戶信息需要存儲(chǔ)到會(huì)話中,此時(shí)可以將該Bean作用域配置為session級(jí)別。

globalSession作用域

類似于session作用域,其用于portlet(Portlet是基于Java的Web組件,由Portlet容器管理,并由容器處理請(qǐng)求,生產(chǎn)動(dòng)態(tài)內(nèi)容)環(huán)境的web應(yīng)用。如果在非portlet環(huán)境將視為session作用域。

? 配置方式和基本的作用域相同,只是必須要有web環(huán)境支持,并配置相應(yīng)的容器監(jiān)聽(tīng)器或攔截器從而能應(yīng)用這些作用域,目前先熟悉概念,后續(xù)集成web時(shí)講解具體使用,大家只需要知道有這些作用域就可以了。

Bean的生命周期

? 對(duì)比已經(jīng)學(xué)過(guò)的servlet 生命周期(容器啟動(dòng)裝載并實(shí)例化servlet類,初始化servlet,調(diào)用service方法,銷毀servlet)。

? 同樣對(duì)于Spring容器管理的bean也存在生命周期的概念

??在Spring中,Bean的生命周期包括Bean的定義、初始化、使用和銷毀4個(gè)階段

Bean的定義

? 在Spring中,通常是通過(guò)配置文檔的方式來(lái)定義Bean的。

? 在一個(gè)配置文檔中,可以定義多個(gè)Bean。

Bean 的初始化

? 默認(rèn)在IOC容器加載時(shí),實(shí)例化對(duì)象。

Spring bean 初始化有兩種方式:

? **方式一:**在配置文檔中通過(guò)指定 init-method 屬性來(lái)完成。

publicclassRoleService{// 定義初始化時(shí)需要被調(diào)用的方法publicvoidinit(){System.out.println("RoleService init...");}}

<!-- 通過(guò)init-method屬性指定方法 --><beanid="roleService"class="com.xxxx.service.RoleService"init-method="init"></bean>

??方式二:?實(shí)現(xiàn) org.springframework.beans.factory.InitializingBean 接口。

publicclassRoleServiceimplementsInitializingBean{@OverridepublicvoidafterPropertiesSet()throwsException{System.out.println("RoleService init...");}}

<beanid="roleService"class="com.xxxx.service.RoleService"></bean>

? Bean對(duì)象實(shí)例化過(guò)程是在Spring容器初始化時(shí)被實(shí)例化的,但也不是不可改變的,可以通過(guò) lazy-init=“true” 屬性延遲bean對(duì)象的初始化操作,此時(shí)再調(diào)用getBean 方法時(shí)才會(huì)進(jìn)行bean的初始化操作

Bean 的使用

**方式一:**使用 BeanFactory

// 得到Spring的上下文環(huán)境BeanFactory factory=newClassPathXmlApplicationContext("spring.xml");RoleService roleService=(RoleService)factory.getBean("roleService");

**方式二:**使用 ApplicationContext

// 得到Spring的上下文環(huán)境ApplicationContext ac=newClassPathXmlApplicationContext("spring.xml");RoleService roleService=(RoleService)ac.getBean("roleService");

Bean的銷毀

? 實(shí)現(xiàn)銷毀方式(Spring容器會(huì)維護(hù)bean對(duì)象的管理,可以指定bean對(duì)象的銷毀所要執(zhí)行的方法)。

? **步驟一:**實(shí)現(xiàn)銷毀方式(Spring容器會(huì)維護(hù)bean對(duì)象的管理,可以指定bean對(duì)象的銷毀所要執(zhí)行的方法)

<beanid="roleService"class="com.xxxx.service.RoleService"destroy-method="destroy"></bean>

**步驟二:**通過(guò) AbstractApplicationContext 對(duì)象,調(diào)用其close方法實(shí)現(xiàn)bean的銷毀過(guò)程

AbstractApplicationContext ctx=newClassPathXmlApplicationContext("spring.xml");ctx.close();

IOC/DI-控制反轉(zhuǎn)和依賴注入

? ? ? 將對(duì)象實(shí)例化的創(chuàng)建過(guò)程轉(zhuǎn)交給外部容器(IOC容器 充當(dāng)工廠角色)去負(fù)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容