成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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

開發 前端
對于有些場景,我們可能需要對應的 Bean? 是原型的,所謂原型就是希望每次在使用的時候獲取到的是一個新的對象實例,而不是單例的,這種情況下很多小伙伴肯定會說,那還不簡單,只要在對應的類上面加上 @scope? 注解,將 value? 設置成 Prototype 不就行了。

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

測試原型

對于有些場景,我們可能需要對應的 Bean? 是原型的,所謂原型就是希望每次在使用的時候獲取到的是一個新的對象實例,而不是單例的,這種情況下很多小伙伴肯定會說,那還不簡單,只要在對應的類上面加上 @scope? 注解,將 value? 設置成 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>無<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>無<br>
*/
@RestController
public class HelloController {

@Autowired
private HelloService service;

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

簡單描述一下上面的代碼,其中 HelloService? 類我們使用了注解 Scope?,并將值設置為 SCOPE_PROTOTYPE?,表示是原型類,在 HelloController? 類中我們調用 HelloService? 的 sayHello? 方式,其中返回了當前實例的 hashcode。

我們通過訪問 http://127.0.0.1:8080/hello 來獲取返回值,如果說每次獲取到的值都不一樣,那就說明我們上面的代碼是沒有問題的,每次在獲取的時候都會使用一個新的 HelloService 實例。

圖片

然而在阿粉的電腦上,無論刷新瀏覽器多少次,最后的結果卻沒有發生任何變化,換句話說這里引用到的 HelloService 始終就是一個,并沒有原型的效果。

那么問題來了,我們明明給 HelloService 類增加了原型注解,為什么這里沒有效果呢?

原因分析

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

那自然是 Spring? 在 HelloController? 初始化的時候,通過依賴注入幫我們賦值的。Spring? 注入依賴的賦值邏輯簡單來說就是創建 Bean? 的時候如果發現有依賴注入,則會在容器中獲取或者創建一個依賴 Bean?,此時對應屬性的 Bean? 是單例的,則容器中只會創建一個,如果對應的 Bean? 是原型,那么每次都會創建一個新的 Bean?,然后將創建的 Bean 賦值給對應的屬性。

在我們這里 HelloService? 類是原型的,所以在創建 HelloController Bean? 的時候,會創建一個 HelloService? 的 Bean? 賦值到 service? 屬性上;到這里都沒有問題,但是因為我們 HelloController Bean? 是單例的,初始化的動作在整個生命周期中只會發生一次,所以即使 HelloService 類是原因的,也只會被依賴注入一次,因此我們上面的這種寫入是達不到我們需要的效果的。

解法

解法一

寫到這里有的小伙伴就會想到,那如果我把 HelloController? 類也設置成原型呢?這樣不就可以了么。給 HelloController? 增加上注解 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)? 重啟過后我們重新訪問 http://127.0.0.1:8080/hello ,發現確實是可以的。也很好理解,因為此時 HelloController? 是原型的,所以每次訪問都會創建一個新的實例,初始化的過程中會被依賴注入新的 HelloService 實例。

但是不得不說,這種解法很不優雅,把 Controller 類設置成原型,并不友好,所以這里我們不推薦這種解法。

解法二

除了將 HelloController? 設置成原型,我們還有其他的解法,上面我們提到 HelloController? 在初始化的時候會依賴注入 HelloService?,那我們是不是可以換一個方式,讓 HelloController? 創建的時候不依賴注入 HelloService,而是在真正需要的時候再從容器中獲取。如下所示:

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>無<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);
}
}

通過測試這種方式也是可以的,每次從容器中重新獲取的時候都是重新創建一個新的實例。

解法三

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

圖片

簡單來說就是通過使用 Lookup? 注解的方法,可以被容器覆蓋,然后通過  BeanFactory 返回指定類型的一個類實例,可以在單例類中使用獲取到一個原型類,示例如下:

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>無<br>
*/
@RestController
public class HelloController {

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

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

寫法跟我們解法二比較相似,只不過不是我們顯示的通過容器中獲取一個原型 Bean? 實例,而是通過 Lookup? 的注解,讓容器來幫我們覆蓋對應的方法,返回一個原型實例對象。這里我們的 getService? 方法里面可以直接返回一個 null,因為這里面的代碼是不會被執行到的。

我們打個斷點調試,會發現通過 Lookup? 注解的方法最終后走到org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy.LookupOverrideMethodInterceptor#intercept 這里。

圖片

圖片

這里我們可以看到,動態從容器中獲取實例。不過需要注意一點,那就是我們通過 Lookup? 注解的方法是有要求的,因為是需要被重寫,所以針對這個方法我們只能使用下面的這種定時定義,必須是 public? 或者 protected,可以是抽象方法,而且方法不能有參數。

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

總結

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

責任編輯:武曉燕 來源: Java極客技術
相關推薦

2025-06-12 03:25:00

2020-10-29 09:19:11

索引查詢存儲

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 學院

2023-10-08 10:14:12

2024-01-05 08:38:20

SpringBeanScope

2021-05-08 08:55:54

CPUIBMIntel

2021-04-29 07:18:21

Spring IOC容器單例

2022-05-26 09:24:09

volatile懶漢模式

2011-03-18 09:27:00

Spring

2021-07-05 08:43:46

Spring Beanscope作用域

2021-03-08 08:40:25

Spring Bean 創建單例對象

2021-09-13 10:03:54

藍牙連接藍牙藍牙設備

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對象作用域
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 女同久久另类99精品国产 | 欧美日韩成人影院 | 亚洲一区视频在线 | 国产网站在线播放 | 一区二区免费高清视频 | 青娱乐av| 精品国产久 | 自拍偷拍中文字幕 | 黄色免费网站在线看 | 国产一极毛片 | 久久久成 | 中国美女av | 成人免费视频网站在线观看 | 全部免费毛片在线播放网站 | 欧美黑人激情 | 欧美日韩中文字幕 | 91精品久久久久久久久 | 国产一区二区不卡 | 免费一级片 | 国产美女福利在线观看 | 久久综合一区二区 | www.激情.com | 欧美亚洲视频在线观看 | 亚洲欧洲视频 | 久久久久国产一区二区三区不卡 | 欧美激情精品久久久久久变态 | 亚洲色图第一页 | 狠狠色综合久久丁香婷婷 | 欧美一区视频 | 中文字幕日韩一区 | 精品一区二区免费视频 | 欧美精品v| 中文一区| av免费成人 | 日本三级全黄三级三级三级口周 | 成人免费大片黄在线播放 | 久久精品色视频 | 成人国产在线视频 | 亚洲精品一区二区三区 | 国产日韩一区二区三区 | 性色在线|