5. ApplicationContext 변경
@Component 어노테이션이 붙은 클래스에 대해서도 객체를 생성하도록 ApplicationContext 클래스를 변경한다. spms.context.ApplicationContext 클래스를 다음과 같이 변경한다.
package spms.context;
import java.io.FileReader;
import java.lang.reflect.Method;
import java.util.Hashtable;
import java.util.Properties;
import java.util.Set;
import javax.naming.Context;
import javax.naming.InitialContext;
import org.reflections.Reflections;
import spms.annotation.Component;
//프로퍼티 파일을 이용한 객체 준비
public class ApplicationContext {
//객체 저장할 보관소
Hashtable<String,Object> objTable = new Hashtable<String,Object>();
//객체 꺼낼 메서드(getter)
public Object getBean(String key) {
return objTable.get(key);
}
//ApplicationContext 클래스의 생성자
public ApplicationContext(String propertiesPath) throws Exception {
//'이름=값'형태로 된 파일 다루는 Properties 클래스
Properties props = new Properties();
//load() : FileReader를 통해 읽어드린 프로퍼티 내용 키-값 형태로 내부 맵에 보관
props.load(new FileReader(propertiesPath));
prepareObjects(props);
prepareAnnotationObjects();
injectDependency();
}
//프로퍼티 파일의 내용 로딩 후 객체 준비 메서드
private void prepareObjects(Properties props) throws Exception {
//JNDI 객체 찾을 때 사용할 InitialContext 준비
Context ctx = new InitialContext();
String key = null;
String value = null;
for(Object item : props.keySet()) {
key = (String)item;
value = props.getProperty(key);
if(key.startsWith("jndi.")) {//keySet() : key목록 가져옴
//lookup() : JNDI 인터페이스 통해 톰캣 서버에 등록된 객체 찾음
objTable.put(key, ctx.lookup(value));
}else {
//Class.forName() 호출하여 클래스 로딩하고, newInstance() 사용하여 인스턴스 생성
objTable.put(key, Class.forName(value).newInstance());
}
}
}
//어노테이션이 붙은 클래스를 찾아 객체 준비 메서드
private void prepareAnnotationObjects() throws Exception {
//Reflections 클래스 : 원하는 클래스를 찾아주는 도구
Reflections reflector = new Reflections("");
//@Component 어노테이션 선언된 클래스 찾아 클래스 목록 반환
Set<Class<?>> list = reflector.getTypesAnnotatedWith(Component.class);
String key = null;
for(Class<?> clazz : list) {
//어노테이션에 정의된 메서드 호출하여 속성값 꺼냄
key = clazz.getAnnotation(Component.class).value();
//어노테이션을 통해 알아낸 객체 이름(key)으로 인스턴스 저장
objTable.put(key, clazz.newInstance());
}
}
...
}
이전 소스와 달라진 점은 prepareAnnotationObjects() 메서드를 추가한 부분이다. 프로퍼티 파일에 등록된 대로 객체를 준비하는 것은 예전처럼 그대로 진행한다. 여기에다가 어노테이션이 붙은 클래스를 찾아서 객체를 준비하는 것이 추가되었다. prepareAnnotationObjects() 메서드가 바로 그 일을 수행한다.
prepareObjects(props);
prepareAnnotationObjects();
- prepareAnnotationObjects() 메서드
이 메서드는 자바 classpath를 뒤져서 @Component 어노테이션이 붙은 클래스를 찾는다. 그리고 그 객체를 생성하여 객체 테이블에 담는 일을 한다. 이 작업을 위해 'Reflections'라는 오픈소스 라이브러리를 활용하였다.
Reflections 클래스는 구글 코드 사이트(https://code.google.com/archive/p/reflections/)에 등록된 오픈 소스 프로젝트이다. 현재 이 프로젝트의 소스는 GitHub 사이트(https://github.com/ronmamo/reflections)로 옮겨졌다. 이 라이브러리에서 제공하는 클래스를 사용하면, 자바에서 제공하는 리플랙션 API를 사용하는 것보다 더 쉽게 클래스를 찾거나 클래스의 정보를 추출할 수 있다.
//Reflections 클래스 : 원하는 클래스를 찾아주는 도구
Reflections reflector = new Reflections("");
Reflections 클래스는 우리가 원하는 클래스를 찾아 주는 도구이다. 생성자에 넘겨주는 매개변수 값은 클래스를 찾을 때 출발하는 패키지이다. 만약 매개변수 값이 'spms'라면 spms 패키지 및 그 하위 패키지를 모두 뒤진다. 매개변수 값이 'spms.controls'라면, spms.controls 패키지와 그 하위 패키지를 모두 뒤진다. 예제에서는 빈 문자열을 넘겼다. 즉 자바 classpath에 있는 모든 패키지를 검색하라는 뜻이다.
Reflections 클래스의 getTypesAnnotatedWith() 메서드를 사용하면 어노테이션이 붙은 클래스들을 찾을 수 있다. 이 메서드의 매개변수 값은 어노테이션의 클래스(java.lang.Class 객체)이다.
//@Component 어노테이션 선언된 클래스 찾아 클래스 목록 반환
Set<Class<?>> list = reflector.getTypesAnnotatedWith(Component.class);
@Component 어노테이션이 붙은 클래스를 찾고 싶으면 앞의 코드처럼 어노테이션 클래스를 지정하면 된다. 반환되는 값은 @Component 어노테이션이 선언된 클래스 목록이다.
for(Class<?> clazz : list) {
...
}
getAnnotation() 메서드를 통해 클래스로부터 어노테이션을 추출한다. 어노테이션에 정의된 메서드를 호출하여 속성값을 꺼낼 수 있다. @Component의 기본 속성값을 꺼내고 싶으면, 다음과 같이 value()를 호출한다.
//어노테이션에 정의된 메서드 호출하여 속성값 꺼냄
key = clazz.getAnnotation(Component.class).value();
이렇게 어노테이션을 통해 알아낸 객체 이름(key)으로 인스턴스를 저장한다.
//어노테이션을 통해 알아낸 객체 이름(key)으로 인스턴스 저장
objTable.put(key, clazz.newInstance());
6. Reflections 라이브러리 준비
이제 실행을 위해 마지막으로 Reflections 라이브러리를 준비한다. 다음 지시에 따라 라이브러리를 다운로드 받고 배치한다. 웹 브라우저에서 https://code.google.com/archive/p/reflections/에 접속하여 메인 화면에서 'Downloads' 링크를 클릭한다(그림 1).
다운로드 화면에서 'reflections-0.9.9-RC1-uberjar.jar' 링크를 클릭한다. 이 JAR 파일에는 Reflections 라이브러리와 의존 라이브러리들이 들어있다. 또한 'reflections-0.9.9-RC1.jar' 링크를 클릭한다. 이 JAR 파일은 Reflections 라이브러리 파일이다(그림 2).
reflections-0.9.9-RC1.jar 파일을 WEB-INF/lib 폴더에 복사한다. reflections-0.9.9-RC1-uberjar.jar 파일의 압축을 해제한다. 압축 해제된 파일들 중에서 JAR 파일을 WEB-INF/lib 폴더에 복사한다. 다음 그림은 WEB/lib 폴더의 내용이다.
톰캣 서버를 재시작하여 동작을 테스트한다. 정상적으로 잘 동작한다. 이렇게 어노테이션을 이용하면 프로퍼티 파일을 이용하는 것보다 객체 관리가 더 쉽다. 또한, 소스 파일에 객체에 대한 부가 정보를 붙이기 때문에 유지 보수가 편해진다.
참고도서 : https://freelec.co.kr/book/1674/
[열혈강의] 자바 웹 개발 워크북
[열혈강의] 자바 웹 개발 워크북
freelec.co.kr
'교재 실습 > 자바 웹 개발 워크북' 카테고리의 다른 글
96. 실력 향상 훈련 (2) (0) | 2022.08.20 |
---|---|
95. 실력 향상 훈련 (1) (0) | 2022.08.16 |
93. 어노테이션을 이용한 객체 관리 (2) (0) | 2022.08.14 |
92. 어노테이션을 이용한 객체 관리 (1) (0) | 2022.08.13 |
91. 프로퍼티를 이용한 객체 관리 (3) (1) | 2022.08.11 |
댓글