日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring5参考指南:依赖注入

發(fā)布時(shí)間:2024/2/28 javascript 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring5参考指南:依赖注入 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

    • 依賴注入
    • 依賴注入的配置詳解
    • depends-on
    • lazy-init
    • 自動(dòng)裝載
    • 方法注入

依賴注入

依賴注入就是在Spring創(chuàng)建Bean的時(shí)候,去實(shí)例化該Bean構(gòu)造函數(shù)所需的參數(shù),或者通過Setter方法去設(shè)置該Bean的屬性。

Spring的依賴注入有兩種基于構(gòu)造函數(shù)的依賴注入和基于setter的依賴注入。

基于構(gòu)造函數(shù)的依賴注入

構(gòu)造函數(shù)的注入是通過構(gòu)造函數(shù)的參數(shù)來實(shí)現(xiàn)的。如下所示:

public class ExampleBean {// Number of years to calculate the Ultimate Answerprivate int years;// The Answer to Life, the Universe, and Everythingprivate String ultimateAnswer;public ExampleBean(int years, String ultimateAnswer) {this.years = years;this.ultimateAnswer = ultimateAnswer;} }

該Bean有一個(gè)兩個(gè)參數(shù)的構(gòu)造函數(shù),那么怎么注入這些參數(shù)呢?
有三種方法。

方法1:按構(gòu)造函數(shù)的類型匹配:

<bean id="exampleBeanA" class="com.flydean.beans.ExampleBean"><constructor-arg type="int" value="7500000"/><constructor-arg type="java.lang.String" value="42"/></bean>

這里通過指定參數(shù)的類型,即可以指定哪個(gè)參數(shù)是years,哪個(gè)參數(shù)是ultimateAnswer。

方法2:構(gòu)造函數(shù)索引:

<bean id="exampleBeanB" class="com.flydean.beans.ExampleBean"><constructor-arg index="0" value="7500000"/><constructor-arg index="1" value="42"/></bean>

Spring中可以通過構(gòu)造函數(shù)的索引來指定特定的參數(shù)。要注意Spring的索引是從0開始的。

方法3:構(gòu)造函數(shù)名字匹配:

<bean id="exampleBeanC" class="com.flydean.beans.ExampleBeanWithConstructorProperties"><constructor-arg name="years" value="7500000"/><constructor-arg name="ultimateAnswer" value="42"/></bean>

如果通過構(gòu)造函數(shù)的名字來匹配,需要注意必須在編譯的時(shí)候開啟調(diào)試標(biāo)志,要不然Spring不能在構(gòu)造函數(shù)中找到參數(shù)名。

如果不想啟用調(diào)試標(biāo)志,則必須使用@ConstructorProperties JDK注解顯式命名構(gòu)造函數(shù)參數(shù)。

public class ExampleBeanWithConstructorProperties {// Number of years to calculate the Ultimate Answerprivate int years;// The Answer to Life, the Universe, and Everythingprivate String ultimateAnswer;@ConstructorProperties({"years", "ultimateAnswer"})public ExampleBeanWithConstructorProperties(int years, String ultimateAnswer) {this.years = years;this.ultimateAnswer = ultimateAnswer;} }

基于Setter的注入

Setter注入主要用來無參構(gòu)造器或者獲得對(duì)象實(shí)例之后才設(shè)置對(duì)象的屬性。下面是Setter的例子:

public class SimpleMovieLister {// the SimpleMovieLister has a dependency on the MovieFinderprivate MovieFinder movieFinder;// a setter method so that the Spring container can inject a MovieFinderpublic void setMovieFinder(MovieFinder movieFinder) {this.movieFinder = movieFinder;}// business logic that actually uses the injected MovieFinder is omitted... }

對(duì)于的XML文件如下:

<!--Setter DI --><bean id="movieFinder" class="com.flydean.beans.MovieFinder"/><bean id="simpleMovieLister" class="com.flydean.beans.SimpleMovieLister"><property name="movieFinder" ref="movieFinder"/></bean>

除了XML配置,也可以使用注解:@Component、@Controller。或者使用@Configuration注解中的@Bean方法。

如何選擇?

既然有這樣兩種注入方式,我們?cè)趺催x擇呢?

通常來說,對(duì)于必須的屬性,我們通過構(gòu)造函數(shù)來注入。對(duì)于可選屬性,我們通過Setter注入。當(dāng)然你也可以在Setter方法中使用@Required注解。

當(dāng)然如果第三方類不公開任何setter方法,那么構(gòu)造函數(shù)注入可能是DI的唯一可用形式。

循環(huán)依賴

循環(huán)依賴主要出現(xiàn)在構(gòu)造函數(shù)注入的情況。

類A通過構(gòu)造函數(shù)注入需要類B的實(shí)例,類B通過構(gòu)造函數(shù)注入需要類A的實(shí)例。如果為要相互注入的類A和類B配置bean,那么SpringIOC容器在運(yùn)行時(shí)檢測(cè)到這個(gè)循環(huán)引用,會(huì)拋出BeanCurrentlyInCreationException。

解決方式就是使用Setter注入。

依賴注入的配置詳解

基本類型,字符串或者其他

如果< property/>元素的value屬性是基本類型,Spring會(huì)將其轉(zhuǎn)換為類需要的類型,配置如下:

<!--Setter DI --><bean id="movieFinder" class="com.flydean.beans.MovieFinder"><property name="name" value="movie"/><property name="number" value="123456"/></bean>

這是一個(gè)常見的Setter注入。為了簡(jiǎn)潔,也可以使用p-namespace,如下:

<?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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="movieFinder" class="com.flydean.beans.MovieFinder"p:name="movie"p:number="123456"/> </beans>

Spring容器使用JavaBeans屬性編輯器機(jī)制將< value/>元素中的文本轉(zhuǎn)換為java.util.properties實(shí)例。這是一個(gè)很好的快捷方式,如下所示:

<bean id="mappings"class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><!-- typed as a java.util.Properties --><property name="properties"><value>jdbc.driver.className=com.mysql.jdbc.Driverjdbc.url=jdbc:mysql://localhost:3306/mydb</value></property></bean>

注意上面例子中的value里面的值。

ref

通過< ref/>標(biāo)記的bean屬性允許在同一容器或父容器中創(chuàng)建對(duì)任何bean的引用,而不管它是否在同一XML文件中。bean屬性的值可以與目標(biāo)bean的id屬性相同,也可以與目標(biāo)bean的name屬性中的一個(gè)值相同。以下示例顯示如何使用ref元素:

<ref bean="someBean"/>

內(nèi)部bean

在< property/> 或者 < constructor-arg/>元素內(nèi)部的< bean/>元素可以定義一個(gè)內(nèi)部bean,下面是個(gè)例子:

<bean id="simpleMovieLister" class="com.flydean.beans.SimpleMovieLister"><property name="movieFinder"><bean class="com.flydean.beans.MovieFinder"><property name="name" value="movie"/><property name="number" value="123456"/></bean></property></bean>

內(nèi)部bean定義不需要ID或名稱。如果指定,容器也不會(huì)使用這個(gè)值作為標(biāo)識(shí)符。容器在創(chuàng)建時(shí)也忽略作用域標(biāo)志,因?yàn)閮?nèi)部bean總是匿名的,并且總是用外部bean創(chuàng)建的。不可能單獨(dú)訪問內(nèi)部bean,也不可能將它們注入到除封閉bean之外的協(xié)作bean中。

集合

< list/>, < set/>, < map/>,和 < props/> 分別被用來設(shè)置Java Collection類型List, Set, Map,和 Properties 類型的屬性和參數(shù)。 下面是個(gè)例子:

<bean id="movieFinderE" class="com.flydean.beans.MovieFinder"></bean><bean class="com.flydean.beans.CollectionBean"><property name="properties"><props><prop key="administrator">administrator@example.org</prop><prop key="support">support@example.org</prop><prop key="development">development@example.org</prop></props></property><property name="arrayList"><list><value>"a list element followed by a reference"</value></list></property><property name="hashMap"><map><entry key="an entry" value="just some string"/><entry key ="a ref" value-ref="movieFinderE"/></map></property><property name="hashSet"><set><value>just some string</value><ref bean="movieFinderE" /></set></property></bean>

強(qiáng)類型集合

通過在Java 5中引入泛型類型,可以使用強(qiáng)類型集合。也就是說,可以聲明集合類型,使其只能包含(例如)字符串元素。如果使用Spring將強(qiáng)類型集合注入bean,則可以利用Spring的類型轉(zhuǎn)換支持,以便在將強(qiáng)類型集合實(shí)例的元素添加到集合之前將其轉(zhuǎn)換為適當(dāng)?shù)念愋汀O旅娴腏ava類和bean定義的例子:

public class SomeClass {private Map<String, Float> accounts;public void setAccounts(Map<String, Float> accounts) {this.accounts = accounts;} } <bean id="something" class="com.flydean.beans.SomeClass"><property name="accounts"><map><entry key="one" value="9.99"/><entry key="two" value="2.75"/><entry key="six" value="3.99"/></map></property></bean>

Null和Empty字符串值

Null和空字符串是不一樣的,如下:

<bean class="ExampleBean"><property name="email" value=""/> </bean>

上面的例子相當(dāng)于:

exampleBean.setEmail("");

下面是怎么設(shè)置null:

<bean class="ExampleBean"><property name="email"><null/></property> </bean>

上面的例子相當(dāng)于:

exampleBean.setEmail(null);

c-namespace

上面講到了p-namespace專門是設(shè)置bean的屬性用的,同樣的c-namespace是用來設(shè)置構(gòu)造函數(shù)參數(shù)的,如下所示:

<bean id="exampleBeanA" class="com.flydean.beans.ExampleBean"><constructor-arg type="int" value="7500000"/><constructor-arg type="java.lang.String" value="42"/></bean><bean id="exampleBeanB" class="com.flydean.beans.ExampleBean"c:years ="10" c:ultimateAnswer="answer"/>

depends-on

通常一個(gè)bean依賴另一個(gè)bean,我們會(huì)在XML中使用< ref/>來引用,但是這種依賴關(guān)系并不直接。我們可以使用depends-on屬性來顯式強(qiáng)制一個(gè)或多個(gè)bean在使用此元素的bean初始化之前進(jìn)行初始化,如下所示:

<bean id="beanA" class="com.flydean.beans.SomeClass" depends-on="beanB"></bean><bean id="beanB" class="com.flydean.beans.MovieFinder"></bean>

lazy-init

正常來說ApplicationContext中配置成單例模式的bean都會(huì)隨Spring啟動(dòng)而初始化,如果有特殊的需要,想延長(zhǎng)初始化該bean,則可以使用 lazy-init 。一個(gè)lazy-initialized bean告訴IOC容器在第一次請(qǐng)求bean實(shí)例時(shí)創(chuàng)建它,而不是在啟動(dòng)時(shí)。

<bean id="beanD" class="com.flydean.beans.MovieFinder" lazy-init="true"></bean>

但是,當(dāng)一個(gè)惰性初始化bean是一個(gè)非惰性初始化的singleton bean的依賴項(xiàng)時(shí),ApplicationContext會(huì)在啟動(dòng)時(shí)創(chuàng)建惰性初始化bean,因?yàn)樗仨殱M足singleton的依賴項(xiàng)。

您還可以通過在< beans/>元素上使用默認(rèn)的lazy init屬性在容器級(jí)別控制lazy初始化,下面的示例顯示:

<beans default-lazy-init="true"><!-- no beans will be pre-instantiated... --> </beans>

自動(dòng)裝載

如果你想讓Spring自動(dòng)幫你注入bean的依賴bean時(shí)候,可以使用Spring的autowiring功能。autowiring 有4種模式:

模式說明
no(默認(rèn))無自動(dòng)裝載。bean必須引用由ref定義的元素。對(duì)于較大的部署,不建議更改默認(rèn)設(shè)置,因?yàn)轱@式指定合作者可以提供更大的控制度和清晰性。在某種程度上,它記錄了系統(tǒng)的結(jié)構(gòu)。
byName按屬性名稱自動(dòng)裝載。Spring尋找與需要自動(dòng)裝載的屬性同名的bean。例如,如果bean定義被設(shè)置為按名稱自動(dòng)裝載,并且它包含一個(gè)master屬性(即,它有一個(gè)setMaster(…)方法),那么spring將查找名為master的bean定義并使用它來設(shè)置該屬性。
byType如果容器中只有一個(gè)屬性類型的bean,則允許自動(dòng)裝載屬性。如果存在多個(gè),則會(huì)引發(fā)一個(gè)致命的異常,這表示您不能為該bean使用byType自動(dòng)裝載。如果沒有匹配的bean,則不會(huì)發(fā)生任何事情(未設(shè)置屬性)。
constructor類似于byType,但適用于構(gòu)造函數(shù)參數(shù)。如果容器中不只有一個(gè)構(gòu)造函數(shù)參數(shù)類型的bean,則會(huì)引發(fā)致命錯(cuò)誤。

自動(dòng)注入的限制和缺陷

雖然自動(dòng)注入用起來很爽,但是它也有如下的缺陷:

  • property和constructor-arg的顯示設(shè)置會(huì)覆蓋自動(dòng)注入,并且自動(dòng)注入不能注入簡(jiǎn)單類型。

  • 自動(dòng)注入不如顯示配置精確。

  • 自動(dòng)注入可能和容器中的很多bean相匹配。可能會(huì)出現(xiàn)問題。

從自動(dòng)裝載中排除Bean

使用autowire-candidate屬性設(shè)置為false,可以防止bean被自動(dòng)注入。該屬性只會(huì)影響按類型注入的方式。如果按name注入,則不受影響。

下面是自動(dòng)注入的例子:

<bean id="simpleMovieLister" class="com.flydean.beans.SimpleMovieLister" autowire="byType"></bean><!--Setter DI --><bean id="movieFinder" class="com.flydean.beans.MovieFinder"><property name="name" value="movie"/><property name="number" value="123456"/></bean>

SimpleMovieLister如下:

package com.flydean.beans;import lombok.Data;@Data public class SimpleMovieLister {// the SimpleMovieLister has a dependency on the MovieFinderprivate MovieFinder movieFinder;// a setter method so that the Spring container can inject a MovieFinderpublic void setMovieFinder(MovieFinder movieFinder) {this.movieFinder = movieFinder;}// business logic that actually uses the injected MovieFinder is omitted... }

在上面的例子中,movieFinder屬性將會(huì)被自動(dòng)注入。

方法注入

在bean的生命周期不同的時(shí)候,如果一個(gè)bean要依賴于另外一個(gè)bean則可能出現(xiàn)問題。 比如一個(gè)單例模式的beanA 依賴于多例模式的beanB。 因?yàn)閎eanA是單例模式的,所以在創(chuàng)建beanA的時(shí)候就已經(jīng)將其依賴的beanB創(chuàng)建了,不可能在每次beanA需要beanB的時(shí)候都創(chuàng)建一個(gè)新的beanB的實(shí)例。

解決方法有很多種,我們一一進(jìn)行講解。

方法1:實(shí)現(xiàn)ApplicationContextAware

如果實(shí)現(xiàn)了ApplicationContextAware,則可以通過getBean方法在每次需要beanB的時(shí)候,請(qǐng)求他的新的實(shí)例,如下:

public class CommandManager implements ApplicationContextAware {private ApplicationContext applicationContext;public Object process(Map commandState) {// grab a new instance of the appropriate CommandCommand command = createCommand();// set the state on the (hopefully brand new) Command instancecommand.setState(commandState);return command.execute();}protected Command createCommand() {// notice the Spring API dependency!return this.applicationContext.getBean("command", Command.class);}public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;} }

這種方法并不可取的,因?yàn)闃I(yè)務(wù)代碼和Spring框架產(chǎn)生了耦合。方法注入是Spring IoC 容器的一個(gè)高級(jí)特性,它可以很好的處理這種情況。

查找方法注入

查找方法注入是指容器重寫container-managed bean上的方法,并返回容器中另一個(gè)命名bean。查找通常涉及一個(gè)原型bean,如前一節(jié)中描述的場(chǎng)景中所示。Spring框架通過使用cglib庫中的字節(jié)碼動(dòng)態(tài)生成覆蓋該方法的子類來實(shí)現(xiàn)該方法注入。

因?yàn)槭褂昧薱glib,所以bean不能是final類,方法也不能是final類型。

查找方法不適用于工廠方法,尤其不適用于配置類中的@Bean方法,因?yàn)樵谶@種情況下,容器不負(fù)責(zé)創(chuàng)建實(shí)例,因此無法動(dòng)態(tài)創(chuàng)建運(yùn)行時(shí)生成的子類。

下面是一個(gè)查找方法的例子:

public abstract class CommandManagerB {public Object process(Map commandState) {// grab a new instance of the appropriate Command interfaceAsyncCommand command = createCommand();return null;}// okay... but where is the implementation of this method?public abstract AsyncCommand createCommand(); }

這里我們定義了一個(gè)抽象類,要查找的方法就是createCommand。返回的對(duì)象類,如下:

public class AsyncCommand { }

下面是XML配置文件:

<!-- a stateful bean deployed as a prototype (non-singleton) --><bean id="myCommand" class="com.flydean.beans.AsyncCommand" scope="prototype"><!-- inject dependencies here as required --></bean><!-- commandProcessor uses statefulCommandHelper --><bean id="commandManager" class="com.flydean.beans.CommandManagerB"><lookup-method name="createCommand" bean="myCommand"/></bean>

CommandMangerB每次調(diào)用createCommand,都會(huì)返回一個(gè)新的AsyncCommand實(shí)例。

在基于注解的情況下,也可以這樣使用:

public abstract class CommandManagerC {public Object process(Object commandState) {Command command = createCommand();return command.execute();}@Lookup("myCommand")protected abstract Command createCommand(); }

其中@Lookup(“myCommand”) 中的名字也可以省略,則按照默認(rèn)的類型來解析。

任意方法替換

我們甚至可以使用replaced-method替換bean的方法實(shí)現(xiàn)。我們有個(gè)MyValueCalculator類,有一個(gè)我們想重寫的方法computeValue。

public class MyValueCalculator {public String computeValue(String input) {// some real code...return "abc";}// some other methods... }

一個(gè)實(shí)現(xiàn)了org.springframework.beans.factory.support.MethodReplacer接口的類提供了新的方法,如下所示:

public class ReplacementComputeValue implements MethodReplacer {public Object reimplement(Object o, Method m, Object[] args) throws Throwable {// get the input value, work with it, and return a computed resultString input = (String) args[0];return "def";} }

bean的定義如下:

<bean id="myValueCalculator" class="com.flydean.beans.MyValueCalculator"><!-- arbitrary method replacement --><replaced-method name="computeValue" replacer="replacementComputeValue"><arg-type>String</arg-type></replaced-method></bean><bean id="replacementComputeValue" class="com.flydean.beans.ReplacementComputeValue"/>

本章的例子可以參考bean-di中的bean-di部分。

更多精彩內(nèi)容且看:

  • 區(qū)塊鏈從入門到放棄系列教程-涵蓋密碼學(xué),超級(jí)賬本,以太坊,Libra,比特幣等持續(xù)更新
  • Spring Boot 2.X系列教程:七天從無到有掌握Spring Boot-持續(xù)更新
  • Spring 5.X系列教程:滿足你對(duì)Spring5的一切想象-持續(xù)更新
  • java程序員從小工到專家成神之路(2020版)-持續(xù)更新中,附詳細(xì)文章教程

更多教程可以參考flydean的博客

總結(jié)

以上是生活随笔為你收集整理的Spring5参考指南:依赖注入的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。