@Scope注解的作用詳解


TOC

@Scope注解的作用詳解

在看公司hbase項目config的配置的時候發現有這個注解,順手百度了一下....然后發現我基礎好差(一般來說,數據庫連接還是使用連接池的,這種多例連接數據庫太耗資源了)


參考:

定義:

@Scope注解是springIoc容器中的一個作用域,在 Spring IoC 容器中具有以下幾種作用域:基本作用域singleton(單例)prototype(多例),Web 作用域(reqeust、session、globalsession),自定義作用域

  • singleton單例模式(默認):全局有且僅有一個實例
  • prototype原型模式:每次獲取Bean的時候會有一個新的實例
  • request: request表示該針對每一次HTTP請求都會產生一個新的bean,同時該bean僅在當前HTTP request內有效
  • session :session作用域表示該針對每一次HTTP請求都會產生一個新的bean,同時該bean僅在當前HTTP session內有效
  • global session : global session作用域類似於標准的HTTP Session作用域,不過它僅僅在基於portlet的web應用中才有意義

直接使用字符串容易出問題,spring有默認的參數:

  • ConfigurableBeanFactory.SCOPE_PROTOTYPE,即“prototype”
  • ConfigurableBeanFactory.SCOPE_SINGLETON,即“singleton”
  • WebApplicationContext.SCOPE_REQUEST,即“request”
  • WebApplicationContext.SCOPE_SESSION,即“session”

使用

直接在bean對象方法上增加@Scope注解就可以

/**
* 定義一個bean對象
* @return
*/
@Scope    //@Scope(value = "prototype")
@Bean(value = "user0", name = "user0", initMethod = "initUser", destroyMethod = "destroyUser")
public User getUser() {
    System.out.println("創建user實例");
    return new User("張三", 26);
}

@Scope注解默認的singleton實例,singleton實例的意思不管你使用多少次在springIOC容器中只會存在一個實例,演示如下只打印了一次創建實例:

AnnotationConfigApplicationContext applicationContext2 = new AnnotationConfigApplicationContext(MainConfig.class);
User bean2 = applicationContext2.getBean(User.class);
System.out.println("實例1 === "+bean2);
User bean3 = applicationContext2.getBean(User.class);
System.out.println("實例2 === "+bean3);
//運行結果
創建user實例
實例1 === User [userName=張三, age=26]
實例2 === User [userName=張三, age=26]

若是改為@Scope(value="prototype")

//運行結果
創建user實例
實例1 === User [userName=張三, age=26]
創建user實例
實例2 === User [userName=張三, age=26]

使用場景

幾乎90%以上的業務使用singleton單實例就可以,所以spring默認的類型也是singleton,singleton雖然保證了全局是一個實例,對性能有所提高,但是如果實例中有非靜態變量時,會導致線程安全問題,共享資源的競爭。

當設置為prototype時:每次連接請求,都會生成一個bean實例,也會導致一個問題,當請求數越多,性能會降低,因為創建的實例,導致GC頻繁,gc時長增加

多例

直接在controller層設置多例

在controller類上設置多例,正常

單例調用多例

在controller是默認的單例,service層是多例的時候,多例失效

雖然Service是多例的,但是Controller是單例的。如果給一個組件加上@Scope("prototype")注解,每次請求它的實例,spring的確會給返回一個新的。問題是這個多例對象Service是被單例對象Controller依賴的。而單例服務Controller初始化的時候,多例對象Service就已經注入了;當你去使用Controller的時候,Service也不會被再次創建了(注入時創建,而注入只有一次)。

  • 方法1: 不使用@Autowired ,每次調用多例的時候,直接調用bean
  • 方法2:spring的解決方法:設置proxyMode,每次請求的時候實例化

    @Scope注解添加了一個proxyMode的屬性,有兩個值ScopedProxyMode.INTERFACESScopedProxyMode.TARGET_CLASS,前一個表示表示Service是一個接口,后一個表示Service是一個類。

@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE, proxyMode = ScopedProxyMode.TARGET_CLASS)
案例
  • 創建bean
    @Bean
    //@Scope標明模式,默認單例模式.  prototype多例模式
    @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public User hbaseConnection() {
        User user = new User((int) (Math.random() * 100));
        System.out.println("調用了hbaseConnection,User:id:" + user.getId());
        return user;
    }
  • controller引入並調用
@RestController
@RequestMapping("/demo1")
public class DemoController {
    @Autowired
    private User hbaseConnection;
    @RequestMapping("/test")
    public void test(){
        System.out.println("test:user:id:"+hbaseConnection.getId());
        System.out.println("test:user:id2:"+hbaseConnection.getId());
    }
}

調用接口,結果為

調用了hbaseConnection,User:id:7
test:user:id:7
調用了hbaseConnection,User:id:2
test:user:id2:2

每調用一次注入的對象,就會重新創建一個






免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM