티스토리 뷰

728x90

 

@Service 에서 @Value 를 사용하여 properties에 있는 값을 가지고 와서 사용을 하려고 하는데 @Value 로 주입한 값이 다 null이 찍히는 현상이 발생했다.

@Controller 에서는 이런 경우가 있었지만, @Service 에서는 이런 일이 처음이어서 많이 당황스럽고 properties 마다 다른 값이 필요한 부분은 우선적으로 주석처리로 사용을 하기로 했다.

conteroller에서 왜 @Value 값을 사용하지 못했는지 궁금하다면?

https://yes-admit.tistory.com/44

 

controller에서 @value 사용하기

컨트롤러에서 @Value 어노테이션을 사용하여 properties에 작성한 값을 가지고 오려고 했는데 값을 가져오지 못했다. service에서는 사용이 되는데 컨트롤러에서는 안되서 검색해보니 아래와 같은 설

yes-admit.tistory.com

스프링에 대한 개념이 잘 안잡혀있어서, 문제의 접근 방식을 찾기 어려웠는데 결론은 @Service 에서 안되는 것이 아니었다.

@Value 어노테이션은 Spring 프레임워크에서 프로퍼티 값을 주입받기 위해 사용되는 것이며, 주로 Spring의 IoC 컨테이너에 의해 관리되는 빈(Bean) 클래스 내부에서 사용된다.  따라서 @Value 어노테이션은 Spring의 빈 라이프사이클과 관련이 있다.

 

그럼 나의 경우에는 왜 안되었을까? 

문제가 되었던건 @Service 에 있는 method의 호출 방식이다.

 

우리가 일반적으로 스프링 개발을 할 때 보통 bean 에 등록되어 있는 service를 생성자주입방식이나, 자동주입방식등을 이용해서 사용을 한다. 이런 경우에는 당연히 Ioc에 등록되어있는 bean을 사용하는것임으로 아무런 문제가 없다.

 

아래의 예시는 전혀 문제 없이 application.properties에 설정한 test.path 가 출력된다.

[Controller]

@Slf4j
@RestController
@RequiredArgsConstructor
public class TestController {
 	private final TestService testService;
   
    @RequestMapping("test")
    public void test() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
		testService.test();
       
    }
  }

[Service]

@Slf4j
public class TestService {
	@Value("${test.path}")
    private String testPath;

    public void test() {
        log.info("testPath :: {}", testPath);
    }
}

[application-context.xml]

application-context.xml을 통해 bean 등록 -> WebApplicationContext로 DispatcherServlet클래스에 의해 만들어진다.

 <bean id="testService" class="service.TestService"/>

 

그러나 이번의 나의 상황은 조금 달랐다. bean을 가져오는 방식이 달랐는데, 아래 처럼ContextLoader.getCurrentWebApplicationContext().getBean 를 사용하여 bean을 가지고 와서 test 메소드를 호출했다.

이런 경우에는 @Value 로 주입한 값들이 null 이 되었다.

 

[Controller]

    
    @RequestMapping("test")
    public void test() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Object targetService = ContextLoader.getCurrentWebApplicationContext().getBean("testService");
        Method targetMethod = targetService.getClass().getMethod("test", new Class[] {});
        targetMethod.invoke(targetService);
    }

Spring IoC 컨테이너는 빈의 라이프사이클을 관리하고, 의존성 주입(Dependency Injection) 및 다양한 빈의 초기화, 소멸 등을 관리하는데 ContextLoader.getCurrentWebApplicationContext().getBean(...) 을 사용하여 직접 빈을 가져올 때는 Spring의 IoC 컨테이너에 있는 bean을 사용하는것이 아니다.

  이런 방식으로 가져온 빈은 Spring의 빈 라이프사이클과 연결되지 않는다. 즉, @Value 어노테이션으로 주입된 값들은 이렇게 직접 빈을 가져온 상황에서는 적용되지 않는다.

 

만약 ContextLoader.getCurrentWebApplicationContext().getBean(...) 을 사용했을 때 @Value의 역할 처럼 값을 주입하는것이 필요하다면, 아래와 같이 setter를 사용하여 값을 주입해주면 된다.

 

[service]

@Slf4j
public class TestService {
	private String testPath;
  	public void setTestPath(String testPath) {
        this.testPath = testPath;
    }
 }

[application-context.xml]

    <bean id="testService" class="service.TestService">
        <property name="testPath" value="${properties에 적은 key 값을 적어줍니다}"/>
    </bean>

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함