Copy @ Scope ( "{์ค์ฝํ์ข
๋ฅ}" )
@ Component
public class prototypeBean {}
์ฑ๊ธํค : ๊ธฐ๋ณธ ์ค์ฝํ, ์คํ๋ง ์ปจํ
์ด๋์ ์์๊ณผ ์ข
๋ฃ๊น์ง ์ ์ง๋๋ ๊ฐ์ฅ ๋์ ๋ฒ์์ ์ค์ฝํ
ํ๋กํ ํ์
: ์คํ๋ง ์ปจํ
์ด๋๋ ํ๋กํ ํ์
๋น์ ์์ฑ๊ณผ ์์กด๊ด๋ฆฌ ์ฃผ์
๊น์ง๋ง ๊ด์ฌํ๊ณ ๋๋ ๊ด๋ฆฌํ์ง ์๋ ๋งค์ฐ ์งง์ ๋ฒ์์ ์ค์ฝํ
์น ๊ด๋ จ ์ค์ฝํ
request: ์น ์์ฒญ์ด ๋ค์ด์ค๊ณ ๋๊ฐ๋๊น์ง ์ ์ง
session: ์น ์ธ์
์ด ์์ฑ๋๊ณ ์ข
๋ฃ๋ ๋ ๊น์ง ์ ์ง
application: ์น์ ์๋ธ๋ฆฟ ์ปจํ
์ค์ ๊ฐ์ ๋ฒ์๋ก ์ ์ง
์ฑ๊ธํค
์ฑ๊ธํค ์ค์ฝํ์ ๋น์ ์คํ๋ง ์ปจํ
์ด๋์ ์์ฒญ
์คํ๋ง ์ปจํ
์ด๋๋ ๋ณธ์ธ์ด ๊ด๋ฆฌํ๋ ์คํ๋ง ๋น ๋ฐํ
์คํ๋ง ์ปจํ
์ด๋์ ๊ฐ์ ์์ฒญ์ด ์๋ ๊ฐ์ ์ธ์คํด์ค์ ์คํ๋ง ๋น ๋ฐํ
Copy import org . junit . jupiter . api . Test ;
import org . springframework . context . annotation . AnnotationConfigApplicationContext ;
import org . springframework . context . annotation . Scope ;
import javax . annotation . PostConstruct ;
import javax . annotation . PreDestroy ;
import static org . assertj . core . api . Assertions . * ;
public class SingletonTest {
@ Test
void singletonBeanFile () {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext( SingletonBean . class ) ;
System . out . println ( "find singletonBean1" );
SingletonBean singletonBean1 = ac . getBean ( SingletonBean . class );
System . out . println ( "find singletonBean2" );
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" );
}
}
}
Copy org . springframework . beans . factory . support . DefaultListableBeanFactory - Creating shared instance of singleton bean 'singletonTest.SingletonBean'
SingletonBean . init
find singletonBean1
find singletonBean2
singletonBean1 = dh0023 . springcore . scope . SingletonTest$SingletonBean @ 37e4d7bb
singletonBean2 = dh0023 . springcore . scope . SingletonTest$SingletonBean @ 37e4d7bb
22 : 55 : 36.852 [main] DEBUG org . springframework . context . annotation . AnnotationConfigApplicationContext - Closing org . springframework . context . annotation . AnnotationConfigApplicationContext @ 193f604a , started on Mon May 17 22 : 55 : 36 KST 2021
SingletonBean . destroy
์ฑ๊ธํค ์ค์ฝํ์ ๋น์ ๋์ผํ ๋น์ ์์ฑํ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค. ๋ํ ์คํ๋ง ์ปจํ
์ด๋ ์์ฑ ์์ ์ ์ด๊ธฐํ ๋ฉ์๋๊ฐ ์คํ๋๋ฉฐ, ์คํ๋ง์ปจํ
์ด๋ ์ข
๋ฃ์ @PreDestroy
๋ฉ์๋๊ฐ ํธ์ถ๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
ํ๋กํ ํ์
์คํ๋ง ์ปจํ
์ด๋๋ ํ๋กํ ํ์
๋น์ ์์ฑํ๊ณ , ์์กด๊ด๊ณ ์ฃผ์
, ์ด๊ธฐํ๊น์ง๋ง ์ฒ๋ฆฌ ํ๋ค. ํ๋กํ ํ์
๋น์ ๊ด๋ฆฌํ ์ฑ
์์ ํ๋กํ ํ์
๋น์ ๋ฐ์ ํด๋ผ์ด์ธํธ์ ์๋ค.(@PreDestroy
๊ฐ์ ์ข
๋ฃ ๋ฉ์๋๊ฐ ํธ์ถ๋์ง ์์ .)
ํ๋กํ ํ์
์ค์ฝํ ๋น์ ์คํ๋ง ์ปจํ
์ด๋์ ์์ฒญ
์คํ๋ง ์ปจํ
์ด๋๋ ์ด ์์ ์ ํ๋กํ ํ์
๋น์ ์์ฑํ๊ณ , ํ์ํ ์์กด๊ด๊ณ๋ฅผ ์ฃผ์
์คํ๋ง ์ปจํ
์ด๋๋ ์์ฑํ ํ๋กํ ํ์
๋น์ ํด๋ผ์ด์ธํธ์ ๋ฐํ
๊ฐ์ ์์ฒญ์ด ์๋ ํญ์ ์๋ก์ด ํ๋กํ ํ์
๋น์ ์์ฑํด์ ๋ฐํ
Copy import org . junit . jupiter . api . Test ;
import org . springframework . context . annotation . AnnotationConfigApplicationContext ;
import org . springframework . context . annotation . Scope ;
import javax . annotation . PostConstruct ;
import javax . annotation . PreDestroy ;
import static org . assertj . core . api . Assertions . assertThat ;
public class PrototypeTest {
@ Test
void PrototypeBeanFile () {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext( PrototypeBean . class ) ;
PrototypeBean prototypeBean1 = ac . getBean ( PrototypeBean . class );
System . out . println ( "find prototypeBean1" );
PrototypeBean prototypeBean2 = ac . getBean ( PrototypeBean . class );
System . out . println ( "find prototypeBean2" );
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" );
}
}
}
Copy DEBUG org . springframework . beans . factory . support . DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
PrototypeBean . init
find prototypeBean1
PrototypeBean . init
find prototypeBean2
prototypeBean1 = dh0023 . springcore . scope . PrototypeTest$PrototypeBean @ 37e4d7bb
prototypeBean2 = dh0023 . springcore . scope . PrototypeTest$PrototypeBean @ 6f7923a5
22 : 44 : 40.464 [main] DEBUG org . springframework . context . annotation . AnnotationConfigApplicationContext - Closing org . springframework . context . annotation . AnnotationConfigApplicationContext @ 193f604a , started on Mon May 17 22 : 44 : 40 KST 2021
Process finished with exit code 0
์คํ๋ง ์ปจํ
์ด๋์์ ๋น์ ์กฐํํ ๋ ์์ฑ๋๋ค. (์ด๊ธฐํ 2๋ฒ๋ ๊ฒ ํ์ธ ๊ฐ๋ฅ)
prototypeBean1๊ณผ prototypeBean2์ ์ฃผ์๊ฐ ๋ค๋ฅธ๊ฒ์ ํ์ธํ ์ ์๋ค. ์ฆ, ์๋ก์ด ๋น์ ์์ฑํ๋ค.
๋ํ, ํ๋กํ ํ์
๋น์ ์คํ๋ง ์ปจํ
์ด๋๊ฐ ์์ฑ, ์์กด๊ด๊ณ ์ฃผ์
, ์ด๊ธฐํ ๊น์ง ๊ด์ฌํ๋ฏ๋ก ์คํ๋ง ์ปจํ
์ด๋ ์ข
๋ฃ์ @PreDestroy
์ข
๋ฃ๋ฉ์๋์ธ destroy()
๊ฐ ํธ์ถ๋์ง ์์ ๊ฒ์ ํ์ธํ ์ ์๋ค.
๋ง์ฝ ํ๋กํ ํ์
๋น์ ์ข
๋ฃํ๊ณ ์ถ์ ๊ฒฝ์ฐ์๋ ์ง์ ์๋์ ๊ฐ์ด ํด๋น ๋ฉ์๋๋ฅผ ํธ์ถํด์ค์ผํ๋ค.
Copy // destroy ํ์์ ์ง์ ํธ์ถ ํ์
prototypeBean1 . destroy ();
prototypeBean2 . destroy ();
ํ๋กํ ํ์
์ค์ฝํ๋ฅผ ์ฑ๊ธํค ๋น๊ณผ ํจ๊ป ์ฌ์ฉํ๊ณ ์ถ๋ค๋ฉด?
์ฑ๊ธํค ๋น๊ณผ ํ๋กํ ํ์
๋น์ ํจ๊ป ์ฌ์ฉํ ๋, ๋งค๋ฒ ์๋ก์ด ํ๋กํ ํ์
๋น์ ์์ฑํ๊ณ ์ถ์ ๊ฒฝ์ฐ์๋ Provider
๋ฅผ ์ด์ฉํ๋ฉด๋๋ค.
ObjectProvider
Copy package org . springframework . beans . factory ;
import java . util . Iterator ;
import java . util . function . Consumer ;
import java . util . function . Supplier ;
import java . util . stream . Stream ;
import org . springframework . beans . BeansException ;
import org . springframework . lang . Nullable ;
/**
* A variant of {@link ObjectFactory} designed specifically for injection points,
* allowing for programmatic optionality and lenient not-unique handling.
*
* <p>As of 5.1, this interface extends {@link Iterable} and provides {@link Stream}
* support. It can be therefore be used in {@code for} loops, provides {@link #forEach}
* iteration and allows for collection-style {@link #stream} access.
*
* @author Juergen Hoeller
* @since 4.3
* @param <T> the object type
* @see BeanFactory#getBeanProvider
* @see org.springframework.beans.factory.annotation.Autowired
*/
public interface ObjectProvider < T > extends ObjectFactory < T > , Iterable < T > {
/**
* Return an instance (possibly shared or independent) of the object
* managed by this factory.
* <p>Allows for specifying explicit construction arguments, along the
* lines of { @link BeanFactory #getBean(String, Object...)}.
* @param args arguments to use when creating a corresponding instance
* @return an instance of the bean
* @throws BeansException in case of creation errors
* @see #getObject()
*/
T getObject ( Object ... args) throws BeansException ;
...
}
์ง์ ํ ๋น์ ์ปจํ
์ด๋์์ ๋์ ์ฐพ์์ฃผ๋ DL(Dependency Lookup - ์์กด๊ด๊ณ๋ฅผ ์ฐพ์) ์๋น์ค๋ฅผ ์ ๊ณตํ๋ค.
์ด๋ ObjectProvider
๋ ObjectFactory
๋ฅผ ์์๋ฐ๊ณ ์๋ค.
ObjectFactory
Copy package org . springframework . beans . factory ;
import org . springframework . beans . BeansException ;
/**
* Defines a factory which can return an Object instance
* (possibly shared or independent) when invoked.
*
* <p>This interface is typically used to encapsulate a generic factory which
* returns a new instance (prototype) of some target object on each invocation.
*
* <p>This interface is similar to {@link FactoryBean}, but implementations
* of the latter are normally meant to be defined as SPI instances in a
* {@link BeanFactory}, while implementations of this class are normally meant
* to be fed as an API to other beans (through injection). As such, the
* {@code getObject()} method has different exception handling behavior.
*
* @author Colin Sampaleanu
* @since 1.0.2
* @param <T> the object type
* @see FactoryBean
*/
@ FunctionalInterface
public interface ObjectFactory < T > {
/**
* Return an instance (possibly shared or independent)
* of the object managed by this factory.
* @return the resulting instance
* @throws BeansException in case of creation errors
*/
T getObject () throws BeansException ;
}
ObjectFactory์ getObject()
๋ฅผ ํธ์ถํ๋ฉด ๋ด๋ถ์์ ์คํ๋ง ์ปจํ
์ด๋๋ฅผ ํตํด ํด๋น ๋น์ ์ฐพ์์ ๋ฐํํ๋ค.
Copy package dh0023 . springcore . scope ;
import lombok . RequiredArgsConstructor ;
import org . assertj . core . api . Assertions ;
import org . junit . jupiter . api . Test ;
import org . springframework . beans . factory . ObjectProvider ;
import org . springframework . beans . factory . annotation . Autowired ;
import org . springframework . context . annotation . AnnotationConfigApplicationContext ;
import org . springframework . context . annotation . Scope ;
import javax . annotation . PostConstruct ;
import javax . annotation . PreDestroy ;
import static org . assertj . core . api . Assertions . * ;
public class SingletonWithPrototypeTest {
@ Test
void singletonClientUseObjectProvider () {
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 > prototypeBeanObjectProvider;
public int logic () {
PrototypeBean prototypeBean = prototypeBeanObjectProvider . getObject ();
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" );
}
}
}
JSR-330 Provider
์๋ฐํ์ค Provider๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด, ํด๋น ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ถ๊ฐํด์ค์ผํ๋ค.
build.gradle
Copy implementation 'javax.inject:javax.inject:1'
Copy public interface Provider < T > {
/**
* Provides a fully-constructed and injected instance of {@code T}.
*
* @throws RuntimeException if the injector encounters an error while
* providing an instance. For example, if an injectable member on
* {@code T} throws an exception, the injector may wrap the exception
* and throw it to the caller of {@code get()}. Callers should not try
* to handle such exceptions as the behavior may vary across injector
* implementations and even different configurations of the same injector.
*/
T get ();
}
Copy package dh0023 . springcore . scope ;
import lombok . RequiredArgsConstructor ;
import org . assertj . core . api . Assertions ;
import org . junit . jupiter . api . Test ;
import org . springframework . beans . factory . ObjectProvider ;
import org . springframework . beans . factory . annotation . Autowired ;
import org . springframework . context . annotation . AnnotationConfigApplicationContext ;
import org . springframework . context . annotation . Scope ;
import javax . annotation . PostConstruct ;
import javax . annotation . PreDestroy ;
import javax . inject . Provider ;
import static org . assertj . core . api . Assertions . * ;
public class SingletonWithPrototypeTest {
@ Test
void singletonClientUseObjectProvider () {
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 {
private final PrototypeBean prototypeBean;
// ClientBean์ ์ฑ๊ธํค์ด๊ณ , ์ต์ด ์ฃผ์
์์๋ง PrototypeBean์ด ์์ฑ๋๋ค.
@ Autowired
public ClientBean ( PrototypeBean prototypeBean) {
this . prototypeBean = prototypeBean;
}
public int logic () {
prototypeBean . addCount ();
return prototypeBean . getCount ();
}
}
@ 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 {
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" );
}
}
}
prototypeBeanProvider.get()
์ ํตํด์ ํญ์ ์๋ก์ด ํ๋กํ ํ์
๋น์ด ์์ฑ๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.(DL) ์๋ฐ ํ์ค์ด๋ฉฐ, ๊ธฐ๋ฅ์ด ๋จ์ํ๋ฏ๋ก ๋จ์ํ
์คํธ๋ฅผ ๋ง๋ค๊ฑฐ๋ mock ์ฝ๋๋ฅผ ๋ง๋ค๊ธฐ๋ ํจ์ฌ ์ฌ์์ง๋ค.
ํ์ง๋ง, ๋ณ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ํ์ํ๋ฉฐ, ์๋ฐ ํ์ค์ด๋ฏ๋ก ์คํ๋ง์ด ์๋ ๋ค๋ฅธ ์ปจํ
์ด๋์์๋ ์ฌ์ฉํ ์ ์๋ค.
์น ์ค์ฝํ
์น ํ๊ฒฝ์์๋ง ๋์
์คํ๋ง ์ปจํ
์ด๋๊ฐ ํด๋น ์ค์ฝํ์ ์ข
๋ฃ์์ ๊น์ง ๊ด๋ฆฌํ๋ค. ( ์ข
๋ฃ๋ฉ์๋ ํธ์ถ๋จ )
์ข
๋ฅ
request: HTTP ์์ฒญ ํ๋๊ฐ ๋ค์ด์ค๊ณ ๋๊ฐ ๋๊น์ง ์ ์ง๋๋ ์ค์ฝํ
session: HTTP Session๊ณผ ๋์ผํ ์๋ช
์ฃผ๊ธฐ
application: ์๋ธ๋ฆฟ ์ปจํ
์คํธ(ServletContext
)์ ๋์ผ ์๋ช
์ฃผ๊ธฐ
websocket: ์น ์์ผ๊ณผ ๋์ผํ ์๋ช
์ฃผ๊ธฐ
request
Copy implementation 'org.springframework.boot:spring-boot-starter-web'
์นํ๊ฒฝ์ด ๋์ํ๋๋ก, ํด๋น ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฐ์ ์ถ๊ฐํด์ค๋ค.
request ์ค์ฝํ๋ ๋์์ ์ฌ๋ฌ HTTP ์์ฒญ์ด ์ค๋ฉด ์ ํํ ์ด๋ค ์์ฒญ์ด ๋จ๊ธด ๋ก๊ทธ์ธ์ง ๊ตฌ๋ถํ ๋ ์ฌ์ฉํ๊ธฐ ์ข๋ค.
Copy package dh0023 . springcore . common ;
import org . springframework . context . annotation . Scope ;
import org . springframework . stereotype . Component ;
import javax . annotation . PostConstruct ;
import javax . annotation . PreDestroy ;
import java . util . UUID ;
@ Component
@ Scope ( "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 );
}
}
@Scope("request")
์ด๋ฏ๋ก HTTP ์์ฒญ๋น ํ๋์ฉ ์์ฑ๋๋ฉฐ, HTTP ์์ฒญ์ด ๋๋๋ ์์ ์ ์๋ฉธ๋๋ค.
Copy package dh0023 . springcore . web ;
import dh0023 . springcore . common . MyLogger ;
import lombok . RequiredArgsConstructor ;
import org . springframework . beans . factory . ObjectProvider ;
import org . springframework . stereotype . Controller ;
import org . springframework . web . bind . annotation . RequestMapping ;
import org . springframework . web . bind . annotation . ResponseBody ;
import javax . servlet . http . HttpServletRequest ;
@ Controller
@ RequiredArgsConstructor
public class LogDemoController {
private final LogDemoService logDemoService;
private final ObjectProvider < MyLogger > myLoggerObjectProvider;
@ RequestMapping ( "log-demo" )
@ ResponseBody
public String logDemo ( HttpServletRequest request) {
String requestUrl = request . getRequestURL () . toString ();
MyLogger myLogger = myLoggerObjectProvider . getObject ();
myLogger . setRequestUrl (requestUrl);
myLogger . log ( "controller test" );
logDemoService . logic ( "testId" );
return "OK" ;
}
}
Copy package dh0023 . springcore . web ;
import dh0023 . springcore . common . MyLogger ;
import lombok . RequiredArgsConstructor ;
import org . springframework . beans . factory . ObjectProvider ;
import org . springframework . stereotype . Service ;
@ Service
@ RequiredArgsConstructor
public class LogDemoService {
private final ObjectProvider < MyLogger > myLoggerObjectProvider;
public void logic ( String id){
MyLogger myLogger = myLoggerObjectProvider . getObject ();
myLogger . log ( "logdemoservice: " + id);
}
}
Copy 44ebd516-6ce7-40ac-8838-1483bd875f17] request scope bean create: dh0023.springcore.common.MyLogger@3a354836
[ac6e0274-80da-4051-9f07-b61e01c6e261] request scope bean create: dh0023.springcore.common.MyLogger@4bb9ebc7
[ac6e0274-80da-4051-9f07-b61e01c6e261] [http://localhost:8080/log-demo] controller test
[44ebd516-6ce7-40ac-8838-1483bd875f17] [http://localhost:8080/log-demo] controller test
[5c0902a9-4401-4629-9bb1-f865d6bda02a] request scope bean create: dh0023.springcore.common.MyLogger@71f75886
[5c0902a9-4401-4629-9bb1-f865d6bda02a] [http://localhost:8080/log-demo] controller test
[4b601885-6795-42e6-a58e-f9ed92dbb819] request scope bean create: dh0023.springcore.common.MyLogger@58c3b813
[4b601885-6795-42e6-a58e-f9ed92dbb819] [http://localhost:8080/log-demo] controller test
[cf41f0c2-05f8-4922-818d-10294f5ea708] request scope bean create: dh0023.springcore.common.MyLogger@d34ed8
[cf41f0c2-05f8-4922-818d-10294f5ea708] [http://localhost:8080/log-demo] controller test
[44ebd516-6ce7-40ac-8838-1483bd875f17] [http://localhost:8080/log-demo] logdemoservice: testId
[ac6e0274-80da-4051-9f07-b61e01c6e261] [http://localhost:8080/log-demo] logdemoservice: testId
[ac6e0274-80da-4051-9f07-b61e01c6e261] request scope bean close: dh0023.springcore.common.MyLogger@4bb9ebc7
[44ebd516-6ce7-40ac-8838-1483bd875f17] request scope bean close: dh0023.springcore.common.MyLogger@3a354836
[5c0902a9-4401-4629-9bb1-f865d6bda02a] [http://localhost:8080/log-demo] logdemoservice: testId
[5c0902a9-4401-4629-9bb1-f865d6bda02a] request scope bean close: dh0023.springcore.common.MyLogger@71f75886
[4b601885-6795-42e6-a58e-f9ed92dbb819] [http://localhost:8080/log-demo] logdemoservice: testId
[4b601885-6795-42e6-a58e-f9ed92dbb819] request scope bean close: dh0023.springcore.common.MyLogger@58c3b813
[cf41f0c2-05f8-4922-818d-10294f5ea708] [http://localhost:8080/log-demo] logdemoservice: testId
[cf41f0c2-05f8-4922-818d-10294f5ea708] request scope bean close: dh0023.springcore.common.MyLogger@d34ed8
๊ฐ๊ฐ ์์ฒญ๋ณ๋ก log๊ฐ ๋จ๋๊ฒ์ ๋ณผ ์ ์๋ค.
ํ๋ก์
Copy package dh0023 . springcore . common ;
import org . springframework . context . annotation . Scope ;
import org . springframework . context . annotation . ScopedProxyMode ;
import org . springframework . stereotype . Component ;
import javax . annotation . PostConstruct ;
import javax . annotation . PreDestroy ;
import java . util . UUID ;
@ Component
@ Scope (value = "request" , proxyMode = ScopedProxyMode . TARGET_CLASS )
public class MyLogger {
}
proxyMode = ScopedProxyMode.TARGET_CLASS
์ถ๊ฐ๋ก ๊ฐ์ง ํ๋ก์ ํด๋์ค๋ฅผ ๋ง๋ค์ด๋๊ณ , HTTP request์ ์๊ด์์ด ๊ฐ์ง ํ๋ก์ ํด๋์ค๋ฅผ ๋ค๋ฅธ ๋น์ ๋ฏธ๋ฆฌ ์ฃผ์
ํด๋ ์ ์๋ค.
ScopedProxyMode
Copy package org . springframework . context . annotation ;
/**
* Enumerates the various scoped-proxy options.
*
* <p>For a more complete discussion of exactly what a scoped proxy is, see the
* section of the Spring reference documentation entitled '<em>Scoped beans as
* dependencies</em>'.
*
* @author Mark Fisher
* @since 2.5
* @see ScopeMetadata
*/
public enum ScopedProxyMode {
/**
* Default typically equals {@link #NO}, unless a different default
* has been configured at the component-scan instruction level.
*/
DEFAULT ,
/**
* Do not create a scoped proxy.
* <p>This proxy-mode is not typically useful when used with a
* non-singleton scoped instance, which should favor the use of the
* {@link #INTERFACES} or {@link #TARGET_CLASS} proxy-modes instead if it
* is to be used as a dependency.
*/
NO ,
/**
* Create a JDK dynamic proxy implementing <i>all</i> interfaces exposed by
* the class of the target object.
*/
INTERFACES ,
/**
* Create a class-based proxy (uses CGLIB).
*/
TARGET_CLASS
}
DEFAULT
: ์ปดํฌ๋ํธ ์ค์บ ๋ ๋ฒจ
NO
: ํ๋ก์๋ฅผ ์์ฑํ์ง ์๋๋ค.
INTERFACES
: ์ ์ฉ๋์์ด ์ธํฐํ์ด์ค์ธ ๊ฒฝ์ฐ
TARGET_CLASS
: ์ ์ฉ ๋์์ด ํด๋์ค์ธ ๊ฒฝ์ฐ
Copy package dh0023 . springcore . web ;
import dh0023 . springcore . common . MyLogger ;
import lombok . RequiredArgsConstructor ;
import org . springframework . stereotype . Controller ;
import org . springframework . web . bind . annotation . RequestMapping ;
import org . springframework . web . bind . annotation . ResponseBody ;
import javax . servlet . http . HttpServletRequest ;
@ Controller
@ RequiredArgsConstructor
public class LogDemoController {
private final LogDemoService logDemoService;
private final MyLogger myLogger;
@ RequestMapping ( "log-demo" )
@ ResponseBody
public String logDemo ( HttpServletRequest request) throws InterruptedException {
String requestUrl = request . getRequestURL () . toString ();
System . out . println ( "myLogger = " + myLogger . getClass ());
myLogger . setRequestUrl (requestUrl);
myLogger . log ( "controller test" );
logDemoService . logic ( "testId" );
return "OK" ;
}
}
Copy package dh0023 . springcore . web ;
import dh0023 . springcore . common . MyLogger ;
import lombok . RequiredArgsConstructor ;
import org . springframework . stereotype . Service ;
@ Service
@ RequiredArgsConstructor
public class LogDemoService {
private final MyLogger myLogger;
public void logic ( String id){
System . out . println ( "myLogger = " + myLogger . getClass ());
myLogger . log ( "logdemoservice: " + id);
}
}
http://localhost:8080/log-demo ์์ฒญ ๋ก๊ทธ ํ์ธ
Copy myLogger = class dh0023.springcore.common.MyLogger$$EnhancerBySpringCGLIB$$db714d07
[65e23cc1-382e-4f2d-9500-f18d1b894b9f] request scope bean create: dh0023.springcore.common.MyLogger@24da7142
[65e23cc1-382e-4f2d-9500-f18d1b894b9f] [http://localhost:8080/log-demo] controller test
myLogger = class dh0023.springcore.common.MyLogger$$EnhancerBySpringCGLIB$$db714d07
[65e23cc1-382e-4f2d-9500-f18d1b894b9f] [http://localhost:8080/log-demo] logdemoservice: testId
[65e23cc1-382e-4f2d-9500-f18d1b894b9f] request scope bean close: dh0023.springcore.common.MyLogger@24da7142
ํด๋์ค๋ฅผ ํ์ธํด๋ณด๋
์์ํ MyLogger ํด๋์ค๊ฐ ์๋๋ผ MyLogger$$EnhancerBySpringCGLIBโ
์ด๋ผ๋ ํด๋์ค๋ก ๋ง๋ค์ด์ง ๊ฐ์ฒด๊ฐ ๋์ ๋ฑ๋ก๋์๋ค.
๋ํ, ์คํ๋ง ์ปจํ
์ด๋์ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ๋ฑ๋กํ๋ฉฐ, ์์กด ๊ด๊ณ ์ฃผ์
๋ ํ๋ก์ ๊ฐ์ฒด๊ฐ ์ฃผ์
๋๋ค.
๋์ ์๋ฆฌ
CGLIB
๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ๋ด ํด๋์ค๋ฅผ ์์ ๋ฐ์ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด์ ์ฃผ์
ํ๋ก์ ๊ฐ์ฒด๋ ์ค์ ์์ฒญ์ด ๋ค์ด์ค๋ฉด ๋ด๋ถ์์ ์ค์ ๋น์ ์์ฒญํ๋ ์์ ๋ก์ง์ด ๋ค์ด์๋ค.
ํ๋ก์ ๊ฐ์ฒด๋ ์ค์ request scope์ ๊ด๊ณ ์์ผ๋ฉฐ, ๋ด๋ถ์ ๋จ์ํ ์์ ๋ก์ง๋ง ์๊ณ , ์ฑ๊ธํค์ฒ๋ผ ๋์ํ๋ค.
์ฆ, ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ ํด๋ผ์ด์ธํธ๋ ์ฑ๊ธํค ๋น์ ์ฌ์ฉํ๋ฏ์ด request scope๋ฅผ ์ฌ์ฉํ ์ ์๋ค. ์ด๋
ธํ
์ด์
์ค์ ๋ณ๊ฒฝ๋ง์ผ๋ก ์๋ณธ ๊ฐ์ฒด๋ฅผ ํ๋ก์ ๊ฐ์ฒด๋ก ๋์ฒดํ ์ ์์ผ๋ฉฐ, ์ด๋ ๋คํ์ฑ๊ณผ DI ์ปจํ
์ด๋๊ฐ ๊ฐ์ง ๊ฐ์ฅ ํฐ ๊ฐ์ ์ด๋ค.
ํ์ง๋ง, ์ฑ๊ธํค์ ์ฌ์ฉํ๋ ๊ฒ์ฒ๋ผ ๋๊ปด์ง์ง๋ง ์ฑ๊ธํค๊ณผ๋ ๋ค๋ฅด๊ฒ ๋์ํ๊ธฐ ๋๋ฌธ์ ์ฃผ์ํด์ ์ฌ์ฉํด์ผํ๋ค. ํน๋ณํ ๊ณณ์์๋ง ์ต์ํํด์ ์ฌ์ฉํด์ผํ๋ค. ๋ง์ฝ ๋ฌด๋ถ๋ณํ๊ฒ ์ฌ์ฉํ๊ฒ ๋๋ค๋ฉด ์ ์ง๋ณด์ ๋ฐ ํ
์คํธ๊ฐ ์ด๋ ค์์ง๋ค.
์ฐธ๊ณ