偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Spring 的 Bean 明明設(shè)置了 Scope 為 Prototype,為什么還是只能獲取到單例對(duì)象?

開(kāi)發(fā) 前端
對(duì)于有些場(chǎng)景,我們可能需要對(duì)應(yīng)的 Bean? 是原型的,所謂原型就是希望每次在使用的時(shí)候獲取到的是一個(gè)新的對(duì)象實(shí)例,而不是單例的,這種情況下很多小伙伴肯定會(huì)說(shuō),那還不簡(jiǎn)單,只要在對(duì)應(yīng)的類(lèi)上面加上 @scope? 注解,將 value? 設(shè)置成 Prototype 不就行了。

Spring? 作為當(dāng)下最火熱的Java? 框架,相信很多小伙伴都在使用,對(duì)于 Spring? 中的 Bean? 我們都知道默認(rèn)是單例的,意思是說(shuō)在整個(gè) Spring 容器里面只存在一個(gè)實(shí)例,在需要的地方直接通過(guò)依賴注入或者從容器中直接獲取,就可以直接使用。

測(cè)試原型

對(duì)于有些場(chǎng)景,我們可能需要對(duì)應(yīng)的 Bean? 是原型的,所謂原型就是希望每次在使用的時(shí)候獲取到的是一個(gè)新的對(duì)象實(shí)例,而不是單例的,這種情況下很多小伙伴肯定會(huì)說(shuō),那還不簡(jiǎn)單,只要在對(duì)應(yīng)的類(lèi)上面加上 @scope? 注解,將 value? 設(shè)置成 Prototype 不就行了。如下所示:

HelloService.java

package com.example.demo.service;

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

/**
* <br>
* <b>Function:</b><br>
* <b>Author:</b>@author ziyou<br>
* <b>Date:</b>2022-07-17 21:20<br>
* <b>Desc:</b>無(wú)<br>
*/
@Service
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class HelloService {

public String sayHello() {
return "hello: " + this.hashCode();
}
}

HelloController.java 代碼如下:

package com.example.demo.controller;

import com.example.demo.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Lookup;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* <br>
* <b>Function:</b><br>
* <b>Author:</b>@author ziyou<br>
* <b>Date:</b>2022-07-17 15:43<br>
* <b>Desc:</b>無(wú)<br>
*/
@RestController
public class HelloController {

@Autowired
private HelloService service;

@GetMapping(value = "/hello")
public String hello() {
return service.sayHello();
}
}

簡(jiǎn)單描述一下上面的代碼,其中 HelloService? 類(lèi)我們使用了注解 Scope?,并將值設(shè)置為 SCOPE_PROTOTYPE?,表示是原型類(lèi),在 HelloController? 類(lèi)中我們調(diào)用 HelloService? 的 sayHello? 方式,其中返回了當(dāng)前實(shí)例的 hashcode。

我們通過(guò)訪問(wèn) http://127.0.0.1:8080/hello 來(lái)獲取返回值,如果說(shuō)每次獲取到的值都不一樣,那就說(shuō)明我們上面的代碼是沒(méi)有問(wèn)題的,每次在獲取的時(shí)候都會(huì)使用一個(gè)新的 HelloService 實(shí)例。

圖片

然而在阿粉的電腦上,無(wú)論刷新瀏覽器多少次,最后的結(jié)果卻沒(méi)有發(fā)生任何變化,換句話說(shuō)這里引用到的 HelloService 始終就是一個(gè),并沒(méi)有原型的效果。

那么問(wèn)題來(lái)了,我們明明給 HelloService 類(lèi)增加了原型注解,為什么這里沒(méi)有效果呢?

原因分析

我們這樣思考一下,首先我們通過(guò)瀏覽器訪問(wèn)接口的時(shí)候,訪問(wèn)到的是 HelloController? 類(lèi)中的方法,那么 HelloController? 由于我們沒(méi)有增加 Scope? 的原型注解,所以肯定是單例的,那么單例的 HelloController? 中的 HelloService 屬性是什么怎么賦值的呢?

那自然是 Spring? 在 HelloController? 初始化的時(shí)候,通過(guò)依賴注入幫我們賦值的。Spring? 注入依賴的賦值邏輯簡(jiǎn)單來(lái)說(shuō)就是創(chuàng)建 Bean? 的時(shí)候如果發(fā)現(xiàn)有依賴注入,則會(huì)在容器中獲取或者創(chuàng)建一個(gè)依賴 Bean?,此時(shí)對(duì)應(yīng)屬性的 Bean? 是單例的,則容器中只會(huì)創(chuàng)建一個(gè),如果對(duì)應(yīng)的 Bean? 是原型,那么每次都會(huì)創(chuàng)建一個(gè)新的 Bean?,然后將創(chuàng)建的 Bean 賦值給對(duì)應(yīng)的屬性。

在我們這里 HelloService? 類(lèi)是原型的,所以在創(chuàng)建 HelloController Bean? 的時(shí)候,會(huì)創(chuàng)建一個(gè) HelloService? 的 Bean? 賦值到 service? 屬性上;到這里都沒(méi)有問(wèn)題,但是因?yàn)槲覀?nbsp;HelloController Bean? 是單例的,初始化的動(dòng)作在整個(gè)生命周期中只會(huì)發(fā)生一次,所以即使 HelloService 類(lèi)是原因的,也只會(huì)被依賴注入一次,因此我們上面的這種寫(xiě)入是達(dá)不到我們需要的效果的。

解法

解法一

寫(xiě)到這里有的小伙伴就會(huì)想到,那如果我把 HelloController? 類(lèi)也設(shè)置成原型呢?這樣不就可以了么。給 HelloController? 增加上注解 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)? 重啟過(guò)后我們重新訪問(wèn) http://127.0.0.1:8080/hello ,發(fā)現(xiàn)確實(shí)是可以的。也很好理解,因?yàn)榇藭r(shí) HelloController? 是原型的,所以每次訪問(wèn)都會(huì)創(chuàng)建一個(gè)新的實(shí)例,初始化的過(guò)程中會(huì)被依賴注入新的 HelloService 實(shí)例。

但是不得不說(shuō),這種解法很不優(yōu)雅,把 Controller 類(lèi)設(shè)置成原型,并不友好,所以這里我們不推薦這種解法。

解法二

除了將 HelloController? 設(shè)置成原型,我們還有其他的解法,上面我們提到 HelloController? 在初始化的時(shí)候會(huì)依賴注入 HelloService?,那我們是不是可以換一個(gè)方式,讓 HelloController? 創(chuàng)建的時(shí)候不依賴注入 HelloService,而是在真正需要的時(shí)候再?gòu)娜萜髦蝎@取。如下所示:

package com.example.demo.controller;

import com.example.demo.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* <br>
* <b>Function:</b><br>
* <b>Author:</b>@author ziyou<br>
* <b>Date:</b>2022-07-17 15:43<br>
* <b>Desc:</b>無(wú)<br>
*/
@RestController
public class HelloController {

@Autowired
private ApplicationContext applicationContext;

@GetMapping(value = "/hello")
public String hello() {
HelloService service = getService();
return service.sayHello();
}

public HelloService getService() {
return applicationContext.getBean(HelloService.class);
}
}

通過(guò)測(cè)試這種方式也是可以的,每次從容器中重新獲取的時(shí)候都是重新創(chuàng)建一個(gè)新的實(shí)例。

解法三

上面解法二還是比較常規(guī)的,除了解法二之外還有一個(gè)解法,那就是使用 Lookup? 注解,根據(jù) Spring 的官方文檔,我們可以看到下面的內(nèi)容。

圖片

簡(jiǎn)單來(lái)說(shuō)就是通過(guò)使用 Lookup? 注解的方法,可以被容器覆蓋,然后通過(guò)  BeanFactory 返回指定類(lèi)型的一個(gè)類(lèi)實(shí)例,可以在單例類(lèi)中使用獲取到一個(gè)原型類(lèi),示例如下:

package com.example.demo.controller;

import com.example.demo.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Lookup;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* <br>
* <b>Function:</b><br>
* <b>Author:</b>@author ziyou<br>
* <b>Date:</b>2022-07-17 15:43<br>
* <b>Desc:</b>無(wú)<br>
*/
@RestController
public class HelloController {

@GetMapping(value = "/hello")
public String hello() {
HelloService service = getService();
return service.sayHello();
}

@Lookup
public HelloService getService() {
return null;
}
}

寫(xiě)法跟我們解法二比較相似,只不過(guò)不是我們顯示的通過(guò)容器中獲取一個(gè)原型 Bean? 實(shí)例,而是通過(guò) Lookup? 的注解,讓容器來(lái)幫我們覆蓋對(duì)應(yīng)的方法,返回一個(gè)原型實(shí)例對(duì)象。這里我們的 getService? 方法里面可以直接返回一個(gè) null,因?yàn)檫@里面的代碼是不會(huì)被執(zhí)行到的。

我們打個(gè)斷點(diǎn)調(diào)試,會(huì)發(fā)現(xiàn)通過(guò) Lookup? 注解的方法最終后走到org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy.LookupOverrideMethodInterceptor#intercept 這里。

圖片

圖片

這里我們可以看到,動(dòng)態(tài)從容器中獲取實(shí)例。不過(guò)需要注意一點(diǎn),那就是我們通過(guò) Lookup? 注解的方法是有要求的,因?yàn)槭切枰恢貙?xiě),所以針對(duì)這個(gè)方法我們只能使用下面的這種定時(shí)定義,必須是 public? 或者 protected,可以是抽象方法,而且方法不能有參數(shù)。

<public|protected> [abstract] <return-type> theMethodName(no-arguments);

總結(jié)

今天阿粉通過(guò)幾個(gè)例子,給大家介紹了一下如何在單例類(lèi)中獲取原型類(lèi)的實(shí)例,提供了三種解法,其中解法一不推薦,解法二和解法三異曲同工,感興趣的小伙伴可以自己嘗試一下。

責(zé)任編輯:武曉燕 來(lái)源: Java極客技術(shù)
相關(guān)推薦

2025-06-12 03:25:00

2020-10-29 09:19:11

索引查詢存儲(chǔ)

2022-05-27 08:25:55

容器Spring

2022-06-23 10:47:57

Spring容器工具

2024-12-31 11:40:05

2022-08-04 08:22:49

MySQL索引

2017-04-17 11:50:13

51CTO 學(xué)院

2023-10-08 10:14:12

2021-05-08 08:55:54

CPUIBMIntel

2024-01-05 08:38:20

SpringBeanScope

2022-05-26 09:24:09

volatile懶漢模式

2021-04-29 07:18:21

Spring IOC容器單例

2011-03-18 09:27:00

Spring

2021-07-05 08:43:46

Spring Beanscope作用域

2021-03-08 08:40:25

Spring Bean 創(chuàng)建單例對(duì)象

2021-09-13 10:03:54

藍(lán)牙連接藍(lán)牙藍(lán)牙設(shè)備

2009-06-17 17:20:14

BeanFactorySpring

2023-01-13 07:41:20

BeanSpring容器

2024-05-28 07:55:31

SpringBean用域

2021-07-01 10:45:18

Bean對(duì)象作用域
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)