MVC - Auto Annotation

jinkyung·2021년 1월 25일
0

JSP

목록 보기
19/20

새로운 dao나 controller생성시마다 properties 파일에 계속 추가 하지 않고 쉽게 관리할 수 있는 방법이 바로 Annotation을 이용하는 것이다.


@Component annotation
: controller의 객체를 만들면서 dispatcher컨트롤러에 주소를 전달

applicaton-context.properties
: 객체를 생성하는 것은 annotation으로 만들 것이기 때문에 주석처리


annotation 클래스 추가
객체 이름을 저장하는 변수 value

package spms.annotation;


import java.lang.annotation.*;

// 클래스 파일에 이 정보가 기록되고 실행시에도 유지된다. 
// 즉, 실행시에 클래스에 기록된 annotation 값을 참조할 수 있다 
//runtime = 실행시 component의 정보가 기록된다 
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
	String value() default "";
}

Controller마다 annotation 추가

Reflections("") : classpath 하위를 모두 찾는다
classpath : src파일 하위에 있는 모든 것

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;

/* application-context.properties 파일을 읽어서
 * 파일에 등록된 객체를 생성하는 역할
 * */
public class ApplicationContext {
	// url : 대응 객체
	Hashtable<String, Object> objTable = 
			new Hashtable<String, Object>();
	
	public Object getBean(String key) {
		return objTable.get(key);
	}
	
	public ApplicationContext(String propertiesPath) 
							throws Exception{
		// 프로퍼티 파일 목록 읽어오기
		Properties props = new Properties();
		props.load(new FileReader(propertiesPath));
		
		prepareObjects(props);		// 객체 생성
		prepareAnnotationObjects();	// 애노테이션 포함 클래스 객체 생성
		injectDependency();			// memberDao 주입
	}
	
	private void prepareObjects(Properties props) throws Exception{
		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.")) {
				// tomcat의 DataSource객체를 찾아서 저장
				objTable.put(key, ctx.lookup(value));
			}else {
				// 나머지 클래스들은 직접 객체를 생성한다
				objTable.put(key, Class.forName(value).newInstance());
			}
		}
	}
	
	private void prepareAnnotationObjects() throws Exception{
		/* Reflections(패키지) : 해당 패키지 하위를 모두 찾는다
		 * Reflections("spms") : spms 하위를 모두 찾는다
		 * Reflections("spms.controls") : spms.controls 하위를 모두 찾는다
		 * Reflections("") : classpath 하위를 모두 찾는다
		 * */
		Reflections reflector = new Reflections("");
		
		// @Component 애노테이션을 가진 type만 추출함
		// component가 등록된 클래스를 가져온다 
		Set<Class<?>> list = 
				reflector.getTypesAnnotatedWith(Component.class);
		String key = null;
		for(Class<?> clazz : list) {
			// ex) value = "/auth/login.do"
			key = clazz.getAnnotation(Component.class).value();
			// key, key의 클래스 객체를 등록 
			objTable.put(key, clazz.newInstance());
		}
	}
	
	private void injectDependency() throws Exception{
		for(String key : objTable.keySet()) {
			if(!key.startsWith("jndi.")) {
				callSetter(objTable.get(key));
			}
		}
	}
	
	private void callSetter(Object obj) throws Exception{
		Object dependency = null;
		for(Method m : obj.getClass().getMethods()) {
			// 메서드 중에 Setter를 찾아라
			/* Dao객체는 set으로 시작하는 메서드가 없으므로
			     주입 대상이 되지 않는다 */
			/* pageController객체만 Setter가 있다 */
			if(m.getName().startsWith("set")) {
				/* 현재 objTable로부터 첫번째 매개변수에 해당하는
				 * 클래스 객체를 찾아라 => 즉 Dao객체를 찾아라
				 * */
				/* dependency == MemberDao객체 */ 
				dependency = findObjectByType(m.getParameterTypes()[0]);
				if(dependency != null) {
					m.invoke(obj, dependency);
				}
			}
		}
	}
	
	private Object findObjectByType(Class<?> type) {
		for(Object obj : objTable.values()) {
//			type으로 obj가 생성된 것이라면
			if(type.isInstance(obj))
				return obj;
		}
		return null;
	}
}

ContextLoaderListener

...
public class ContextLoaderListener implements ServletContextListener {
	
	//외부에서 바로 가져다 쓸 수 있도록 static (편의성)
	static ApplicationContext applicationContext;
	
	public static ApplicationContext getApplicationContext() {
		return applicationContext;
	}

	@Override
	public void contextDestroyed(ServletContextEvent sce) {
		try {
			System.out.println("contextDestroyed");
			// 우리가 DataSource 객체를 해제하지 않아도
			// tomcat 서버가 알아서 해제한다
		}catch(Exception e) {
			e.printStackTrace();
		}		

	}

	@Override
	public void contextInitialized(ServletContextEvent sce) {
		try {
			System.out.println("contextInitialized");
			ServletContext sc = sce.getServletContext();

			String propertiesPath = sc.getRealPath(
					sc.getInitParameter("contextConfigLocation"));

			applicationContext = new ApplicationContext(propertiesPath);
		}catch(Exception e) {
			e.printStackTrace();
		}
	}

이제 properties가 없어도 annotation을 이용하여 DI(memberDao 주입) 가능.

0개의 댓글