[Spring] 9.λΉ μ€μ½ν
1. λΉ μ€μ½νλ?
- μ€νλ§ λΉμ΄ μ€νλ§ μ»¨ν μ΄λμ μμκ³Ό ν¨κ» μμ±λμ΄ μ€νλ§ μ»¨ν μ΄λκ° μ’ λ£λ λ κΉμ§ μ μ§
-> μ€νλ§ λΉμ΄ κΈ°λ³Έμ μΌλ‘ μ±κΈν€ μ€μ½νλ‘ μμ±λκΈ° λλ¬Έ
-> λΉ μ€μ½ν : λΉμ΄ μ‘΄μ¬ν μ μλ λ²μ
μ€νλ§μ λ€μκ³Ό κ°μ λ€μν μ€μ½νλ₯Ό μ§μ
- μ±κΈν€ : κΈ°λ³Έ μ€μ½νΌ, μ€νλ§ μ»¨ν μ΄λμ μμκ³Ό μ’ λ£κΉμ§ μ μ§λλ κ°μ₯ λμ λ²μμ μ€μ½ν
- νλ‘ν νμ : μ€νλ§ μ»¨ν μ΄λλ νλ‘ν νμ λΉμ μμ±κ³Ό μμ‘΄κ΄κ³ μ£Όμ κΉμ§λ§ κ΄μ¬ / λλ κ΄λ¦¬νμ§ μλ λ§€μ° μ§§μ μ€μ½ν
- μΉ κ΄λ ¨ μ€μ½ν
> "request" : μΉ μμ²μ΄ λ€μ΄μ€κ³ λκ° λ κΉμ§ μ μ§λλ μ€μ½ν
> "session" : μΉ μΈμ μ΄ μμ±λκ³ μ’ λ£λ λ κΉμ§ μ μ§λλ μ€μ½ν
> "application" : μΉμ μλΈλ¦Ώ 컨ν μ€μ κ°μ λ²μλ‘ μ μ§λλ μ€μ½ν
λΉ μ€μ½ν μ§μ λ°©λ²
[μ»΄ν¬λνΈ μ€μΊ μλ λ±λ‘]
@Scope("prototype")
@Component
public class HelloBean {}
[μλ λ±λ‘]
@Scope("prototype")
@Bean
PrototypeBean HelloBean() {
return new HelloBean();
}
2. νλ‘ν νμ μ€μ½ν
νλ‘ν νμ μ€μ½ν
- μ±κΈν€ μ€μ½νμ λΉμ μ‘°ννλ©΄ μ€νλ§ μ»¨ν μ΄λλ νμ κ°μ μΈμ€ν΄μ€μ μ€νλ§ λΉμ λ°ν
- νλ‘ν νμ μ€μ½νλ₯Ό μ€νλ§ μ»¨ν μ΄λμ μ‘°ννλ©΄ μ€νλ§ μ»¨ν μ΄λλ νμ μλ‘μ΄ μΈμ€ν΄μ€ μμ±ν΄μ λ°ν
μ±κΈν€ λΉ μμ²
- μ±κΈν€ μ€μ½νμ λΉμ μ€νλ§ μ»¨ν μ΄λμ μμ²νλ€
- μ€νλ§ μ»¨ν μ΄λλ λ³ΈμΈμ΄ κ΄λ¦¬νλ μ€νλ§ λΉμ λ°ννλ€
- μ΄νμ μ€νλ§ μ»¨ν μ΄λμ κ°μ μμ²μ΄ μλ κ°μ κ°μ²΄ μΈμ€ν΄μ€μ μ€νλ§ λΉμΌλ₯΄ λ°ννλ€
νλ‘ν νμ λΉ μμ²1
- νλ‘ν νμ μ€μ½νμ λΉμ μ€νλ§ μ»¨ν μ΄λμ μμ²νλ€
- μ€νλ§ μ»¨ν μ΄λλ μ΄ μμ μ νλ‘ν νμ λΉμ μμ±νκ³ νμν μμ‘΄κ΄κ³λ₯Ό μ£Όμ νλ€
νλ‘ν νμ λΉ μμ²2
- μ€νλ§ μ»¨ν μ΄λλ μμ±ν νλ‘ν νμ λΉμ ν΄λΌμ΄μΈνΈμ λ°ν
- μ΄ν μ€νλ§ μ»¨ν μ΄λμ κ°μ μμ²μ΄ μ€λ©΄ νμ μλ‘μ΄ νλ‘ν νμ λΉμ μμ±ν΄μ λ°ν
μ 리
- μ€νλ§ μ»¨ν μ΄λλ νλ‘ν νμ λΉμ μμ±νκ³ , μμ‘΄κ΄κ³ μ£Όμ , μ΄κΈ°νκΉμ§λ§ μ²λ¦¬
- ν΄λΌμ΄μΈνΈμ λΉμ λ°ννκ³ μ΄ν μ€νλ§ μ»¨ν μ΄λλ μμ±λ νλ‘ν νμ λΉμ κ΄λ¦¬νμ§ μμ
- νλ‘ν νμ λΉμ κ΄λ¦¬ν μ± μμ νλ‘ν νμ λΉμ λ°μ ν΄λΌμ΄μΈνΈμ μλ€
- κ·Έλμ @PreDestroyκ°μ μ’ λ£ λ©μλκ° νΈμΆλμ§ μμ
μ±κΈν€ μ€μ½ν λΉ ν μ€νΈ
public class SingletonTest {
@Test
public void singletonBeanFind() {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SingletonBean.class);
SingletonBean singletonBean1 = ac.getBean(SingletonBean.class);
SingletonBean singletonBean2 = ac.getBean(SingletonBean.class);
System.out.println("singletonBean1 = " + singletonBean1);
System.out.println("singletonBean2 = " + singletonBean2);
assertThat(singletonBean1).isSameAs(singletonBean2);
ac.close(); //μ’
λ£
}
@Scope("singleton")
static class SingletonBean {
@PostConstruct
public void init() {
System.out.println("SingletonBean.init");
}
@PreDestroy
public void destroy() {
System.out.println("SingletonBean.destroy");
}
}
}
νλ‘ν νμ μ€μ½ν λΉ ν μ€νΈ
public class PrototypeTest {
@Test
public void prototypeBeanFind() {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(PrototypeBean.class);
System.out.println("find prototypeBean1");
PrototypeBean prototypeBean1 = ac.getBean(PrototypeBean.class); System.out.println("find prototypeBean2");
PrototypeBean prototypeBean2 = ac.getBean(PrototypeBean.class); System.out.println("prototypeBean1 = " + prototypeBean1);
System.out.println("prototypeBean2 = " + prototypeBean2);
assertThat(prototypeBean1).isNotSameAs(prototypeBean2);
ac.close(); //μ’
λ£
}
@Scope("prototype")
static class PrototypeBean {
@PostConstruct
public void init() {
System.out.println("PrototypeBean.init");
}
@PreDestroy
public void destroy() {
System.out.println("PrototypeBean.destroy");
}
}
}
* κ° λΉμ @Component μμ΄λ AnnotaionConfigApplication μ§μ ν΄μ£Όλ©΄ ν΄λΉ ν΄λμ€κ° μλμΌλ‘ μ»΄ν¬λνΈ μ€μΊμ²λΌ λμ
- μ±κΈν€ λΉμ μ€νλ§ μ»¨ν
μ΄λ μμ± μμ μ μ΄κΈ°ν λ©μλκ° μ€ν λμ§λ§, νλ‘ν νμ
μ€μ½νμ λΉμ μ€νλ§ μ»¨ν
μ΄λμμ λΉμ μ‘°νν λ μμ±λκ³ , μ΄κΈ°ν λ©μλλ μ€νλλ€.
- νλ‘ν νμ λΉμ 2λ² μ‘°ννμΌλ―λ‘ μμ ν λ€λ₯Έ μ€νλ§ λΉμ΄ μμ±λκ³ , μ΄κΈ°νλ 2λ² μ€νλ κ²μ νμΈν μ μλ€. - μ±κΈν€ λΉμ μ€νλ§ μ»¨ν μ΄λκ° κ΄λ¦¬νκΈ° λλ¬Έμ μ€νλ§ μ»¨ν μ΄λκ° μ’ λ£λ λ λΉμ μ’ λ£ λ©μλκ° μ€νλμ§λ§, νλ‘ν νμ λΉμ μ€νλ§ μ»¨ν μ΄λκ° μμ±κ³Ό μμ‘΄κ΄κ³ μ£Όμ κ·Έλ¦¬κ³ μ΄κΈ°ν κΉμ§λ§ κ΄μ¬νκ³ , λλ κ΄λ¦¬νμ§ μλλ€. - λ°λΌμ νλ‘ν νμ λΉμ μ€νλ§ μ»¨ν μ΄λκ° μ’ λ£λ λ @PreDestroy κ°μ μ’ λ£ λ©μλκ° μ ν μ€νλμ§ μλλ€. |
νλ‘ν νμ λΉμ νΉμ§ μ 리
- μ€νλ§ μ»¨ν
μ΄λμ μμ²ν λ λ§λ€ μλ‘ μμ±λλ€.
- μ€νλ§ μ»¨ν μ΄λλ νλ‘ν νμ λΉμ μμ±κ³Ό μμ‘΄κ΄κ³ μ£Όμ κ·Έλ¦¬κ³ μ΄κΈ°νκΉμ§λ§ κ΄μ¬νλ€. - μ’ λ£ λ©μλκ° νΈμΆλμ§ μλλ€. - κ·Έλμ νλ‘ν νμ λΉμ νλ‘ν νμ λΉμ μ‘°νν ν΄λΌμ΄μΈνΈκ° κ΄λ¦¬ν΄μΌ νλ€. - μ’ λ£ λ©μλμ λν νΈμΆλ ν΄λΌμ΄μΈνΈκ° μ§μ ν΄μΌνλ€. |
3. νλ‘ν νμ μ€μ½ν - μ±κΈν€ λΉκ³Ό ν¨κ» μ¬μ©μ λ¬Έμ μ
μ€νλ§ μ»¨ν μ΄λμ νλ‘ν νμ μ€μ½νμ λΉμ μμ²νλ©΄ νμ μλ‘μ΄ κ°μ²΄ μΈμ€ν΄μ€λ₯Ό μμ±ν΄μ λ°ν
νμ§λ§ μ±κΈν€ λΉκ³Ό ν¨κ» μ¬μ©ν λ μλνλλ‘ μ λμνμ§ μμ
[μ€νλ§ μ»¨ν μ΄λμ νλ‘ν νμ λΉμ μ§μ μμ² μμ]
μ€νλ§ μ»¨ν μ΄λμ νλ‘ν νμ λΉ μ§μ μμ²1
- ν΄λΌμ΄μΈνΈ Aλ μ€νλ§ μ»¨ν μ΄λμ νλ‘ν νμ λΉμ μμ²
- μ€νλ§ μ»¨ν μ΄λλ νλ‘ν νμ λΉμ μλ‘ μμ±ν΄μ λ°ν(x01) = ν΄λΉ λΉμ countνλ κ°μ 0
- ν΄λΌμ΄μΈνΈλ μ‘°νν νλ‘ν νμ λΉμ addCount()λ₯Ό νΈμΆνλ©΄μ count νλ +1
- κ²°κ³Όμ μΌλ‘ νλ‘ν νμ λΉ(x01)μ countλ 1μ΄ λ¨
μ€νλ§ μ»¨ν μ΄λμ νλ‘ν νμ λΉ μ§μ μμ²2
- ν΄λΌμ΄μΈνΈBλ μ€νλ§ μ»¨ν μ΄λμ νλ‘ν νμ λΉμ μμ²
- μ€νλ§ μ»¨ν μ΄λλ νλ‘ν νμ λΉμ μλ‘ μμ±ν΄μ λ°ν(x02) ν΄λΉ λΉμ count νλ κ°μ 0
- ν΄λΌμ΄μΈνΈλ μ‘°νν νλ‘ν νμ λΉμ addCount()λ₯Ό νΈμΆνλ©΄μ countνλ +1
- κ²°κ³Όμ μΌλ‘ νλ‘ν νμ λΉ(x02)μ countλ 1μ΄ λ¨
μ½λ
public class SingletonWithPrototypeTest1 {
@Test
void prototypeFind() {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(PrototypeBean.class);
PrototypeBean prototypeBean1 = ac.getBean(PrototypeBean.class);
prototypeBean1.addCount();
assertThat(prototypeBean1.getCount()).isEqualTo(1);
PrototypeBean prototypeBean2 = ac.getBean(PrototypeBean.class);
prototypeBean2.addCount();
assertThat(prototypeBean2.getCount()).isEqualTo(1);
}
@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");
}
}
}
μ±κΈν€ λΉμμ νλ‘ν νμ λΉ μ¬μ©
- clientBeanμ΄λΌλ μ±κΈν€ λΉμ΄ μμ‘΄κ΄κ³ μ£Όμ μ ν΅ν΄μ νλ‘ν νμ λΉμ μ£Όμ λ°μμ μ¬μ©νλ μ
μ±κΈν€μμ νλ‘ν νμ λΉ μ¬μ©1
- clientBeanμ μ±κΈν€μ΄λ―λ‘ λ³΄ν΅ μ€νλ§ μ»¨ν μ΄λ μμ± μμ μ ν¨κ» μμ±λκ³ , μμ‘΄κ΄κ³ μ£Όμ λ λ°μ
- clientBeanμ μμ‘΄κ΄κ³ μλ μ£Όμ μ¬μ© / μ£Όμ μμ μ μ€νλ§ μ»¨ν μ΄λμ νλ‘ν νμ λΉμ μμ²
- μ€νλ§ μ»¨ν μ΄λλ νλ‘ν νμ λΉμ μμ±ν΄μ clientBeanμ λ°ν / νλ‘ν νμ λΉμ countνλ κ°μ 0
- clientBeanμ νλ‘ν νμ λΉμ λ΄λΆ νλμ λ³΄κ΄ (μ ννλ μ°Έμ‘°κ° λ³΄κ΄)
μ±κΈν€μμ νλ‘ν νμ λΉ μ¬μ©2
- ν΄λΌμ΄μΈνΈAλ clientBeanμ μ€νλ§ μ»¨ν μ΄λμ μμ²ν΄μ λ°μ / μ±κΈν€μ΄λ―λ‘ νμ κ°μ clientBeanμ΄ λ°νλ¨
- ν΄λΌμ΄μΈνΈAλ clientBean.logic()μ νΈμΆ
- clientBeanμ prototypeBeanμ addCount()λ₯Ό νΈμΆν΄μ νλ‘ν νμ λΉμ countλ₯Ό μ¦κ° / count κ°μ΄ 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(2);
}
static class ClientBean {
private final PrototypeBean prototypeBean;
@Autowired
public ClientBean(PrototypeBean prototypeBean) {
this.prototypeBean = prototypeBean;
}
public int logic() {
prototypeBean.addCount();
int count = prototypeBean.getCount();
return count;
}
}
@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");
}
}
}
* count 2κ° λ¨ -> νλ‘ν νμ λΉμ μλ‘κ² λ§λ€μ΄μ§λ κ² μλκ°μ? -> ν΄λΌμ΄μΈνΈ λΉ μμ±μμ μ μ΄λ―Έ νλ‘ν νμ μ΄ μ£Όμ λ¨
4. νλ‘ν νμ μ€μ½ν - μ±κΈν€ λΉκ³Ό ν¨κ» μ¬μ©μ Providerλ‘ λ¬Έμ ν΄κ²°
μ±κΈν€ λΉκ³Ό νλ‘ν νμ λΉμ ν¨κ» μ¬μ©ν λ μ΄λ»κ²νλ©΄ μλ‘μ΄ νν ν νμ λΉμ μμ±ν μ μμκΉ?
[μ€νλ§ μ»¨ν μ΄λμ μμ²]
public class PrototypeProviderTest {
@Test
void providerTest() {
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);
}
static class ClientBean {
@Autowired
private ApplicationContext ac;
public int logic() {
PrototypeBean prototypeBean = ac.getBean(PrototypeBean.class);
prototypeBean.addCount();
int count = prototypeBean.getCount();
return count;
}
}
@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");
}
}
}
- μ€νν΄λ³΄λ©΄ ac.getBean() μ ν΅ν΄μ νμ μλ‘μ΄ νλ‘ν νμ
λΉμ΄ μμ±λλ κ²μ νμΈν μ μλ€.
- μμ‘΄κ΄κ³λ₯Ό μΈλΆμμ μ£Όμ (DI) λ°λκ² μλλΌ μ΄λ κ² μ§μ νμν μμ‘΄κ΄κ³λ₯Ό μ°Ύλ κ²μ Dependency Lookup (DL) μμ‘΄κ΄κ³ μ‘°ν(νμ) μ΄λΌνλ€. - κ·Έλ°λ° μ΄λ κ² μ€νλ§μ μ ν리μΌμ΄μ 컨ν μ€νΈ μ 체λ₯Ό μ£Όμ λ°κ² λλ©΄, μ€νλ§ μ»¨ν μ΄λμ μ’ μμ μΈ μ½λκ° λκ³ , λ¨μ ν μ€νΈλ μ΄λ €μμ§λ€. - μ§κΈ νμν κΈ°λ₯μ μ§μ ν νλ‘ν νμ λΉμ 컨ν μ΄λμμ λμ μ°Ύμμ£Όλ λ±! DL μ λμ κΈ°λ₯λ§ μ 곡νλ 무μΈκ°κ° μμΌλ©΄ λλ€. |
ObjectFactory, ObjectProvider
- μ§μ ν λΉμ 컨ν μ΄λμμ λμ μ°Ύμμ£Όλ DL μλΉμ€λ₯Ό μ 곡νλ κ²μ΄ λ°λ‘ ObjectProvider μ΄λ€.
- μ°Έκ³ λ‘ κ³Όκ±°μλ ObjectFactory κ° μμλλ°, μ¬κΈ°μ νΈμ κΈ°λ₯μ μΆκ°ν΄μ ObjectProvider κ° λ§λ€μ΄μ‘λ€.
@Autowired
private ObjectProvider<PrototypeBean> prototypeBeanProvider;
public int logic() {
PrototypeBean prototypeBean = prototypeBeanProvider.getObject();
prototypeBean.addCount();
int count = prototypeBean.getCount();
return count;
}
- μ€νν΄λ³΄λ©΄ prototypeBeanProvider.getObject() μ ν΅ν΄μ νμ μλ‘μ΄ νλ‘ν νμ
λΉμ΄ μμ±λλ κ²μ νμΈν μ μλ€.
- ObjectProvider μ getObject() λ₯Ό νΈμΆνλ©΄ λ΄λΆμμλ μ€νλ§ μ»¨ν μ΄λλ₯Ό ν΅ν΄ ν΄λΉ λΉμ μ°Ύμμ λ°ννλ€. (DL) - μ€νλ§μ΄ μ 곡νλ κΈ°λ₯μ μ¬μ©νμ§λ§, κΈ°λ₯μ΄ λ¨μνλ―λ‘ λ¨μν μ€νΈλ₯Ό λ§λ€κ±°λ mock μ½λλ₯Ό λ§λ€κΈ°λ ν¨μ¬ μ¬μμ§λ€. - ObjectProvider λ μ§κΈ λ± νμν DL μ λμ κΈ°λ₯λ§ μ 곡νλ€. |
νΉμ§
- ObjectFactory: κΈ°λ₯μ΄ λ¨μ, λ³λμ λΌμ΄λΈλ¬λ¦¬ νμ μμ, μ€νλ§μ μμ‘΄
- ObjectProvider: ObjectFactory μμ, μ΅μ , μ€νΈλ¦Ό μ²λ¦¬λ± νΈμ κΈ°λ₯μ΄ λ§κ³ , λ³λμ λΌμ΄λΈλ¬λ¦¬ νμ μμ, μ€νλ§μ μμ‘΄ |
JSR-330 Provider
- javax.inject.Provider λΌλ JSR-330 μλ° νμ€
- gradleμ λΌμ΄λΈλ¬λ¦¬ μΆκ°
μ€νλ§λΆνΈ 3.0 λ―Έλ§
javax.inject:javax.inject:1 λΌμ΄λΈλ¬λ¦¬λ₯Ό gradle dependenciesμ μΆκ°ν΄μΌ νλ€. μ€νλ§λΆνΈ 3.0 μ΄μ jakarta.inject:jakarta.inject-api:2.0.1 λΌμ΄λΈλ¬λ¦¬λ₯Ό gradle dependenciesμ μΆκ°ν΄μΌ νλ€. |
dependencies{
implementation : 'javax.inject:javax.inject:1'
...
}
@Autowired
private Provider<PrototypeBean> provider;
public int logic() {
PrototypeBean prototypeBean = provider.get();
prototypeBean.addCount();
int count = prototypeBean.getCount();
return count;
}
- μ€νν΄λ³΄λ©΄ provider.get() μ ν΅ν΄μ νμ μλ‘μ΄ νλ‘ν νμ
λΉμ΄ μμ±λλ κ²μ νμΈν μ μλ€.
- provider μ get() μ νΈμΆνλ©΄ λ΄λΆμμλ μ€νλ§ μ»¨ν μ΄λλ₯Ό ν΅ν΄ ν΄λΉ λΉμ μ°Ύμμ λ°ννλ€. (DL) - μλ° νμ€μ΄κ³ , κΈ°λ₯μ΄ λ¨μνλ―λ‘ λ¨μν μ€νΈλ₯Ό λ§λ€κ±°λ mock μ½λλ₯Ό λ§λ€κΈ°λ ν¨μ¬ μ¬μμ§λ€. - Provider λ μ§κΈ λ± νμν DL μ λμ κΈ°λ₯λ§ μ 곡νλ€. |
νΉμ§
- get() λ©μλ νλλ‘ κΈ°λ₯μ΄ λ§€μ° λ¨μνλ€.
- λ³λμ λΌμ΄λΈλ¬λ¦¬κ° νμνλ€. - μλ° νμ€μ΄λ―λ‘ μ€νλ§μ΄ μλ λ€λ₯Έ 컨ν μ΄λμμλ μ¬μ©ν μ μλ€. |
μ°Έκ³ :
μ€λ¬΄μμ μλ° νμ€μΈ JSR-330 Providerλ₯Ό μ¬μ©ν κ²μΈμ§, μλλ©΄ μ€νλ§μ΄ μ 곡νλ ObjectProviderλ₯Ό μ¬μ©ν κ²μΈμ§ κ³ λ―Όμ΄ λ κ²μ΄λ€. ObjectProviderλ DLμ μν νΈμ κΈ°λ₯μ λ§μ΄ μ 곡ν΄μ£Όκ³ μ€νλ§ μΈμ λ³λμ μμ‘΄κ΄κ³ μΆκ°κ° νμ μκΈ° λλ¬Έμ νΈλ¦¬νλ€. λ§μ½(μ λ§ κ·Έλ΄μΌμ κ±°μ μκ² μ§λ§) μ½λλ₯Ό μ€νλ§μ΄ μλ λ€λ₯Έ 컨ν μ΄λμμλ μ¬μ©ν μ μμ΄μΌ νλ€λ©΄ JSR-330 Providerλ₯Ό μ¬μ©ν΄μΌνλ€.
μ€νλ§μ μ¬μ©νλ€ λ³΄λ©΄ μ΄ κΈ°λ₯ λΏλ§ μλλΌ λ€λ₯Έ κΈ°λ₯λ€λ μλ° νμ€κ³Ό μ€νλ§μ΄ μ 곡νλ κΈ°λ₯μ΄
κ²ΉμΉ λκ° λ§μ΄ μλ€. λλΆλΆ μ€νλ§μ΄ λ λ€μνκ³ νΈλ¦¬ν κΈ°λ₯μ μ 곡ν΄μ£ΌκΈ° λλ¬Έμ, νΉλ³ν λ€λ₯Έ 컨ν μ΄λλ₯Ό μ¬μ©ν μΌμ΄ μλ€λ©΄, μ€νλ§μ΄ μ 곡νλ κΈ°λ₯μ μ¬μ©νλ©΄ λλ€.
5. μΉ μ€μ½ν
μΉ μ€μ½νμ νΉμ§
- μΉ μ€μ½νλ μΉ νκ²½μμλ§ λμ
- μΉ μ€μ½νλ νλ‘ν νμ κ³Ό λ€λ₯΄κ² μ€νλ¦¬μ΄ ν΄λΉ μ€μ½νμ μ’ λ£μμ κΉμ§ κ΄λ¦¬ (μ’ λ£λ©μλ νΈμΆ)
μΉ μ€μ½ν μ’ λ₯
'request' : HTTPμμ² νλκ° λ€μ΄μ€κ³ λκ°λκΉμ§ μ μ§λλ μ€μ½ν / κ°κ°μ HTTP μμ²λ§λ€ λ³λμ λΉ μΈμ€ν΄μ€κ° μμ±λκ³ κ΄λ¦¬λ¨
'session' : HTTP sessionκ³Ό λμΌν μλͺ μ£ΌκΈ°λ₯Ό κ°μ§λ μ€μ½ν
'application' : μλΈλ¦Ώ 컨ν μ€νΈ('ServletContext')μ λμΌν μλͺ μ£ΌκΈ°λ₯Ό κ°μ§λ μ€μ½ν
'websocket' : μΉ μμΌκ³Ό λμΌν μλ©΄μ£ΌκΈ°λ₯Ό κ°μ§λ μ€μ½ν
ex) request μ€μ½ν
HTTP request μμ² λΉ κ°κ° ν λΉλλ request μ€μ½ν
6. request μ€μ½ν μμ λ§λ€κΈ°
μΉ νκ²½ μΆκ°
- build.gradle
//web λΌμ΄λΈλ¬λ¦¬ μΆκ°
implementation 'org.springframework.boot:spring-boot-starter-web'
μ΄μ hello.cored.CoreApplicationμ mainλ©μλ μ€ννλ©΄ μΉ μ ν리μΌμ΄μ μ€ν νμΈ
μ°Έκ³ :
spring-boot-starter-web λΌμ΄λΈλ¬λ¦¬λ₯Ό μΆκ°νλ©΄ μ€νλ§ λΆνΈλ λ΄μ₯ ν°μΌ μλ²λ₯Ό νμ©ν΄μ μΉ μλ²μ μ€νλ§μ ν¨κ» μ€νμν¨λ€. μ°Έκ³ :
μ€νλ§ λΆνΈλ μΉ λΌμ΄λΈλ¬λ¦¬κ° μμΌλ©΄ μ°λ¦¬κ° μ§κΈκΉμ§ νμ΅ν AnnotationConfigApplicationContext μ κΈ°λ°μΌλ‘ μ ν리μΌμ΄μ μ ꡬλνλ€. μΉ λΌμ΄λΈλ¬λ¦¬κ° μΆκ°λλ©΄ μΉκ³Ό κ΄λ ¨λ μΆκ° μ€μ κ³Ό νκ²½λ€μ΄ νμνλ―λ‘ > AnnotationConfigServletWebServerApplicationContext λ₯Ό κΈ°λ°μΌλ‘ μ ν리μΌμ΄μ μ ꡬλνλ€. |
request μ€μ½ν μμ κ°λ°
- λμμ μ¬λ¬ HTTP μμ²μ΄ μ€λ©΄ μ νν μ΄λ€ μμ²μ΄ λ¨κΈ΄ λ‘κ·ΈμΈμ§ κ΅¬λΆ μ΄λ €μ
- μ΄λ΄λ μ¬μ©νκΈ° μ’μ κ²μ΄ request μ€μ½ν
[d06b992f...] request scope bean create
[d06b992f...] [http://localhost:8080/log-demo] controller test [d06b992f...] [http://localhost:8080/log-demo] service id = testId [d06b992f...] request scope bean close |
- κΈ°λνλ κ³΅ν΅ ν¬λ§· : [UUID][requestURL]{message}
- UUIDλ₯Ό μ¬μ©ν΄μ HTTP μμ² κ΅¬λΆ
- requestURL μ 보λ μΆκ°λ‘ λ£μ΄μ μ΄λ€ URLμ μμ²ν΄μ λ¨μ λ‘κ·ΈμΈμ§ νμΈ
μ½λ
MyLogger.class
γ΄hello.cored.common
@Component
@Scope(value = "request")
public class MyLogger {
private String uuid;
private String requestURL;
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();
System.out.println("[" + uuid + "] request scope bean create:" + this);
}
@PreDestroy
public void close() {
System.out.println("[" + uuid + "] request scope bean close:" + this);
}
}
- λ‘κ·Έλ₯Ό μΆλ ₯νκΈ° μν MyLogger ν΄λμ€μ΄λ€.
- @Scope(value = "request") λ₯Ό μ¬μ©ν΄μ request μ€μ½νλ‘ μ§μ νλ€. - μ΄μ μ΄ λΉμ HTTP μμ² λΉ νλμ© μμ±λκ³ , HTTP μμ²μ΄ λλλ μμ μ μλ©Έλλ€. - μ΄ λΉμ΄ μμ±λλ μμ μ μλμΌλ‘ @PostConstruct μ΄κΈ°ν λ©μλλ₯Ό μ¬μ©ν΄μ uuidλ₯Ό μμ±ν΄μ μ μ₯ν΄λλ€. - μ΄ λΉμ HTTP μμ² λΉ νλμ© μμ±λλ―λ‘, uuidλ₯Ό μ μ₯ν΄λλ©΄ λ€λ₯Έ HTTP μμ²κ³Ό ꡬλΆν μ μλ€. - μ΄ λΉμ΄ μλ©Έλλ μμ μ @PreDestroy λ₯Ό μ¬μ©ν΄μ μ’ λ£ λ©μμ§λ₯Ό λ¨κΈ΄λ€. - requestURLμ μ΄ λΉμ΄ μμ±λλ μμ μλ μ μ μμΌλ―λ‘, μΈλΆμμ setterλ‘ μ λ ₯ λ°λλ€. |
LogDemoController
γ΄hello.cored.web
@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";
}
}
- λ‘κ±°κ° μ μλνλμ§ νμΈνλ ν
μ€νΈμ© 컨νΈλ‘€λ¬λ€.
- μ¬κΈ°μ HttpServletRequestλ₯Ό ν΅ν΄μ μμ² URLμ λ°μλ€. - requestURL κ° http://localhost:8080/log-demo μ΄λ κ² λ°μ requestURL κ°μ myLoggerμ μ μ₯ν΄λλ€. - myLoggerλ HTTP μμ² λΉ κ°κ° ꡬλΆλλ―λ‘ λ€λ₯Έ HTTP μμ² λλ¬Έμ κ°μ΄ μμ΄λ κ±±μ μ νμ§ μμλ λλ€. - 컨νΈλ‘€λ¬μμ controller testλΌλ λ‘κ·Έλ₯Ό λ¨κΈ΄λ€. |
LogDemoService
γ΄hello.cored.logdemo
@Service
@RequiredArgsConstructor
public class LogDemoService {
private final MyLogger myLogger;
public void logic(String id) {
myLogger.log("service id = " + id);
}
}
- λΉμ¦λμ€ λ‘μ§μ΄ μλ μλΉμ€ κ³μΈ΅μμλ λ‘κ·Έλ₯Ό μΆλ ₯
- μ€μ) request scopeλ₯Ό μ¬μ©νμ§ μκ³ νλΌλ―Έν°λ‘ μ΄ λͺ¨λ μ 보λ₯Ό μλΉμ€ κ³μΈ΅μ λκΈ΄λ€λ©΄, νλΌλ―Έν°κ° λ§μμ μ§μ λΆν΄μ§λ€. λ λ¬Έμ λ requestURL κ°μ μΉκ³Ό κ΄λ ¨λ μ λ³΄κ° μΉκ³Ό κ΄λ ¨μλ μλΉμ€ κ³μΈ΅κΉμ§ λμ΄κ°κ² λλ€. μΉκ³Ό κ΄λ ¨λ λΆλΆμ 컨νΈλ‘€λ¬κΉμ§λ§ μ¬μ©ν΄μΌ νλ€. μλΉμ€ κ³μΈ΅μ μΉ κΈ°μ μ μ’ μλμ§ μκ³ , κ°κΈμ μμνκ² μ μ§νλ κ²μ΄ μ μ§λ³΄μ κ΄μ μμ μ’λ€. - request scopeμ MyLogger λλΆμ μ΄λ° λΆλΆμ νλΌλ―Έν°λ‘ λκΈ°μ§ μκ³ , MyLoggerμ λ©€λ²λ³μμ μ μ₯ν΄μ μ½λμ κ³μΈ΅μ κΉλνκ² μ μ§ν μ μλ€. |
* request μ€μ½ν λΉμ μμ§ μμ±λμ§ μλλ€. μ΄ λΉμ μ€μ κ³ κ°μ μμ²μ΄ μμΌ μμ±ν μ μλ€!
7. μ€μ½νμ Provider
μ λ¬Έμ ν΄κ²°)
1) ObjdectProvider μ¬μ©
@Controller
@RequiredArgsConstructor
public class LogDemoController {
private final LogDemoService logDemoService;
private final ObjectProvider<MyLogger> myLoggerProvider;
@RequestMapping("log-demo")
@ResponseBody
public String logDemo(HttpServletRequest request) {
String requestURL = request.getRequestURL().toString();
MyLogger myLogger = myLoggerProvider.getObject();
myLogger.setRequestURL(requestURL);
myLogger.log("controller test");
logDemoService.logic("testId");
return "OK";
}
}
@Service
@RequiredArgsConstructor
public class LogDemoService {
private final ObjectProvider<MyLogger> myLoggerProvider;
public void logic(String id) {
MyLogger myLogger = myLoggerProvider.getObject();
myLogger.log("service id = " + id);
}
}
- ObjectProvider λλΆμ ObjectProvider.getObject() λ₯Ό νΈμΆνλ μμ κΉμ§ request scope λΉμ μμ±μ μ§μ°ν μ μλ€.
- ObjectProvider.getObject() λ₯Ό νΈμΆνμλ μμ μλ HTTP μμ²μ΄ μ§νμ€μ΄λ―λ‘ request scope λΉμ μμ±μ΄ μ μ μ²λ¦¬λλ€. - ObjectProvider.getObject() λ₯Ό LogDemoController , LogDemoService μμ κ°κ° νλ²μ© λ°λ‘ νΈμΆν΄λ κ°μ HTTP μμ²μ΄λ©΄ κ°μ μ€νλ§ λΉμ΄ λ°νλλ€! |
8. μ€μ½νμ Proxy
μ λ¬Έμ ν΄κ²°)
@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyLogger {
}
ν΅μ¬)
- proxyMode = ScopedProxyMode.TARGET_CLASS λ₯Ό μΆκ°. μ μ© λμμ΄ μΈν°νμ΄μ€κ° μλ ν΄λμ€λ©΄ TARGET_CLASS λ₯Ό μ ν μ μ© λμμ΄ μΈν°νμ΄μ€λ©΄ INTERFACES λ₯Ό μ ν - μ΄λ κ² νλ©΄ MyLoggerμ κ°μ§ νλ‘μ ν΄λμ€λ₯Ό λ§λ€μ΄λκ³ HTTP requestμ μκ΄ μμ΄ κ°μ§ νλ‘μ ν΄λμ€λ₯Ό λ€λ₯Έ λΉμ 미리 μ£Όμ ν΄ λ μ μλ€. |
@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);
}
}
μΉ μ€μ½νμ νλ‘μ λμ μ리
CGLIBλΌλ λΌμ΄λΈλ¬λ¦¬λ‘ λ΄ ν΄λμ€λ₯Ό μμ λ°μ κ°μ§ νλ‘μ κ°μ²΄λ₯Ό λ§λ€μ΄μ μ£Όμ
νλ€.
- @Scope μ proxyMode = ScopedProxyMode.TARGET_CLASS) λ₯Ό μ€μ νλ©΄ μ€νλ§ μ»¨ν
μ΄λλ CGLIBλΌλ λ°μ΄νΈμ½λλ₯Ό μ‘°μνλ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©ν΄μ, MyLoggerλ₯Ό μμλ°μ κ°μ§ νλ‘μ κ°μ²΄λ₯Ό μμ±νλ€.
- κ²°κ³Όλ₯Ό νμΈν΄λ³΄λ©΄ μ°λ¦¬κ° λ±λ‘ν μμν MyLogger ν΄λμ€κ° μλλΌ MyLogger$ $EnhancerBySpringCGLIB μ΄λΌλ ν΄λμ€λ‘ λ§λ€μ΄μ§ κ°μ²΄κ° λμ λ±λ‘λ κ²μ νμΈν μ μλ€.
- κ·Έλ¦¬κ³ μ€νλ§ μ»¨ν μ΄λμ "myLogger"λΌλ μ΄λ¦μΌλ‘ μ§μ§ λμ μ μ΄ κ°μ§ νλ‘μ κ°μ²΄λ₯Ό λ±λ‘νλ€. - ac.getBean("myLogger", MyLogger.class) λ‘ μ‘°νν΄λ νλ‘μ κ°μ²΄κ° μ‘°νλλ κ²μ νμΈν μ μλ€. - κ·Έλμ μμ‘΄κ΄κ³ μ£Όμ λ μ΄ κ°μ§ νλ‘μ κ°μ²΄κ° μ£Όμ λλ€. |
κ°μ§ νλ‘μ κ°μ²΄λ μμ²μ΄ μ€λ©΄ κ·Έλ λ΄λΆμμ μ§μ§ λΉμ μμ²νλ μμ λ‘μ§μ΄ λ€μ΄μλ€.
- κ°μ§ νλ‘μ κ°μ²΄λ λ΄λΆμ μ§μ§ myLoggerλ₯Ό μ°Ύλ λ°©λ²μ μκ³ μλ€.
- ν΄λΌμ΄μΈνΈκ° myLogger.logic() μ νΈμΆνλ©΄ μ¬μ€μ κ°μ§ νλ‘μ κ°μ²΄μ λ©μλλ₯Ό νΈμΆν κ²μ΄λ€. - κ°μ§ νλ‘μ κ°μ²΄λ request μ€μ½νμ μ§μ§ myLogger.logic() λ₯Ό νΈμΆνλ€. - κ°μ§ νλ‘μ κ°μ²΄λ μλ³Έ ν΄λμ€λ₯Ό μμ λ°μμ λ§λ€μ΄μ‘κΈ° λλ¬Έμ μ΄ κ°μ²΄λ₯Ό μ¬μ©νλ ν΄λΌμ΄μΈνΈ μ μ₯μμλ μ¬μ€ μλ³ΈμΈμ§ μλμ§λ λͺ¨λ₯΄κ², λμΌνκ² μ¬μ©ν μ μλ€(λ€νμ±) |
λμ μ 리
- CGLIBλΌλ λΌμ΄λΈλ¬λ¦¬λ‘ λ΄ ν΄λμ€λ₯Ό μμ λ°μ κ°μ§ νλ‘μ κ°μ²΄λ₯Ό λ§λ€μ΄μ μ£Όμ
νλ€.
- μ΄ κ°μ§ νλ‘μ κ°μ²΄λ μ€μ μμ²μ΄ μ€λ©΄ κ·Έλ λ΄λΆμμ μ€μ λΉμ μμ²νλ μμ λ‘μ§μ΄ λ€μ΄μλ€. - κ°μ§ νλ‘μ κ°μ²΄λ μ€μ request scopeμλ κ΄κ³κ° μλ€. κ·Έλ₯ κ°μ§μ΄κ³ , λ΄λΆμ λ¨μν μμ λ‘μ§λ§ μκ³ , μ±κΈν€ μ²λΌ λμνλ€. |
νΉμ§ μ 리
- νλ‘μ κ°μ²΄ λλΆμ ν΄λΌμ΄μΈνΈλ λ§μΉ μ±κΈν€ λΉμ μ¬μ©νλ―μ΄ νΈλ¦¬νκ² request scopeλ₯Ό μ¬μ©ν μ μλ€.
- μ¬μ€ Providerλ₯Ό μ¬μ©νλ , νλ‘μλ₯Ό μ¬μ©νλ ν΅μ¬ μμ΄λμ΄λ μ§μ§ κ°μ²΄ μ‘°νλ₯Ό κΌ νμν μμ κΉμ§ μ§μ°μ²λ¦¬ νλ€λ μ μ΄λ€. - κΌ μΉ μ€μ½νκ° μλμ΄λ νλ‘μλ μ¬μ©ν μ μλ€. |
μ£Όμμ
- λ§μΉ μ±κΈν€μ μ¬μ©νλ κ² κ°μ§λ§ λ€λ₯΄κ² λμνκΈ° λλ¬Έμ κ²°κ΅ μ£Όμν΄μ μ¬μ©ν΄μΌ νλ€.
- μ΄λ° νΉλ³ν scopeλ κΌ νμν κ³³μλ§ μ΅μνν΄μ μ¬μ©νμ, 무λΆλ³νκ² μ¬μ©νλ©΄ μ μ§λ³΄μνκΈ° μ΄λ €μμ§λ€. |
'π¨βπ» Web Development > Spring - κΈ°λ³Έ' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
[Spring] 8.λΉ μλͺ μ£ΌκΈ° μ½λ°± (0) | 2023.02.28 |
---|---|
[Spring] 7.λ€μν μμ‘΄κ΄κ³ μ£Όμ λ°©λ² (0) | 2023.02.28 |
[Spring] 6.μ»΄ν¬λνΈ μ€μΊ (0) | 2023.02.24 |
[Spring] 5.μ±κΈν€ 컨ν μ΄λ (0) | 2023.02.22 |
[Spring] 4.μ€νλ§ μ»¨ν μ΄λμ μ€νλ§ λΉ (0) | 2023.02.20 |
μ΅κ·ΌλκΈ