AVt天堂网 手机版,亚洲va久久久噜噜噜久久4399,天天综合亚洲色在线精品,亚洲一级Av无码毛片久久精品

當(dāng)前位置:首頁 > 科技  > 軟件

玩轉(zhuǎn)Spring各種作用域Bean Scope及源碼分析

來源: 責(zé)編: 時(shí)間:2024-01-08 09:17:41 228觀看
導(dǎo)讀環(huán)境:Spring5.3.23一. 簡介Spring Scope Bean是Spring用于管理Bean的作用域的一種機(jī)制。它定義了容器中Bean的生命周期和實(shí)例化策略,即如何創(chuàng)建Bean實(shí)例。在Spring中,Bean的作用域包括單例(singleton)、原型(prototype)、請(qǐng)

環(huán)境:Spring5.3.23cKx28資訊網(wǎng)——每日最新資訊28at.com

一. 簡介

Spring Scope Bean是Spring用于管理Bean的作用域的一種機(jī)制。它定義了容器中Bean的生命周期和實(shí)例化策略,即如何創(chuàng)建Bean實(shí)例。cKx28資訊網(wǎng)——每日最新資訊28at.com

在Spring中,Bean的作用域包括單例(singleton)、原型(prototype)、請(qǐng)求(request)、會(huì)話(session)等。每個(gè)作用域都有其特定的使用場景和行為:cKx28資訊網(wǎng)——每日最新資訊28at.com

  1. 單例(singleton):這是Spring默認(rèn)的作用域,表示在整個(gè)Spring容器中,只有一個(gè)Bean實(shí)例存在。無論你從哪個(gè)地方獲取這個(gè)Bean,都將返回同一個(gè)實(shí)例。
  2. 原型(prototype):每次從容器中請(qǐng)求Bean時(shí),都會(huì)創(chuàng)建一個(gè)新的Bean實(shí)例。
  3. 請(qǐng)求(request):在一個(gè)HTTP請(qǐng)求的范圍內(nèi),Bean是單例的。這種作用域適用于與單個(gè)請(qǐng)求關(guān)聯(lián)的Bean。
  4. 會(huì)話(session):在一個(gè)HTTP會(huì)話的范圍內(nèi),Bean是單例的。這種作用域適用于與單個(gè)用戶會(huì)話關(guān)聯(lián)的Bean。

此外,Spring還提供了其他一些作用域應(yīng)用(Application)、WebSocket,以滿足不同場景的需求。cKx28資訊網(wǎng)——每日最新資訊28at.com

通過合理地選擇Bean的作用域,可以優(yōu)化應(yīng)用的性能和資源利用率。例如,對(duì)于需要頻繁創(chuàng)建和銷毀實(shí)例的Bean,使用原型作用域會(huì)更高效;而對(duì)于需要在多個(gè)請(qǐng)求或會(huì)話之間共享狀態(tài)的Bean,則可以選擇單例或會(huì)話作用域。附官方圖:cKx28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片cKx28資訊網(wǎng)——每日最新資訊28at.com

接下來將分別介紹每一種作用域bean。cKx28資訊網(wǎng)——每日最新資訊28at.com

二. 作用域應(yīng)用

基礎(chǔ)類

static class Person {  @Override  public String toString() {    return super.toString() + " - " + this.hashCode() + "" ;  }}

2.1 單例(singleton)

默認(rèn)使用@Bean,@Service,@Controller注解標(biāo)注的注解都是單例的。也可以同@Scope注解指定作用域?yàn)閱卫?/span>cKx28資訊網(wǎng)——每日最新資訊28at.com

@Bean// 不指定@Scope默認(rèn)就是單例@Scope(value = "singleton")public Person person() {  return new Person() ;}

測試cKx28資訊網(wǎng)——每日最新資訊28at.com

try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {  context.registerBean(Config.class) ;  context.refresh() ;    System.out.println(context.getBean(Person.class)) ;  System.out.println(context.getBean(Person.class)) ;}

控制臺(tái)輸出cKx28資訊網(wǎng)——每日最新資訊28at.com

com.pack.main.scope.ScopeMain5$Person@5e0e82ae - 1578009262com.pack.main.scope.ScopeMain5$Person@5e0e82ae - 1578009262

每次獲取的都是同一個(gè)實(shí)例。cKx28資訊網(wǎng)——每日最新資訊28at.com

原理cKx28資訊網(wǎng)——每日最新資訊28at.com

public abstract class AbstractBeanFactory {  protected <T> T doGetBean(...) {    // ...    // 判斷是否是單例    if (mbd.isSingleton()) {      // 先從單例池中查找是否已經(jīng)存在,不存在則調(diào)用createBean創(chuàng)建,      // 然后存入單例池中      sharedInstance = getSingleton(beanName, () -> {        try {          return createBean(beanName, mbd, args);        }      });    }    // ...  }}

2.2 原型(prototype)

每次從容器中請(qǐng)求Bean時(shí),都會(huì)創(chuàng)建一個(gè)新的Bean實(shí)例。cKx28資訊網(wǎng)——每日最新資訊28at.com

@Bean@Scope(value = "prototype")public Person person() {  return new Person() ;}

控制臺(tái)輸出cKx28資訊網(wǎng)——每日最新資訊28at.com

com.pack.main.scope.ScopeMain5$Person@fa4c865 - 262457445com.pack.main.scope.ScopeMain5$Person@3bd82cf5 - 1004023029

每次獲取都是不同的對(duì)象。cKx28資訊網(wǎng)——每日最新資訊28at.com

原理cKx28資訊網(wǎng)——每日最新資訊28at.com

public abstract class AbstractBeanFactory {  protected <T> T doGetBean(...) {    // ...    // 判斷是否是單例    if (mbd.isSingleton()) {      // ...    }    // 判斷是否是原型    else if (mbd.isPrototype()) {      Object prototypeInstance = null;      try {        // 不存在什么緩存池,直接創(chuàng)建bean實(shí)例返回        prototypeInstance = createBean(beanName, mbd, args);      }    }    // ...  }}

這里考慮一個(gè)問題,如何在單例bean中正確的注入原型bean?cKx28資訊網(wǎng)——每日最新資訊28at.com

2.3 請(qǐng)求(request)

接下來都是與web環(huán)境相關(guān)了,所以這里演示的示例會(huì)以SpringBoot3.0.5環(huán)境演示。cKx28資訊網(wǎng)——每日最新資訊28at.com

基礎(chǔ)類cKx28資訊網(wǎng)——每日最新資訊28at.com

@Component@Scope(value = "request")public class Person {}

測試類cKx28資訊網(wǎng)——每日最新資訊28at.com

@RestController@RequestMapping("/scopes")public class ScopeController {  @Resource  private Person person ;  @Resource  private PersonService ps ;  @GetMapping("/request")  public Person request() {    System.out.println("ScopeController: " + person) ;    ps.query() ;    return person ;  }}

ServicecKx28資訊網(wǎng)——每日最新資訊28at.com

@Servicepublic class PersonService {  @Resource  private Person person ;  public void query() {    System.out.println("PersonService: " + person) ;  }}

如果上面這樣配置,啟動(dòng)服務(wù)將會(huì)報(bào)錯(cuò):cKx28資訊網(wǎng)——每日最新資訊28at.com

Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.  at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131) ~[spring-web-6.0.7.jar:6.0.7]

該錯(cuò)誤的原因就是你在一個(gè)單例bean中注入一個(gè)request作用域的bean,而request作用域bean的生命周期是在一個(gè)web請(qǐng)求開始創(chuàng)建的,所以這里你當(dāng)然是沒法注入的。cKx28資訊網(wǎng)——每日最新資訊28at.com

解決辦法:cKx28資訊網(wǎng)——每日最新資訊28at.com

  • @Scope設(shè)置代理模式
@Component@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)public class Person {}

測試結(jié)果cKx28資訊網(wǎng)——每日最新資訊28at.com

ScopeController: com.pack.scopes.Person@106a9684 - 275420804PersonService: com.pack.scopes.Person@106a9684 - 275420804ScopeController: com.pack.scopes.Person@64396678 - 1681483384PersonService: com.pack.scopes.Person@64396678 - 1681483384

每次請(qǐng)求接口都獲取的不是同一個(gè)實(shí)例。并且在一個(gè)完整的請(qǐng)求中獲取的Person都是同一個(gè)。cKx28資訊網(wǎng)——每日最新資訊28at.com

  • 使用@RequestScope

該注解原理與上面其實(shí)一致的cKx28資訊網(wǎng)——每日最新資訊28at.com

@Scope(WebApplicationContext.SCOPE_REQUEST)public @interface RequestScope {  @AliasFor(annotation = Scope.class)  // 設(shè)置好了使用代理  ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;}

2.4 會(huì)話(session)

@Component@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)// 與request一樣,必須設(shè)置代理模式或者使用下面這個(gè)注解// @SessionScopepublic class Person {}

測試cKx28資訊網(wǎng)——每日最新資訊28at.com

ScopeController: com.pack.scopes.Person@2b56038d - 727057293PersonService: com.pack.scopes.Person@2b56038d - 727057293ScopeController: com.pack.scopes.Person@2b56038d - 727057293PersonService: com.pack.scopes.Person@2b56038d - 727057293

多次訪問都是同一個(gè)session;你再換個(gè)瀏覽器訪問cKx28資訊網(wǎng)——每日最新資訊28at.com

ScopeController: com.pack.scopes.Person@1aa201fd - 446824957PersonService: com.pack.scopes.Person@1aa201fd - 446824957ScopeController: com.pack.scopes.Person@1aa201fd - 446824957PersonService: com.pack.scopes.Person@1aa201fd - 446824957

此時(shí)對(duì)象就是一個(gè)新的了,不同的瀏覽器訪問當(dāng)然不是同一個(gè)session了。cKx28資訊網(wǎng)——每日最新資訊28at.com

2.5 應(yīng)用(application)

@Scope(value = "application", proxyMode = ScopedProxyMode.TARGET_CLASS)// @ApplicationScope// 都是web環(huán)境,所以情況都一樣public class Person {}

測試cKx28資訊網(wǎng)——每日最新資訊28at.com

360瀏覽器cKx28資訊網(wǎng)——每日最新資訊28at.com

ScopeController: com.pack.scopes.Person@6371b4b6 - 1668396214PersonService: com.pack.scopes.Person@6371b4b6 - 1668396214

Chrome瀏覽器cKx28資訊網(wǎng)——每日最新資訊28at.com

ScopeController: com.pack.scopes.Person@6371b4b6 - 1668396214PersonService: com.pack.scopes.Person@6371b4b6 - 1668396214

他們是同一個(gè)對(duì)象,application作用域生命周期與整個(gè)應(yīng)用一樣,只有你關(guān)閉了服務(wù)器,在啟動(dòng)后才會(huì)是再重新創(chuàng)建的bean對(duì)象。cKx28資訊網(wǎng)——每日最新資訊28at.com

3. web作用域原理

3.1 注冊(cè)作用域

public abstract class AbstractApplicationContext {  public void refresh() {    postProcessBeanFactory(beanFactory);  }}public class AnnotationConfigServletWebServerApplicationContext {  protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {    super.postProcessBeanFactory(beanFactory);  }}public class ServletWebServerApplicationContext {  protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {    // ...    registerWebApplicationScopes();  }  private void registerWebApplicationScopes() {    WebApplicationContextUtils.registerWebApplicationScopes(getBeanFactory());  }}public abstract class WebApplicationContextUtils {  public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory) {    registerWebApplicationScopes(beanFactory, null);  }  public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory,      @Nullable ServletContext sc) {    // 注冊(cè)作用域    beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());    beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope());    if (sc != null) {      ServletContextScope appScope = new ServletContextScope(sc);      beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope);    }  }}

這里每一種web作用域都有一個(gè)對(duì)應(yīng)的Scope實(shí)現(xiàn)RequestScope,SessionScope,ServletContextScope。cKx28資訊網(wǎng)——每日最新資訊28at.com

3.2 查找web作用域beancKx28資訊網(wǎng)——每日最新資訊28at.com

public abstract class AbstractBeanFactory {  protected <T> T doGetBean(...) {    // ...    // 判斷是否是單例    if (mbd.isSingleton()) {      // ...    }    // 判斷是否是原型    else if (mbd.isPrototype()) {      Object prototypeInstance = null;      try {        // 不存在什么緩存池,直接創(chuàng)建bean實(shí)例返回        prototypeInstance = createBean(beanName, mbd, args);      }    }    // 其它作用域bean,如上面的web作用域    else {      String scopeName = mbd.getScope();      Scope scope = this.scopes.get(scopeName);      if (scope == null) {        throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");      }      try {          // 通過具體Scope的實(shí)現(xiàn)類獲取bean對(duì)象        Object scopedInstance = scope.get(beanName, () -> {          beforePrototypeCreation(beanName);          try {            // 首次都還是會(huì)創(chuàng)建            return createBean(beanName, mbd, args);            }          });        }      }    }    // ...  }}

總結(jié):Spring Scope Bean是Spring框架中用于管理Bean的作用域的機(jī)制,它定義了Bean的生命周期和實(shí)例化策略。通過合理地選擇Bean的作用域,可以優(yōu)化應(yīng)用的性能和資源利用率。cKx28資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://www.tebozhan.com/showinfo-26-57916-0.html玩轉(zhuǎn)Spring各種作用域Bean Scope及源碼分析

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: MongoDB 大量數(shù)據(jù)插入時(shí)的性能影響及解決方法

下一篇: 2023年最火的前端項(xiàng)目出爐,竟然是它?

標(biāo)簽:
  • 熱門焦點(diǎn)
Top