inblog logo
|
vosw1
    Spring

    Reflection

    Jan 23, 2024
    Reflection

    Reflection

    : 실행 중에 자기 자신의 구조를 검사하고 조작할 수 있는 능력
     
    예시) 내가 무슨 메서드를 만들지 라이브러리를 만드는 사람은 알 수 없으나
    내가 메서드를 만들면 동작시킬 수 있음
    notion image
    정원사가 나무를 관리함
    나무는 정상적인 나무도 있고,
    썩어서 보수를 해줘야 하는 나무도 있음
    리플렉션은 모든 나무를 하나하나 관리
    그래서 리플렉션을 통한 접근은 느림
    장점 : 구체적인 클래스를 알지 못해도 동적으로 클래스를 만들어 의존 관계를 만들 수 있음.
    단점 : 분석을 많이 해서 속도가 느림 / 기존 프로그램이 더 빠름
    private 데이터도 접근 가능해 캡슐화 어려움
    런타임 단계에서 에러가 발생하기 때문에 디버깅 어려움
    미리 코딩할 수 없음
     
    notion image
    리플렉션을 효율적으로 사용하기 위해 어노테이션(Annotation)을 사용한다. 어노테이션은 깃발을 꽂는다고 생각하면 된다. 내가 관리를 원하는 메서드에 깃발을 꽂으면 그 메서드만 조작할 수 있다.
     
    변할 때 서로의 개발자가 다를 때) 늘릴 때 마다 커뮤니케이션 해야 함
     
    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.login(); } } }
    notion image
    notion image
    notion image
     
    검사하는게 리플렉션
    어노테이션은 검사를 효율적으로 하게 만들어줌
     
    package ex02; import java.lang.reflect.Method; public class App { public static void main(String[] args) { String path = "/login"; UserController con = new UserController(); Method[] methods = con.getClass().getDeclaredMethods(); System.out.println(methods.length); for(Method method : methods){ System.out.println(method.getName()); } } }
    package ex02; public class UserController { public void login(){ System.out.println("로그인 호출됨"); } public void join(){ System.out.println("회원가입 호출됨"); } public void userinfo(){ System.out.println("유저정보 보기"); } }
    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 { // 어노테이션 // 인터페이스앞에 @interface annotation이다 // 발동시점을 정해야함 힌트를 컴파일시점에서 보고 작동함 // 깃발을 꽂음 String uri(); }
    notion image
     
    리플렉션으로 Annotation을 분석하는 것
    package ex02; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class App { public static void main(String[] args) { String path = "/login"; 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)) {// = con.login(); 과 같은 것 try { method.invoke(con); break; } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (Exception e) { e.printStackTrace(); } } } } }
    도메인마다 컨트롤러를 만듦
     
    메서드화
    package ex03; import java.lang.reflect.Method; public class App { public static void findUri(UserController con, String path){ Method[] methods = con.getClass().getDeclaredMethods(); for (Method method : methods) { RequestMapping rm = method.getDeclaredAnnotation(RequestMapping.class); if (rm == null) continue; if (rm.uri().equals(path)) { try { method.invoke(con); break; } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (Exception e) { e.printStackTrace(); } } } } public static void main(String[] args) { String path = "/update-Password"; findUri(new UserController(), "/login"); UserController con = new UserController(); } }
    notion image
    모든 컨트롤러에 있는 어노테이션 분석을 위해
    패키지를 리플렉션해서 컨트롤러를 다 찾아낼 것임
     
    컨포넌트 스캔 : 패키지를 분석해서 찾아서 메모리에 띄울 것을 뉴해서 set 자료형에 담음 → 중복 안됨/ 싱글톤에 담음
    절대 중복될 수 없음
     
    classLoader를 통해서 메인의 자바에 접근 할 수 있음
    실제 접근하는 것 classis니까 java로 생각해도 됨
    찾아서 그 안에 있는 것들 중에 ex03이라는 패키지의 위치를 찾음
    ex03을 파일 객체로 읽음 → 자바 객체로 들어와있음 /폴더같은 것
    ex03이 가지고 있는 모든 파일들만큼 for문이 돌아감
    폴더도 파일로 봄
     
    자기 경로에 있는 것만 보기에 그 폴더 안에 있는 파일까지 보지 않음
     
    있으면 set 자료형에 담음
    폴더만 다시 리스트 파일즈 해서 들어가서 다시 있는지 확인해서 있으면 set 자료형에 담음
     
    package ex03; import java.io.File; import java.lang.reflect.Method; import java.net.URISyntaxException; import java.net.URL; public class App { public static void findUri(UserController con, String path) { Method[] methods = con.getClass().getDeclaredMethods(); for (Method method : methods) { RequestMapping rm = method.getDeclaredAnnotation(RequestMapping.class); if (rm == null) continue; if (rm.uri().equals(path)) { try { method.invoke(con); break; } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (Exception e) { e.printStackTrace(); } } } } public static void main(String[] args) throws URISyntaxException { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // 패키지 분석 URL packasgeUrl = classLoader.getResource("ex03"); // 패키지 분석 File ex03 = new File(packasgeUrl.toURI()); for(File file : ex03.listFiles()){ // ex03이 가지고 있는 모든 파일들만큼 for문이 돌아감 System.out.println(file.getName()); } //findUri(new UserController(), "/login"); } }
    notion image
    package ex03; import java.io.File; import java.lang.reflect.Method; import java.net.URISyntaxException; import java.net.URL; import java.util.HashSet; import java.util.Set; public class App { public static void findUri(UserController con, String path) { Method[] methods = con.getClass().getDeclaredMethods(); for (Method method : methods) { RequestMapping rm = method.getDeclaredAnnotation(RequestMapping.class); if (rm == null) continue; if (rm.uri().equals(path)) { try { method.invoke(con); break; } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (Exception e) { e.printStackTrace(); } } } } public static void main(String[] args) throws URISyntaxException { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // 패키지 분석 URL packasgeUrl = classLoader.getResource("ex03"); // 패키지 분석 File ex03 = new File(packasgeUrl.toURI()); Set<Object> instances = new HashSet<>(); for(File file : ex03.listFiles()){ // ex03이 가지고 있는 모든 파일들만큼 for문이 돌아감 //System.out.println(file.getName()); if (file.getName().endsWith(".class")){ String className = "ex03" + "." + file.getName().replace(".class", ""); System.out.println(className); } } //findUri(new UserController(), "/login"); } }
    notion image
     
    문자열로도 뉴할 수 있음→ 리플렉션에 필요함
    package ex04; public class Dog { public String name = "강아지"; public Dog() { System.out.println("강아지 객체 만들어짐"); } }
    package ex04; public class DogApp { public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException { String className = "ex04.Dog"; Class cls = Class.forName(className); Object ob = cls.newInstance(); Dog d = (Dog) ob; System.out.println(d.name); } }
    notion image
    어떤 클래스를 만들지 모를 때 이렇게 뉴 해야함
    그럴 때 리플렉션으로 클래스 이름을 분석해서 뉴할 것
    이것을 set자료형에 담을 것
     
    ex03" + "." + file.getName() // 뉴하기 위해서
    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 { 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(); } } } } } 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, "/login"); } }
    package ex03; @Controller public class BoardController { public void write(){ System.out.println("글쓰기 호출됨"); } }
    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) //런타임 실행시 -> 깃발을 꽂을때 하는 행위 = findUri @Target(ElementType.TYPE) // 클래스 위에 붙일 때 public @interface 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.METHOD) public @interface RequestMapping { // 어노테이션 //인터페이스앞에 @interface annotation이다 //발동시점을 정해야함 힌트를 컴파일시점에서 보고 작동함 String uri(); }
    package ex03; @Controller public class UserController { @RequestMapping(uri="/login") public void login(){ System.out.println("로그인 호출됨"); } @RequestMapping(uri="/join") public void join(){ System.out.println("회원가입 호출됨"); } @RequestMapping(uri="/userinfo") public void userinfo(){ System.out.println("유저정보 보기"); } @RequestMapping(uri="/update-Password") public void updatePassword(){ System.out.println("비밀번호 수정하기"); } }
    lombok 적용 안될 때
    Gradle
    To set up lombok with any build tool, you have to specify that the lombok dependency is required to compile your source code, but does not need to be present when running/testing/jarring/otherwise deploying your code. Generally this is called a 'provided' dependency. This page explains how to integrate lombok with the Gradle build tool.
    Gradle
    https://projectlombok.org/setup/gradle
    notion image
    package controller; import dao.BankDAO; import lombok.AllArgsConstructor; /** * 책임 : 유효성검사(바디데이터), 파싱(바디데이터), 적절한 DAO 찾기 */ @AllArgsConstructor public class BankController { private BankDAO dao; @RequestMapping(uri = "/insert") public void insert(){ // 1. 파싱 // 2. 유효성검사 // 3. dao 찾기 System.out.println("controller : insert"); dao.insert("1234", 1000); } @RequestMapping(uri = "/delete") public void delete(){ System.out.println("controller : delete"); dao.deleteByNumber(1); } @RequestMapping(uri = "/update") public void update(){ System.out.println("controller : update"); dao.updateByNumber(1000, 1); } @RequestMapping(uri = "/selectOne") public void selectOne(){ System.out.println("controller : selectOne"); dao.selectByNumber(1); } @RequestMapping(uri = "/selectAll") public void selectAll(){ System.out.println("controller : selectAll"); dao.selectAll(); } @RequestMapping(uri = "/withdraw") public void withdraw(){ System.out.println("controller : withdraw"); dao.updateByNumber(1000, 1); dao.updateByNumber(-1000, 2); } @RequestMapping(uri = "/deposit") public void deposit(){ System.out.println("controller : deposit"); dao.updateByNumber(1000, 1); } }
    import controller.BankController; import controller.RequestMapping; import lombok.AllArgsConstructor; import java.lang.reflect.Method; /** * 책임 : 라우팅 */ @AllArgsConstructor public class Dispatcher { private BankController con; public void route(String path){ Method[] methods = con.getClass().getDeclaredMethods(); for(Method method : methods){ RequestMapping rm = method.getDeclaredAnnotation(RequestMapping.class); if(rm == null) continue; if(rm.uri().equals(path)){ try { method.invoke(con); break; } catch (Exception e) { e.printStackTrace(); } } } } }
    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(); }
    import controller.BankController; import dao.BankDAO; public class BankApp { public static void main(String[] args) { String uri = "/withdraw"; BankDAO dao = new BankDAO(); BankController con = new BankController(dao); Dispatcher dis = new Dispatcher(con); dis.route(uri); } }
    notion image
    Share article

    vosw1

    RSS·Powered by Inblog