μΈνλ° μ€νλ§ ν΅μ¬ μ리 κΈ°λ³ΈνΈμ μ 리ν κΈμ λλ€.
μ€μ½ν : λΉμ΄ μ‘΄μ¬ν μ μλ λ²μ
μ€νλ§ μ§μ μ€μ½ν
μ±κΈν€ : κΈ°λ³Έ μ€μ½ν, μ€νλ§ μ»¨ν μ΄λμ μμκ³Ό μ’ λ£κΉμ§ μ μ§λλ κ°μ₯ λμ λ²μμ μ€μ½ν
νλ‘ν νμ : μ€νλ§ μ»¨ν μ΄λλ νλ‘ν νμ λΉμ μμ±κ³Ό μμ‘΄κ΄κ³ μ£Όμ κΉμ§λ§ κ΄μ¬νκ³ λλ κ΄λ¦¬νμ§ μλ λ§€μ° μ§§μ λ²μμ μ€μ½ν
μΉ κ΄λ ¨
- request : μΉ μμ²μ΄ λ€μ΄μ€κ³ λκ° λκΉμ§ μ μ§λλ μ€μ½ν
- session : μΉ μΈμ μ΄ μμ±λκ³ μ’ λ£λ λκΉμ§ μ μ§λλ μ€μ½ν
- application : μΉμ μλΈλ¦Ώ 컨ν μ€νΈμ κ°μ λ²μλ‘ μ μ§λλ μ€μ½ν
//μ»΄ν¬λνΈ μ€μΊ μλ λ±λ‘
@Scope("prototype")
@Component
public class HelloBean {}
//μλ λ±λ‘
@Scope("prototype")
@Bean
PrototypeBean HelloBean() {
return new HelloBean();
}
μ±κΈν€ μ€μ½ν
μ€νλ§ μ»¨ν μ΄λλ νμ κ°μ μΈμ€ν΄μ€μ μ€νλ§ λΉμ λ°ν
SingletonBean.init
singletonBean1 = ~.SingletonTest$SingletonBean@12bcd0c0
singletonBean2 = ~.SingletonTest$SingletonBean@12bcd0c0
SingletonBean.destory
νλ‘ν νμ μ€μ½ν
μ€νλ§ μ»¨ν μ΄λλ νμ μλ‘μ΄ μΈμ€ν΄μ€λ₯Ό μμ±ν΄μ λ°ν
νλ‘ν νμ μ€μ½νμ λΉμ μ€νλ§ μ»¨ν μ΄λμ μμ² → μ€νλ§ μ»¨ν μ΄λλ νλ‘ν νμ λΉ μμ±, νμν μμ‘΄κ΄κ³ μ£Όμ , μ΄κΈ°ν
μ΄ν μ€νλ§ μ»¨ν μ΄λλ μμ±λ νλ‘ν νμ λΉμ κ΄λ¦¬ X (νλ‘ν νμ λΉμ λ°μ ν΄λΌμ΄μΈνΈκ° κ΄λ¦¬) → μ’ λ£ λ©μλ(@PreDestory) μλ νΈμΆ X
find prototypeBean1
SingletonBean.init
find prototypeBean2
SingletonBean.init
prototypeBean1 = com.sunny.item_service.scope.PrototypeTest$PrototypeBean@12bcd0c0
prototypeBean2 = com.sunny.item_service.scope.PrototypeTest$PrototypeBean@4879f0f2
μ±κΈν€ λΉκ³Ό νν νμ λΉμ ν¨κ»
public class SingletonWithPrototypeTest {
@Test
void singletonClientUsePrototype() {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(ClientBean.class, PrototypeBean.class);
ClientBean clientBean1 = ac.getBean(ClientBean.class);
int count1 = clientBean1.logic();
assertThat(count1).isEqualTo(1);
ClientBean clientBean2 = ac.getBean(ClientBean.class);
int count2 = clientBean2.logic();
assertThat(count2).isEqualTo(2);
}
@Scope("singleton")
static class ClientBean {
private final PrototypeBean prototypeBean; //μμ± μμ μ μ£Όμ
@Autowired
public ClientBean(PrototypeBean prototypeBean) { this.prototypeBean = prototypeBean; }
public int logic() {
prototypeBean.addCount();
return prototypeBean.getCount();
}
}
@Scope("prototype")
static class PrototypeBean {
private int count = 0;
public void addCount() { count++; }
public int getCount() { return count; }
@PostConstruct
public void init() { System.out.println("PrototypeBean.init = " + this); }
@PreDestroy
public void destroy() { System.out.println("PrototypeBean.destroy"); }
}
}
μ±κΈν€ λΉμ μμ± μμ μλ§ μμ‘΄κ΄κ³ μ£Όμ μ λ°κΈ° λλ¬Έμ,
νλ‘ν νμ λΉμ΄ μλ‘ μμ±λκΈ°λ νμ§λ§ μ±κΈν€ λΉκ³Ό ν¨κ» κ³μ μ μ§λλ κ²μ΄ λ¬Έμ
νλ‘ν νμ λΉμ μ£Όμ μμ μλ§ μλ‘ μμ±νλκ² μλλΌ μ¬μ©ν λλ§λ€ μλ‘ μμ±ν΄μ μ¬μ©νκ³ μΆμ λ,
1. μ±κΈν€ λΉμ΄ νλ‘ν νμ μ μ¬μ©ν λλ§λ€ μ€νλ§ μ»¨ν μ΄λμ μλ‘ μμ²
public class SingletonWithPrototypeTest1 {
@Test
void singletonClientUsePrototype() {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(ClientBean.class, PrototypeBean.class);
ClientBean clientBean1 = ac.getBean(ClientBean.class);
int count1 = clientBean1.logic();
assertThat(count1).isEqualTo(1);
ClientBean clientBean2 = ac.getBean(ClientBean.class);
int count2 = clientBean2.logic();
assertThat(count2).isEqualTo(1);
}
@Scope("singleton")
static class ClientBean {
@Autowired
private ObjectProvider<PrototypeBean> prototypeBeanProvider;
public int logic() {
PrototypeBean prototypeBean = prototypeBeanProvider.getObject();
prototypeBean.addCount();
return prototypeBean.getCount();
}
}
@Scope("prototype")
static class PrototypeBean {...}
}
2. ObjectFactory, ObjectProvider (κΈ°λ₯ μ°¨μ΄)
build.gradle μΆκ°
dependencies {
implementation 'jakarta.inject:jakarta.inject-api:2.0.1'
}
import jakarta.inject.Provider;
public class SingletonWithPrototypeTest {
@Test
void singletonClientUsePrototype() {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(ClientBean.class, PrototypeBean.class);
ClientBean clientBean1 = ac.getBean(ClientBean.class);
int count1 = clientBean1.logic();
assertThat(count1).isEqualTo(1);
ClientBean clientBean2 = ac.getBean(ClientBean.class);
int count2 = clientBean2.logic();
assertThat(count2).isEqualTo(1);
}
@Scope("singleton")
static class ClientBean {
@Autowired
private Provider<PrototypeBean> prototypeBeanProvider;
public int logic() {
PrototypeBean prototypeBean = prototypeBeanProvider.get();
prototypeBean.addCount();
return prototypeBean.getCount();
}
}
@Scope("prototype")
static class PrototypeBean { ... }
}
3. JSR-330 Provider
Providerμ get() νΈμΆνλ©΄ λ΄λΆμμλ μ€νλ§ μ»¨ν μ΄λλ₯Ό ν΅ν΄ ν΄λΉ λΉμ μ°Ύμμ λ°ν (DL)
JSR-330 Provider : μ½λλ₯Ό μ€νλ§μ΄ μλ λ€λ₯Έ 컨ν μ΄λμμλ μ¬μ©ν μ μμ΄μΌ νλ€λ©΄ μ¬μ©
ObjectProvider : DLμ μν νΈμ κΈ°λ₯μ λ§μ΄ μ 곡, μ€νλ§ μΈ λ³λμ μμ‘΄κ΄κ³ μΆκ°κ° νμμκΈ° λλ¬Έμ νΈλ¦¬
νΉλ³ν λ€λ₯Έ 컨ν μ΄λλ₯Ό μ¬μ©ν μΌμ΄ μλ€λ©΄, μ€νλ§μ΄ μ 곡νλ κΈ°λ₯μ μ¬μ©νμ! (ObjectProvider)
λ§€λ² μ¬μ©ν λλ§λ€ μμ‘΄κ΄κ³ μ£Όμ μ΄ μλ£λ μλ‘μ΄ κ°μ²΄κ° νμν λ νλ‘ν νμ λΉ μ¬μ©
μ€λ¬΄μμλ μ±κΈν€ λΉμΌλ‘ λλΆλΆμ λ¬Έμ ν΄κ²° κ°λ₯
μΉ μ€μ½ν
μΉ νκ²½μμλ§ λμ, μ€νλ§μ΄ ν΄λΉ μ€μ½νμ μ’ λ£μμ κΉμ§ κ΄λ¦¬ → μ’ λ£ λ©μλ νΈμΆ
- request : HTTP μμ² νλκ° λ€μ΄μ€κ³ λκ° λκΉμ§ μ μ§λλ μ€μ½ν, κ°κ°μ HTTP μμ²λ§λ€ λ³λμ λΉ μΈμ€ν΄μ€κ° μμ±λκ³ κ΄λ¦¬λλ€
- session : HTTP Sessionκ³Ό λμΌν μλͺ μ£ΌκΈ°λ₯Ό κ°μ§λ μ€μ½ν
- application : μλΈλ¦Ώ 컨ν μ€νΈ(ServletContext)μ λμΌν μλͺ μ£ΌκΈ°λ₯Ό κ°μ§λ μ€μ½ν
- websocket : μΉ μμΌκ³Ό λμΌν μλͺ μ£ΌκΈ°λ₯Ό κ°μ§λ μ€μ½ν
build.gradle μΆκ°
dependencies {
//web λΌμ΄λΈλ¬λ¦¬ μΆκ°
implementation 'org.springframework.boot:spring-boot-starter-web'
}
@Component
@Scope(value = "request") //λΉ μ€μ½ν: HTTP μμ²λΉ νλμ© μμ±, HTTP μμ²μ΄ λλλ μμ μ μ’
λ£
public class MyLogger {
private String uuid;
private String requestURL;
//λΉμ΄ μμ±λλ μμ μλ requestURLλ₯Ό μ μ μμΌλ―λ‘ μΈλΆμμ setterλ‘ μ
λ ₯λ°μ
public void setRequestURL(String requestURL) {
this.requestURL = requestURL;
}
public void log(String message) {
System.out.println("[" + uuid + "][" + requestURL + "] " + message);
}
@PostConstruct
public void init() {
uuid = UUID.randomUUID().toString(); //HTTP μμ²λΉ νλμ© μμ±
System.out.println("[" + uuid + "] request scope bean create: " + this);
}
@PreDestroy
public void close() {
System.out.println("[" + uuid + "] request scope bean close: " + this);
}
}
@Controller
@RequiredArgsConstructor
public class LogDemoController {
private final LogDemoService logDemoService;
private final MyLogger myLogger;
@RequestMapping("log-demo")
@ResponseBody
public String logDemo(HttpServletRequest request) {
String requestURL = request.getRequestURL().toString();
myLogger.setRequestURL(requestURL);
myLogger.log("controller test");
logDemoService.logic("testId");
return "ok";
}
}
@Service
@RequiredArgsConstructor
public class LogDemoService {
private final MyLogger myLogger;
public void logic(String id) {
myLogger.log("service id = " + id);
}
}
ERROR!
Caused by: org.springframework.beans.factory.support.ScopeNotActiveException: Error creating bean with name 'myLogger': 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
request scopeλ νλμ μμ²μ΄ λ€μ΄μ€κ³ λκ° λκΉμ§ μ μ§λλ μ€μ½νμΈλ° λ€μ΄μ¨ μμ²μ΄ μμ΄μ λ°μν μλ¬
LogDemoController, LogDemoService μ½λ λ³κ²½
private final MyLogger myLogger; → private final ObjectProvider<MyLogger> myLoggerProvider; λ³κ²½
MyLogger myLogger = myLoggerProvider.getObject(); μΆκ°
1. Provider (ObjectProvider) μ¬μ©
@Scopeμ proxyMode μΆκ°
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyLogger {}
2. νλ‘μ λ°©μ : MyLoggerμ κ°μ§ νλ‘μ ν΄λμ€λ₯Ό λ§λ€μ΄λκ³ HTTP requestμ μκ΄μμ΄ κ°μ§ νλ‘μ ν΄λμ€λ₯Ό λ€λ₯Έ λΉμ 미리 μ£Όμ
κ°μ§ νλ‘μ κ°μ²΄λ λ΄λΆμμ μ§μ§ λΉμ μμ²νλ μμ λ‘μ§μ΄ λ€μ΄μλ€
λ§μΉ μ±κΈν€μ μ¬μ©νλ κ² κ°μ§λ§ λ€λ₯΄κ² λμνλ―λ‘ μ£Όμν΄μ μ¬μ©! 무λΆλ³ν μ¬μ© κΈμ§!
[4cd29588-ab10-42b9-990c-4524da84f3bd] request scope bean create: ~.MyLogger@6d1ab145 [4cd29588-ab10-42b9-990c-4524da84f3bd][http://localhost:8080/log-demo] controller test
[4cd29588-ab10-42b9-990c-4524da84f3bd][http://localhost:8080/log-demo] service id = testId
[4cd29588-ab10-42b9-990c-4524da84f3bd] request scope bean close: ~.MyLogger@6d1ab145
'π Spring > Lecture' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
| @ModelAttributeμ Model (0) | 2025.04.04 |
|---|---|
| μ€νλ§μ λΉ μλͺ μ£ΌκΈ° μ½λ°± μ§μ (2) | 2025.03.24 |
| Annotation μ§μ μμ± (0) | 2025.03.24 |
| μ‘°ν λΉμ΄ 2κ° μ΄μμΌ λ (0) | 2025.03.24 |
| μμ‘΄κ΄κ³ μ£Όμ (0) | 2025.03.24 |
