01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
@Component class SingletonScopedBean{ @Autowired private PrototypeScopedBean prototypeScopedBean; public String getState(){ return this .prototypeScopedBean.getState(); } } @Component @Scope (value= "prototype" ) class PrototypeScopedBean{ private final String state; public PrototypeScopedBean(){ this .state = UUID.randomUUID().toString(); } public String getState() { return state; } } |
Здесь прототип боба с ограниченным объемом вводится в боб синглтона с ограниченным объемом действия.
Теперь рассмотрим этот тест, используя следующие компоненты:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
@RunWith (SpringJUnit4ClassRunner. class ) @ContextConfiguration public class ScopedProxyTest { @Autowired private SingletonScopedBean singletonScopedBean; @Test public void testScopedProxy() { assertThat(singletonScopedBean.getState(), not(equalTo(singletonScopedBean.getState()))); } @Configuration @ComponentScan ( "org.bk.samples.scopedproxy" ) public static class SpringContext{} } |
Следует отметить, что здесь создается только 1 экземпляр PrototypeScopedBean, и этот 1 экземпляр внедряется в SingletonScopedBean, поэтому приведенный выше тест, который фактически ожидает новый экземпляр PrototypeScopedBean при каждом вызове метода getState (), завершится неудачно. ,
Если при каждом запросе к PrototypeScopedBean требуется новый экземпляр (и, как правило, если компонент с более длинной областью имеет компонент с более короткой областью действия в качестве зависимости, и более короткую область необходимо учитывать), то существует несколько решений:
1. Метод поиска инъекций — о котором можно прочитать здесь
2. Лучшим решением является использование прокси Scoped —
Прокси с заданной областью можно указать таким образом, используя @Configuration:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
@Component @Scope (value= "prototype" , proxyMode=ScopedProxyMode.TARGET_CLASS) class PrototypeScopedBean{ private final String state; public PrototypeScopedBean(){ this .state = UUID.randomUUID().toString(); } public String getState() { return state; } } |
С этим изменением компонент, внедренный в SingletonScopedBean, является не самим PrototypeScopedBean, а посредником для компонента (созданным с использованием CGLIB или динамических прокси-серверов), и этот прокси-сервер понимает область и возвращает экземпляры на основе требований области, тест должен сейчас работаю как положено.
Ссылка: Spring Scoped Proxy от нашего партнера JCG Биджу Кунджуммен в блоге all and sundry.