Статьи

Spring Scoped Proxy

Рассмотрим два компонента Spring, определенных следующим образом:

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.