인프런 커뮤니티 질문&답변

멍토님의 프로필 이미지
멍토

작성한 질문수

스프링 핵심 원리 - 기본편

request 스코프 관련 문의

작성

·

96

0

안녕하세요, 몇가지 질문이 있습니다.

  1. 선생님의 코드대로 쳤는데 제 인텔리제이에서는 왜 다음과 같은 에러가 발생하는지 모르겠습니다.

스크린샷 2024-06-12 오후 3.13.34.png왜 LogDemoController가 static 컨텍스트라고 떠서 이런 에러가 발생하는지 모르겠습니다.

제가 봤을땐 static이 아닌데 말이죠 (MyLogger, Controller, Service 모두 static은 없음)

여기까지의 소스 코드를 1차 첨부합니다. (에러 발생 코드)

package hello.core.common;

import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import java.util.UUID;

@Component
@Scope(value="request")
public class MyLogger {

    private String uuid; // unique id
    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 + "] " + "[" + requestURL + "] request scope bean create : " + this);
    }

    @PreDestroy
    public void close(){
        System.out.println("[" + uuid + "] " + "[" + requestURL + "] request scope bean close : " + this);
    }

    /*
    로그를 출력하기 위한 클래스
    request 스코프로 지정했으며, HTTP 요청당 하나씩 생성되고, HTTP 요청이 끝나는 시점에 소멸된다.
    이 빈이 생성되는 시점에 자동으로 @PostConstruct 초기화 메서드를 사용해서 uuid를 생성해서 저장해둔다.
    이 빈은 HTTP 요청 당 하나씩 생성되므로, uuid를 저장해두면 다른 HTTP 요청과 구분할 수 있다.
    requestURL은 빈이 생성되는 시점에는 알 수 없으므로 외부에서 setter로 입력받는다.
     */

}
package hello.core.web;

import hello.core.common.MyLogger;
import jakarta.servlet.http.HttpServletRequest;
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;

@Controller
@RequiredArgsConstructor
public class LogDemoController {
    private final LogDemoService logDemoService;
    private final ObjectProvider<MyLogger> myLoggerProvider; // 스프링 컨테이너가 뜨면서 의존관계 주입을 해야하는데 mylogger는 request scope이라 아직 고객 요청이 없어서 에러

    @RequestMapping("log-demo")
    @ResponseBody
    public String logDemo(HttpServletRequest request){
        String requestURL = request.getRequestURL().toString(); // 고객이 요청한 url을 받을 수 있음
        MyLogger myLogger = myLoggerProvider.getObject(); // 주입 시점에 주입 받을 수 있음
        myLogger.setRequestURL(requestURL);
        myLogger.log("controller test");
        LogDemoService.logic("testId");
        return "OK";
    }

}
package hello.core.web;
import hello.core.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> myLoggerProvider;

    public void logic(String id) {

        MyLogger myLogger = myLoggerProvider.getObject();
        myLogger.log("service id = " + id);
    }
}
  1. 어쨋든 이 문제를 해결하지 않으면 소스 코드 실행이 되지 않습니다. 따라서 intelliJ 가이드에 따라 static으로 만들어주고 실행을 하면 또 에러가 발생합니다.

private final ObjectProvider<MyLogger> myLoggerProvider;

위 구문 초기화를 하라는 가이드에 = Null을 해주면

소스 코드 실행 시 (디버깅 결과) myLoggerProvider.getObject() 에서 널포인트 익셉션이 터집니다.

여기까지 상황의 코드를 2차 첨부합니다.

package hello.core.web;

import hello.core.common.MyLogger;
import jakarta.servlet.http.HttpServletRequest;
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;

@Controller
@RequiredArgsConstructor
public class LogDemoController {
    private final LogDemoService logDemoService;
    private final ObjectProvider<MyLogger> myLoggerProvider; // 스프링 컨테이너가 뜨면서 의존관계 주입을 해야하는데 mylogger는 request scope이라 아직 고객 요청이 없어서 에러

    @RequestMapping("log-demo")
    @ResponseBody
    public String logDemo(HttpServletRequest request){
        String requestURL = request.getRequestURL().toString(); // 고객이 요청한 url을 받을 수 있음
        MyLogger myLogger = myLoggerProvider.getObject(); // 주입 시점에 주입 받을 수 있음
        myLogger.setRequestURL(requestURL);
        myLogger.log("controller test");
        LogDemoService.logic("testId");
        return "OK";
    }

}
package hello.core.web;
import hello.core.common.MyLogger;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class LogDemoService {

    private static final ObjectProvider<MyLogger> myLoggerProvider = null;

    public static void logic(String id) {

        MyLogger myLogger = myLoggerProvider.getObject();
        myLogger.log("service id = " + id);
    }
}

 

어떻게 해결해야할까요? 제가 잘못 타이핑한 부분이 있다면 말씀 부탁드립니다.

 

 

답변 1

1

안녕하세요. 멍토님, 공식 서포터즈 y2gcoder입니다.

일단 먼저 1번 상태에서 사진을 보시면 LogDemoController의 멤버 변수인 LogDemoService logDemoService 가 사용되지 않아 회색인 것을 보실 수 있습니다!

package hello.core.web;

import hello.core.common.MyLogger;
import jakarta.servlet.http.HttpServletRequest;
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;

@Controller
@RequiredArgsConstructor
public class LogDemoController {
    private final LogDemoService logDemoService;
    private final ObjectProvider<MyLogger> myLoggerProvider; // 스프링 컨테이너가 뜨면서 의존관계 주입을 해야하는데 mylogger는 request scope이라 아직 고객 요청이 없어서 에러

    @RequestMapping("log-demo")
    @ResponseBody
    public String logDemo(HttpServletRequest request){
        String requestURL = request.getRequestURL().toString(); // 고객이 요청한 url을 받을 수 있음
        MyLogger myLogger = myLoggerProvider.getObject(); // 주입 시점에 주입 받을 수 있음
        myLogger.setRequestURL(requestURL);
        myLogger.log("controller test");
        LogDemoService.logic("testId");    // 이 부분이 문제입니다!!
        return "OK";
    }

}

그걸 토대로 LogDemoController를 살펴보시면

LogDemoService.logic("testId");    // 이 부분이 문제입니다!!

이 부분에서 logDemoService.logic("testId") 로 부르지 않고 LogDemoService.logic("testId")로 부르고 있기 때문에 컴파일러는 너 왜 정적 메서드를 부르고 있냐? 이렇게 에러를 뱉어주고 있는 것으로 보입니다.

logDemoService.logic("testId")로 고치고 나서 다시 한 번 시도해보시겠습니까?

 

 

감사합니다.

멍토님의 프로필 이미지
멍토
질문자

와 진짜 감사합니다!!! 부족한게 많은데 많이 배워갑니다😀

멍토님의 프로필 이미지
멍토

작성한 질문수

질문하기