티스토리 뷰
@Service 에서 @Value 를 사용하여 properties에 있는 값을 가지고 와서 사용을 하려고 하는데 @Value 로 주입한 값이 다 null이 찍히는 현상이 발생했다.
@Controller 에서는 이런 경우가 있었지만, @Service 에서는 이런 일이 처음이어서 많이 당황스럽고 properties 마다 다른 값이 필요한 부분은 우선적으로 주석처리로 사용을 하기로 했다.
conteroller에서 왜 @Value 값을 사용하지 못했는지 궁금하다면?
https://yes-admit.tistory.com/44
스프링에 대한 개념이 잘 안잡혀있어서, 문제의 접근 방식을 찾기 어려웠는데 결론은 @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>
'백엔드 > spring' 카테고리의 다른 글
- Total
- Today
- Yesterday
- javascript
- 코딩테스트
- 스프링
- 현대
- 톰캣
- 자바
- springboot
- 리액트
- 오토에버코테
- 자바코테
- Linux
- centos
- java
- 전자정부프레임워크
- 자바스크립트
- 현대오토에버
- 쿠버네티스
- Kubernetes
- Spring
- mysql
- softeer
- react
- 코테
- tomcat
- 아파치카프카
- 현대코테
- 도커
- Docker
- java 코테
- softeer java
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |