Spring 시리즈는 혼자 공부하며 기록으로 남기고, 만약 잘못 학습 한 지식이 있다면 공유하며 피드백을 받고자 작성합니다.
스프링에 대해 깊게 공부해보고자 인프런의 김영한 강사님께서 강의를 진행하시는 (스프링 핵심 원리 - 기본편) 강의를 수강하며 정리하는 글입니다.
혹여나 글을 읽으시며 잘못 설명된 부분이 있다면 지적 부탁드리겠습니다.
하위 3개는 웹기술 공부하다보면 자연스레 이해가 간다고 하시는데.. 커리큘럼 다음강의(모든 개발자를 위한 HTTP 웹 기본 지식) 이거 들어보면 나오지 않을까.. 싶다

build.gradle 추가 필요
//web 라이브러리 추가
implementation 'org.springframework.boot:spring-boot-starter-web'
CoreApplication을 실행 시켜보자.Tomcat started on port(s) : 8080 ~~~~
라는게 뜨면 정상적으로 잘 동작한 것이다. http://localhost.com:8080 으로 들어가면 오류페이지가 나온다면 정상이다.
참고: 스프링은 내장톰캣 서버를 사용해서 웹 서비스와 스프링을 함께 실행시키는 것이다. 외장 톰캣을 사용하면 java 설치, war파일 빌드 다 따로따로 해야한다.
참고: 스프링 부트는 웹 라이브러리를 추가하면 웹과 관련된 추가 설정과 환경들이 필요하므로
AnnotationConfigServletWebServcerApplicationContext를 기반으로 애플리케이션을 구동한다.
이름 짱기네;;
Rquest Scope!아래와 같이 로그가 남도록 개발을 해보자
[uuid][url] 서비스명
[srf41232...] request scope bean create
[srf41232...][http://localhost:8080/log-demo] controller test
[srf41232...][http://localhost:8080/log-demo] service id = testId
[srf41232...] request scope bean close
MyLogger 코드
@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);
}
}
LogDemoContoller 코드
@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("test Id");
return "OK";
}
}
@ResponseBody 애노테이션은 문자 그대로 응답을 보낼 수 있다.HttpServletRequest : http-request 정보를 받을 수 있다.LogDemoService 코드
@Service
@RequiredArgsConstructor
public class LogDemoService {
private final MyLogger myLogger;
public void logic(String id) {
myLogger.log("service id = " + id);
}
}
Error creating bean with name 'myLogger': Scope 'request' is not active for the
current thread;
라는 오류가 나온다면? 정상이다.
myLogger는 Reqeust Scope라서 HTTP 요청이 들어와야 생성이 되는데 이미 있지도 않은걸 주입하려고하니 오류가 나는것이다.Provider 쓰면 해결이 바로된다@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();
}
...
}
@Service
@RequiredArgsConstructor
public class LogDemoService {
private final ObjectProvider<MyLogger> myLoggerProvider;
...
}
ObjectProvider를 사용하여 .getObject() 메서드를 호출하는 시점까지 MyLogger 즉 Request 빈의 생성을 지연할 수 있다.실행 결과
[c83056c5...] request scope bean create : hello.core.common.MyLogger@5035f3bb
[c83056c5...][http://localhost:8080/log-demo] [controller test]
[c83056c5...][http://localhost:8080/log-demo] [service id = test Id]
[c83056c5...] request scope bean close : hello.core.common.MyLogger@5035f3bb
@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyLogger {}
proxyMode = ScopedProxyMode.TARGET_CLASS 를 적용해주면 된다.TARGET_CLASS 선택INTERFACES 선택Provider를 적용했을때의 결과랑 완전히 같은걸 볼 수 있다.myLogger에 뭐가 들어와있나 출력을 찍어보자myLogger = class hello.core.common.MyLogger$$SpringCGLIB$$0
CGLIB 라이브러리로 기존 클래스를 상속 받은 가짜 프록시 객체를 만들어서 주입한다
myLogger 라는 이름으로 진짜 대신에 이 가짜 프록시 객체가 등록된다.ac.getBean("myLogger", MyLogger.class)로 조회해도 가짜 프록시 객체가 조회된다.프록시 동작 구조 그림

myLogger를 찾는 방법을 알고있다.logic() 메서드를 호출하면 프록시 객체의 메서드를 호출한 것이다.