단점 : 다 분석하기 때문에 많이 쓰면 시간이 너무 오래 걸려 느리다.
→ 적재적소에 쓰는것이 중요함.
어노테이션을 사용하면 리플렉션을 효율적으로 사용가능 → 리플렉션을 사용할지 말지 결정 하기 때문에 효율적
예제
예제를 통해 리플렉션의 사용 전 후의 차이를 비교
코드를 이해하지말고 어떻게 작동하는지 작동 원리를 이해하자
ex01
생성
Java Class : App, UserController

App
package ex01;
public class App {
public static void main(String[] args) {
String path = "/login";
UserController con = new UserController();
if(path.equals("/login")){
con.login();
} else if (path.equals("/join")) {
con.join();
}
}
}
UserController
package ex01;
public class UserController {
// /login
public void login(){
System.out.println("로그인 호출됨");
}
// /join
public void join(){
System.out.println("회원가입 호출됨");
}
public void userinfo(){
System.out.println("유저정보 보기");
}
}
결과

App main에서 path값에 따라 UserController의 메서드 실행
UserController에 메서드를 하나 더 생성하면 App의 main 코드도 수정 하여야 한다. → ex02
ex02
생성
Java Class : App, UserController
Java Annotation : RequestMapping

App
package ex02;
import java.lang.reflect.Method;
public class App {
public static void main(String[] args) {
String path = "/updatepassword";
UserController con = new UserController();
Method[] methods = con.getClass().getDeclaredMethods();
// System.out.println(methods.length);
for(Method method : methods){
// System.out.println(method.getName());
RequestMapping rm = method.getDeclaredAnnotation(RequestMapping.class);
if(rm == null) continue;
if(rm.uri().equals(path)){
try {
method.invoke(con); // con.login()
break;
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
App의 코드를 수정 하지 않아도 됨(path는 원래 입력받는 값이라 App의 코드에 포함 x)
UserController
package ex02;
public class UserController {
// /login
@RequestMapping(uri = "/login")
public void login() {
System.out.println("로그인 호출됨");
}
// /join
@RequestMapping(uri = "/join")
public void join() {
System.out.println("회원가입 호출됨");
}
@RequestMapping(uri = "/userinfo")
public void userinfo() {
System.out.println("유저정보 보기");
}
@RequestMapping(uri = "/updatepassword")
public void updatePassword() {
System.out.println("패스워드 수정하기");
}
}
UserController에 원하는 메서드들을 추가가능
RequestMapping
package ex02;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequestMapping {
String uri();
}
RequestMapping 이라는 어노테이션을 만들어서 UserController에 있는 메서드들을 원하는 것만 분석하여 효율적으로 리플렉션 사용 가능.
하지만 위 코드는 컨트롤러가 늘어나면 해결이 불가능 → ex03
ex03
@Controller를 List에 저장 안전하게 하려면 Set(같은 타입 중복이 안됨)에다가 저장
생성
Java Class : App, UserController, BoardController
Java Annotation : RequestMapping, Controller

App
package ex03;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
public class App {
// RequestMapping 어노테이션이 붙어있는 것을 확인
public static void findUri(List<Object> instances, String path){
for (Object instance : instances){
Method[] methods = instance.getClass().getDeclaredMethods();
for(Method method : methods){
RequestMapping rm = method.getDeclaredAnnotation(RequestMapping.class);
if(rm == null) continue;
if(rm.uri().equals(path)){
try {
method.invoke(instance); // con.login();
break;
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
// Controller 어노테이션이 붙어있는거 확인
public static List<Object> componentScan(String pkg) throws URISyntaxException, ClassNotFoundException, InstantiationException, IllegalAccessException {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
URL packageUrl = classLoader.getResource(pkg);
File ex03 = new File(packageUrl.toURI());
List<Object> instances = new ArrayList<>();
for (File file : ex03.listFiles()){
//System.out.println(file.getName());
if(file.getName().endsWith(".class")){
String className = pkg + "." + file.getName().replace(".class", "");
//System.out.println(className);
Class cls = Class.forName(className);
if(cls.isAnnotationPresent(Controller.class)){
Object instance = cls.newInstance();
instances.add(instance); // UserController, BoardController
}
}
}
return instances;
}
public static void main(String[] args) throws URISyntaxException, ClassNotFoundException, InstantiationException, IllegalAccessException {
List<Object> instances = componentScan("ex03");
findUri(instances, "/write");
}
}
어노테이션이 있는지 확인하는 코드 생성(코드 생성할줄 몰라도 됨)
UserController
package ex03;
@Controller
public class UserController {
// /login
@RequestMapping(uri = "/login")
public void login() {
System.out.println("로그인 호출됨");
}
// /join
@RequestMapping(uri = "/join")
public void join() {
System.out.println("회원가입 호출됨");
}
@RequestMapping(uri = "/userinfo")
public void userinfo() {
System.out.println("유저정보 보기");
}
@RequestMapping(uri = "/updatepassword")
public void updatePassword() {
System.out.println("패스워드 수정하기");
}
}
BoardController
package ex03;
@Controller
public class BoardController {
@RequestMapping(uri = "/write")
public void write(){
System.out.println("글쓰기 호출됨");
}
}
두 종류 컨트롤러가 각각 있음
Controller
package ex03;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE) // 클래스 위에
public @interface Controller {
}
클래스를 찾아주는 어노테이션 → componentScan
RequestMapping
package ex03;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequestMapping {
String uri();
}
메서드를 찾아주는 어노테이션 → findUri
이렇게 하면 컨트롤러가 여러개여도 상관없음.
Main → Dispatcher → Controller → Dao → Database
Main은 Dispatcher 호출, Dispatcher는 Controller 호출….. Dao는 Database 호출 순으로 됨.
나누는 이유는 각각의 책임 분리를 위해 → SRP(단일 책임 원칙)
Share article