ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JAVA] 다이나믹 프록시 - 2
    Java 2020. 10. 4. 17:06

    - 참고 : 인프런 >> 더 자바, 코드를 조작하는 다양한 방법, (백기선 강의)

     

    다이나믹 프록시

     

    1. JDK Proxy 

    (java.lang.refelction.proxy)

     

    • 반드시 Interface가 정의 되어있어야 한다.
    • 런타임시 동적으로 생성
    • InvocationHandler 라는 Interface를 구현
      • invoke 메소드 Override하여 Proxy의 위임 기능을 수행
      • 'Object'에 대해 Reflection기능을 사용하여 기능을 구현

     

    [예제 코드]

    @Test
    public void test_다이나믹_프록시() {
        BookService bookService = (BookService) Proxy.newProxyInstance(BookService.class.getClassLoader(),
                new Class[]{BookService.class}, new InvocationHandler() {
    
            //리얼 서브젝트 클래스
            BookService bookService = new RealBookService();
    
                    @Override
                    public Object invoke(Object o, Method method, Object[] args) throws Throwable {
                        if (method.getName().equals("rent")) {
                            System.out.println("[before]");
                            Object invoke = method.invoke(bookService, args);
                            System.out.println("[after]");
                            return invoke;
                        }
                        return method.invoke(bookService, args);
                    }
                });
    
        bookService.rent();
    }
    

     

    2. CGLIB Proxy

     

    • 사용 ? 
      • 하이버 네이트
      • 스프링 AOP 

     

    [예제 코드]

    @Test
    public void test_다이나믹_프록시2_cglib() {
    
        MethodInterceptor handler = new MethodInterceptor() {
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                BookService bookService = new RealBookService();
                if (method.getName().equals("rent")) {
                    System.out.println("[before]");
                    Object invoke = method.invoke(bookService, args);
                    System.out.println("[after]");
                    return invoke;
                }
                return method.invoke(bookService, args);
            }
        };
    
        //Enhnacer라는 클래스를 이용하여 프록시를 생성한다.
        BookService bookService = (BookService) Enhancer.create(BookService.class, handler);
        bookService.rent();
    }

     

    3. Bytebuddy Proxy

     

     

    @Test
    public void test_다이나믹_프록시3_bytebuddy() throws Exception {
    
        /*
            상속을 통해 proxy >> 상속을 하지 못하는 클래스는 bytebuddy를 통해 못함.
              - final class >> 상속을 막음
              - private 생성자  >> 하위 클래스에서 부모클래스 생성자 호출을 막음
         */
    
        Class<? extends BookService> proxyClass = new ByteBuddy().subclass(BookService.class)
                .method(named("rent")).intercept(InvocationHandlerAdapter.of(new InvocationHandler() {
                    @Override
                    public Object invoke(Object o, Method method, Object[] args) throws Throwable {
                        BookService bookService = new RealBookService();
                        if (method.getName().equals("rent")) {
                            System.out.println("[before]");
                            Object invoke = method.invoke(bookService, args);
                            System.out.println("[after]");
                            return invoke;
                        }
                        return method.invoke(bookService, args);
                    }
                }))
                .make()
                .load(BookService.class.getClassLoader()).getLoaded();
    
        BookService bookService = proxyClass.getConstructor(null).newInstance();
        bookService.rent();
    }

     

    정리

     

     - 런타임에 인터페이스 또는 클래스의 프록시 인스턴스 또는 클래스를 만들어 사용하는 프로그래밍 기법

     

    사용 처 ? 

     - 스프링 데이터 JPA

     - 스프링 AOP

     - Mockito

    - 하이버네이트 Lazy Initialzation

    댓글

Designed by Tistory.