πSpring Beanκ³Ό μλͺ μ£ΌκΈ°, μ€μ½ν
ν΅μ¬μ리 μ리μ¦
(μ΄ κΈμ κΉμν λμ μ€νλ§ ν΅μ¬μ리 κΈ°λ³ΈνΈμ 곡λΆνκ³ μμ±ν κΈμ λλ€)
μ λν° 3D κ²μμμ§μ GameObjectλΌλμ§ Reactμ Componentλ₯Ό 보면 λͺ¨λ μλͺ μ£ΌκΈ° ν¨μκ° μλ€. κ°μ²΄κ° μμ±λ λ, μλ©Έλ λ, μ λ°μ΄νΈ λ λμ λμλ€μ μ μνλ κ²μ΄λ€. μ΄λ Effective C++μμ μ€λͺ νλ RAII(Resource Acquisition Is Initialization) κ°λ κ³Όλ λ§λΏμ μλ€.
μ΄λκ²μ΄ μ€λ¦¬μ§λμΈμ§λ λͺ°λΌλ μ€νλ§ Bean μμ μ΄λ¬ν μλͺ μ£ΌκΈ° ν¨μλ₯Ό κ°μ§κ³ μλ€. κ·Έκ²μ λν μ€λͺ μ ν κ²μ΄λ€.
λ¨Όμ ν΄λμ€μλ μμ±μμ μλ©ΈμλΌλ νλ₯ν μλͺ μ£ΌκΈ° λκ΅¬κ° μλλ° μ λ€λ₯Έ μ½λ°±ν¨μκ° νμν κ²μΌκΉ? λ΅μ μ€νλ§μ κ²½μ° Beanμ μμ±κ³Ό μμ‘΄μ± μ£Όμ μ μμ μ΄ λ€λ₯Ό μ μκΈ° λλ¬Έμ΄λ€. (λ¬Όλ‘ κ°μ₯ λ§μ΄ μ¬μ©νλ μμ±μ μ£Όμ μ κ²½μ°λ λ μμ μ΄ λμΌνμ¬ κ±±μ ν νμλ μλ€)
μμμ RAIIμ λν΄ μΈκΈνμμ§λ§ μ€νλ§μμλ μ‘°κΈ λ€λ₯Έ μ² νμ κ°μ§κ³ μλλ―νλ€. κ°μ²΄μ μμ±κ³Ό μ΄κΈ°νλ₯Ό λΆλ¦¬νμ¬ μν μ λλλ κ²μ΄λ€. λ¨μΌμ± μμμΉμ μκ°νλ©΄ μ³μ λ§μΌ μ μκ³ , RAII κ°λ μ΄ λμ¨ C++μμλ κ°λΉμ§ 컬λ ν°κ° μμ΄ μμμ ν΄μ κ° λ무λλ μ€μνλ€λ λ°°κ²½μ μκ°ν΄λ΄μΌ νλ€.
κ·ΈλΌ λ³Έκ²©μ μΌλ‘ μλͺ μ£ΌκΈ°μ κ΄λ ¨λ μ½λ°±μ λν΄ μμ보μ.
- μμμ μ΄μ©νλ λ°©λ²
public class NetworkClient implements InitializingBean, DisposableBean {
@Override
public void afterPropertiesSet() throws Exception {
connect();
}
@Override
public void destroy() throws Exception {
disConnect();
}
}
μ μ½λμμ λ³΄λ― InitializingBean, DisposableBean μΈν°νμ΄μ€λ₯Ό μμνκ³ κ·Έμ λ°λ₯Έ afterPropertiesSet(), destroy()λ₯Ό ꡬννλ λ°©μμ΄λ€. νμ§λ§ κ±°μ μ¬μ©λμ§ μλ λ°©λ²μΈλ° μ΄μ λ, μ μΈν°νμ΄μ€λ€μ μ€νλ§μμ μ 곡νλ λ΄μ©μ΄λΌ μ μ°μ±μ΄ λ¨μ΄μ§κ³ λ©μλλͺ μ λ³κ²½ν μ μκΈ° λλ¬Έμ΄λ€.
- Bean μ€μ μ μ§μ νλ λ°©λ²
@Configuration
static class LifeCycleConfig {
@Bean(initMethod = "init", destroyMethod = "close")
public NetworkClient networkClient() {
...
μ½λμμ λ³΄λ― Bean μ λ Έν μ΄μ μμ μ§μ μλͺ μ£ΌκΈ° ν¨μλͺ μ λ±λ‘ν μ μλ€. μμ λ°©μμ λ¬Έμ μλ λ©μλλͺ μ§μ λ¬Έμ λ₯Ό ν΄κ²°ν μ μλ€. νκ°μ§ λ λΉλ°μ΄ μλλ° μ΄ κΈ°λ₯μλ λ©μλλͺ μΆλ‘ κΈ°λ₯μ΄ μμ΄μ destroyMethodλ₯Ό λ£μ§ μμλ close, shutdownκ³Ό κ°μ μλ―Έμ λ©μλλ₯Ό μ°Ύμμ μλμΌλ‘ νΈμΆν΄μ€λ€. νΈλ¦¬ν μλ μμ§λ§ μμλ λͺ μμ μΈ κ²μ΄ μ’λ€. κ°μΈμ μΌλ‘λ μ°μ§ μμ κ² κ°λ€.
- @PostConstruct, @PreDestory μ λ Έν μ΄μ μ νμ©νλ λ°©λ²
@PostConstruct
public void init() {
connect();
}
@PreDestroy
public void close() {
disConnect();
}
λ± λ³΄λ©΄ μλ€μνΌ κ°μ₯ κΆμ₯λλ κΈ°λ²μ΄λ€. μ΅μ μ€νλ§ νΈλ λμ λ§κ² μ λ Έν μ΄μ μΌλ‘ κ°λ¨νκ² μ μκ° κ°λ₯νκ³ λ©μλλͺ μ§μ λ κ°λ₯νλ©°, 무μλ³΄λ€ μλ° νμ€μΌλ‘ λμν΄μ μ€νλ§μ μ’ μμ±μ΄ μλ€.
Bean μ€μ½ν
Beanμ κΈ°λ³Έμ μΌλ‘ μ±κΈν€μΌλ‘ ꡬνλμ΄ μ€νλ§ μ»¨ν μ΄λκ° μ¬λΌμ§ λκΉμ§(μ ν리μΌμ΄μ μ΄ μ’ λ£λ λκΉμ§) μ μ§λλ€. νμ§λ§ μ±κΈν€ Beanλ§ μλ κ²μ μλλ©° λ€μν μ€μ½νλ₯Ό κ°μ§ Beanλ€μ΄ μ‘΄μ¬νλ€. μ΄λ²μλ Bean μ€μ½νμ λν΄ μμλ³Ό κ²μ΄λ€.
λ¨Όμ Bean μ€μ½νμ μ’ λ₯μ λν΄ μμ보μ.
μ±κΈν€
: κΈ°λ³Έ μ€μ½ν, μ€νλ§ μ»¨ν μ΄λμ μμκ³Ό μ’ λ£κΉμ§ μ μ§λλ κ°μ₯ λμ λ²μμ μ€μ½νμ΄λ€.νλ‘ν νμ
: μ€νλ§ μ»¨ν μ΄λλ νλ‘ν νμ λΉμ μμ±κ³Ό μμ‘΄κ΄κ³ μ£Όμ κΉμ§λ§ κ΄μ¬νκ³ λλ κ΄λ¦¬νμ§ μλ λ§€μ° μ§§μ λ²μμ μ€μ½νμ΄λ€.μΉ κ΄λ ¨ μ€μ½ν
request: μΉ μμ²μ΄ λ€μ΄μ€κ³ λκ°λ κΉμ§ μ μ§λλ μ€μ½νμ΄λ€.
session: μΉ μΈμ μ΄ μμ±λκ³ μ’ λ£λ λ κΉμ§ μ μ§λλ μ€μ½νμ΄λ€.
application: μΉμ μλΈλ¦Ώ 컨ν μ€νΈμ κ°μ λ²μλ‘ μ μ§λλ μ€μ½νμ΄λ€.
websocket: μΉ μμΌκ³Ό λμΌν μλͺ μ£ΌκΈ°λ₯Ό κ°μ§λ μ€μ½νμ΄λ€.
μ€μ½ν μ§μ μ κ°λ¨νλ€. μμλ μ λ Έν μ΄μ μ ν΅ν΄μ μλμ κ°μ΄ μ§μ ν μ μλ€.
@Scope("prototype")
@Component
public class HelloBean {
...
κ·Έλ λ€λ©΄ μ’ λ μμΈν κ°κ°μ μ€μ½νμ λν΄ μμ보μ.
νλ‘ν νμ
μ€μ½ν
λ κ°λ¨ν λ§ν΄ μ±κΈν€μ΄ μλ Beanμ μλ―Ένλ€. μμ‘΄μ±μ΄ μ£Όμ
λ λλ§λ€ μλ‘μ΄ μΈμ€ν΄μ€κ° μ겨λλ κ²μ΄λ€. μ€νλ§ μ»¨ν
μ΄λλ μμ‘΄μ± μ£Όμ
λ° μ΄κΈ°νκΉμ§λ§μ λ΄λΉνκ³ λ μ΄μ μ΄ Beanμ κ΄λ¦¬νμ§ μλλ€. λ°λΌμ μ μλͺ
μ£ΌκΈ°μμ μ€λͺ
νλ Destroy λ©μλ λ±λ νΈμΆλμ§ μλλ€.
μ΄λ° κ²½μ°λ₯Ό μ‘°μ¬νμ. μ±κΈν€ Beanμ΄ νλ‘ν νμ Beanμ μ£Όμ λ°λ κ²½μ° μ±κΈν€ Bean μ μ₯μμλ νλ‘ν νμ Beanμ μ£Όμ λ°μ λ νΌλ°μ€λ₯Ό κ°μ§κ³ μλ κ²μ΄λ―λ‘ κ·Έ λ©μλκ° λΆλ¦΄λλ§λ€ μλ‘ μμ±λμ§λ μλλ€λ μ μ΄λ€. λ€μ λ§νμλ©΄ μ¬μ©ν λλ§λ€ μμ±λμ§ μλλ€!
κ·Έλ λ€λ©΄ μ΄λ° λ¬Έμ λ μ΄λ»κ² ν΄κ²°ν΄μΌν κΉ? μ΄λ°μ μ€λͺ νλ Providerλ₯Ό μ΄μ©ν΄μ Beanμ κ·Έλκ·Έλ μ£Όμ λ°λλ€λ©΄ ν΄κ²°μ κ°λ₯ν κ²μ΄λ€.
public int logic() {
PrototypeBean prototypeBean = ac.getBean(PrototypeBean.class);
...
νμ§λ§ λ κΉλν λ°©λ²μ μμκΉ? μ λ°©λ²μ 컨ν μ€νΈλ₯Ό κ°μ ΈμμΌνκ³ κ·Έλ¦¬ μ΄μμ§ μμ APIλ₯Ό κ³μ νΈμΆν΄μΌ νλ€.
Dependancy Lookup
μ μ΄μ©νλ©΄ κ°λ₯νλ€. μμ‘΄κ΄κ³λ₯Ό μΈλΆμμ μ£Όμ (DI) λ°λκ² μλλΌ μ΄λ κ² μ§μ νμν μμ‘΄κ΄κ³λ₯Ό μ°Ύλ κ²μ Dependency Lookup (DL) μμ‘΄κ΄κ³ μ‘°νλΌνλ€.
μ€νλ§μμ μ§μ ν Beanμ 컨ν μ΄λμμ λμ μ°Ύμμ£Όλ DL μλΉμ€λ₯Ό μ 곡νλ κ²μ΄ λ°λ‘ ObjectProviderμ΄λ€. μ¬μ©λ²μ μλμ κ°λ€.
@Autowired
private ObjectProvider<PrototypeBean> prototypeBeanProvider;
public int logic() {
PrototypeBean prototypeBean = prototypeBeanProvider.getObject();
prototypeBean.addCount();
int count = prototypeBean.getCount();
return count;
}
μ κΈ°λ₯μ μ€νλ§μ μμ‘΄μ μ΄λ€. μλ° νμ€λ§μΌλ‘ ν΄κ²°νλ λ°©λ² λν μ‘΄μ¬νλ€.
//implementation 'javax.inject:javax.inject:1' gradle μΆκ° νμ @Autowired
private Provider<PrototypeBean> provider;
public int logic() {
PrototypeBean prototypeBean = provider.get();
prototypeBean.addCount();
int count = prototypeBean.getCount();
return count;
}
μ€νλ§μ μμ‘΄νμ§λ μμ§λ§ gradleμ μ€μ μΆκ°κ° νμνκ³ , Beanμ μ°Ύλλ€λ μμ²΄κ° μ€νλ§μ μμ‘΄μ μ΄μ§ μλνλ μκ°μ΄ λ λ€. μ무λλ ObjectProviderμ μ¬μ©μ΄ κ°μ₯ μ’μ보μΈλ€. λλΆλΆμ μλ° νμ€λ³΄λ€ μ€νλ§μ΄ νΈλ¦¬νκ² κΈ°λ₯μ ꡬννκ³ μλ€.
DLμ νλ‘ν νμ Beanμ μ£Όμ μ΄μΈμλ μΈμΌμ΄ μμ μ μμΌλ μ μ 리ν΄λμ.
μ΄λ²μλ νλ‘μλ₯Ό μ¬μ©νλ λ°©λ²μ μμ보μ.
ν΄λΌμ΄μΈνΈλ μ€μ Beanκ³Ό λκ°μ Proxy Beanμ μ£Όμ
λ°κ³ λ€νμ±μ μ΄μ©ν΄μ μ€μ Beanμ΄ νΈμΆλμ΄ κ°κ° μ€μ λ‘λ μλ§μ Beanμ μ¬μ©ν μ μλ λ°©μμ΄λ€.
λ΄λΆ ꡬ쑰λ₯Ό μ΄ν΄λ³΄λ©΄ μ΄λ²μλ CGLIBλ₯Ό ν΅ν΄ Proxy κ°μ²΄κ° μμ±λλ λ°©μμ΄λ€. μμ λ‘μ§μ΄ μλμΌλ‘ ꡬνλλ©° μ€μ Beanμ μ°Ύλ κ³Όμ μ νΈμΆκΉμ§ μ§μ°λλ€.
@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyLogger {
}
μ λ κ² μ€μ νλ©΄ MyLoggerλ₯Ό μ¬μ©νλ λΆλΆμλ νλ‘μ κ°μ²΄κ° μλμΌλ‘ μ£Όμ λλ κ²μ΄λ€.