spring bean scope簡要說明,有代碼示例

以前一直只知道spring bean有做用域,沒有怎麼關注具體內容,今天特地看了,記錄過程以做備忘。java

做用域(5類)

做用域總計5種:singleton, prototype, request, session, global session
其中singleton, prototype爲常規bean中均可以使用,默認爲singleton;request, session, global session爲web中特有,主要配置在如controller,action中具體配置方式有多種,此例中以springboot爲示例web

單例模式(singleton)

spring 容器中只存在一個具體實例,如
定義UserServiceImplspring

@Service
public class UserServiceImpl implements IUserService {}
@RestController
@RequestMapping("/user")
public class UserController {
    private static final Logger logger = LoggerFactory.getLogger(UserController.class);
    @Autowired
    private IUserService userService;

    @RequestMapping("/{id}")
    @ResponseBody
    public User get(@PathVariable(required = false) Long id) {
        logger.info("userService:{}", userService.toString());
        return userService.get(1l);
    }
}

@RestController
@RequestMapping("/test")
public class TestController {
    private static final Logger logger = LoggerFactory.getLogger(TestController.class);
    @Autowired
    private IUserService userService;

    @GetMapping("/user")
    public User testUser() {
        logger.info("testController:{}", this.toString());
        logger.info("userService:{}", userService.toString());
        return userService.get(1l);
    }
}
結果:在調用兩個地址後,userService.toString()打印出來的結果是一致的

圖片描述

原型模式(prototype)

每次注入時提供一個新的實例

代碼以下:
改變服務提供方 UserServiceImpl安全

@Service
@Scope(value = "prototype")
public class UserServiceImpl implements IUserService {}

再次調用springboot

結果:爲兩個調用者生成不一樣的實例,但同一個調用者只生成一個

clipboard.png

每次調用時生成不一樣的實例

可在scope中加入 proxyMode= ScopedProxyMode.TARGET_CLASS網絡

改變服務提供方 UserServiceImplsession

@Service
@Scope(value = "prototype",proxyMode= ScopedProxyMode.TARGET_CLASS)
public class UserServiceImpl implements IUserService {}

再次調用app

結果:每一次請求(調用),生成了不一樣的實例

clipboard.png

2018-3-26更新開始

若是調用者爲原型模式,即ide

@Scope(value = "prototype")
public class UserController {...}

UserServiceImpl 設置爲@Scope(value = "prototype")便可,無需配置proxyMode= ScopedProxyMode.TARGET_CLASSui


2018-3-26更新結束

request

request, session, global session爲web中特有,做用域大體對應HTTP中的Request, Session和Application,本例只以request爲例

保持上面代碼修改UserController,代碼以下:

@RestController
@RequestMapping("/user")
@Scope(value = "request")
public class UserController {
...
}

再次調用

結果:每次調用會生成新的UserController 實例

clipboard.png

@Scope(value = "request") 只能用於 controller/restcontroller 相似web組件中,如用於service中會出現以下異常:
Error creating bean with name 'userServiceImpl': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is 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/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.

另singleton的bean引用一個prototype的bean的說明

網絡中有說singleton的bean不能引用prototype的bean,經實驗,是能夠引用,但能力有限,未能明確引用是否會有線程安全或其餘問題
此處僅作引用示例,代碼以下

修改UserController,代碼以下:

@RestController
@RequestMapping("/user")
public class UserController {
...
}

修改

@Service
@Scope(value = "prototype",proxyMode= ScopedProxyMode.TARGET_CLASS)
public class UserServiceImpl implements IUserService {}

再次調用

結果:在singleton的bean能夠引用prototype的bean

clipboard.png

相關文章
相關標籤/搜索