자바 면접 흔 한 패턴 문제---대리 모드

  • 본 편 은 대리 디자인 모델 을 정리 한 것 으로 추 후 자주 업 데 이 트 됩 니 다~
  • 대리 모델 의 가장 직관 적 인 해석 은 대 리 를 통 해 대리 대상 에 게'강화'되 는 것 이다!(즉,피 에이전트 의 기능 확장)
  • 프 록 시 모드 는 정적 에이전트 와 동적 에이전트 로 나 뉜 다.동적 에이전트 의 프 록 시 클래스 는 동적 으로 생 성 되 고 정적 에이전트 의 프 록 시 클래스 는 우리 가 미리 작성 한 논리 이다.
  • 자바 에서 동적 대 리 를 실현 하 는 방식 은 두 가지 가 있다.
  • JDK 동적 에이전트
  • CGLIB 동적 에이전트
  • 1.정적 에이전트
    정적 에이전트 역할 분석:
  • 추상 적 인 역할:보통 인터페이스 나 추상 류 를 사용 하여 이 루어 진다.
  • 실제 역할:대 리 된 역할.
  • 대리 역할:실제 역할 을 대리 하고 실제 역할 을 대리 한 후에 보통 부속 적 인 조작 을 한다.
  • 호출 자:대리 역할 을 사용 하여 조작 을 합 니 다.
  • 우 리 는 세입 자가 집 을 빌 리 는 것 을 예 로 들 면,관련 대상 은 세입 자,중개,집주인 이다.집주인 은 피 대리 대상,중 개 는 대리 대상)
    세입 자 는 집주인 의 집 을 중개업 자의 손 을 통 해 임대 하고,대리 대상 중개업 자 는 세입 자 를 찾 아 전 세 를 구하 고 중개 비용 을 받 아야 한다.
    코드 구현:Rent.java 즉 추상 적 인 역할
    
    //     :  
    public interface Rent {
       public void rent();
    }
    Host.java 즉 실제 캐릭터
    
    //     :   ,       
    public class Host implements Rent{
       public void rent() {
           System.out.println("    ");
      }
    }
    Proxy.java 즉 대리 역할
    
    //    :  
    public class Proxy implements Rent {
       private Host host;
       public Proxy() { }
       public Proxy(Host host) {
           this.host = host;
      }
       //   
       public void rent(){
           seeHouse();
           host.rent();
           fare();
      }
       //   
       public void seeHouse(){
           System.out.println("     ");
      }
       //     
       public void fare(){
           System.out.println("    ");
      }
    }
    
    Client.java 호출 자,즉 고객
    
    //    ,          !
    public class Client {
       public static void main(String[] args) {
           //      
           Host host = new Host();
           //       
           Proxy proxy = new Proxy(host);
           //      !
           proxy.rent();
      }
    }
    정적 에이전트 의 단점:
    프 록 시 클래스 를 수 동 으로 만들어 야 합 니 다.프 록 시 대상 이 많 으 면 프 록 시 클래스 도 점점 많아 집 니 다.
    이 문 제 를 해결 하기 위해 동적 대리 가 생 겼 습 니 다!
    2.동적 에이전트
    동적 대리 하면 면접 을 볼 때 동적 대리 의 두 가지 실현 방식 을 물 어 볼 것 이다.
    먼저 공공UserService 인터페이스 와UserServiceImpl실현 유형 을 살 펴 보 자.
    
    /**
     * @author csp
     * @date 2021-06-03
     */
    public interface UserService {
        /**
         *   
         */
        void login();
        /**
         *   
         */
        void logout();
    }
    
    
    /**
     * @author csp
     * @date 2021-06-03
     */
    public class UserServiceImpl implements UserService{
        @Override
        public void login() {
            System.out.println("    ...");
        }
        @Override
        public void logout() {
            System.out.println("      ...");
        }
    }
    
    JDK 동적 에이전트
    코드 는 다음 과 같 습 니 다:
    
    /**
     * @author csp
     * @date 2021-06-03
     */
    public class JDKProxyFactory implements InvocationHandler {
        //     (     )
        private Object target;
        public JDKProxyFactory(Object target) {
            super();
            this.target = target;
        }
        /**
         *       
         *
         * @return
         */
        public Object createProxy() {
            // 1.           
            ClassLoader classLoader = target.getClass().getClassLoader();
            // 2.           
            Class<?>[] interfaces = target.getClass().getInterfaces();
            // 3.           invocationHandler     
            Object newProxyInstance = Proxy.newProxyInstance(classLoader, interfaces, this);
            return newProxyInstance;
        }
        /**
         *            
         *
         * @param proxy      .     
         * @param method        
         * @param args         
         * @return
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("JDK     :  /       ......");
            Object invoke = method.invoke(target, args);
            System.out.println("JDK     :  /       ......");
            return invoke;
        }
        public static void main(String[] args) {
            // 1.    
            UserServiceImpl userService = new UserServiceImpl();
            // 2.      
            JDKProxyFactory jdkProxyFactory = new JDKProxyFactory(userService);
            // 3.           ,        
            UserService userServiceProxy = (UserService) jdkProxyFactory.createProxy();
            userServiceProxy.login();
            System.out.println("==================================");
            userServiceProxy.logout();
        }
    }
    
    출력 결 과 는 다음 과 같 습 니 다.
    JDK 동적 에이전트:로그 인/로그아웃 전 논리 검사...
    사용자 로그 인...
    JDK 동적 에이전트:로그 인/로그 인 후 로그 인쇄...
    ==================================
    JDK 동적 에이전트:로그 인/로그아웃 전 논리 검사...
    사용자 로그 인 출시...
    JDK 동적 에이전트:로그 인/로그 인 후 로그 인쇄...
    CGLIB 동적 에이전트
    코드 는 다음 과 같 습 니 다:
    
    /**
     * @author csp
     * @date 2021-06-03
     */
    public class CglibProxyFactory implements MethodInterceptor {
        //     (     )
        private Object target;
        //             
        public CglibProxyFactory(Object target) {
            super();
            this.target = target;
        }
        /**
         *       
         *
         * @return
         */
        public Object createProxy() {
            // 1.  Enhancer
            Enhancer enhancer = new Enhancer();
            // 2.       class
            enhancer.setSuperclass(target.getClass());
            // 3.      
            enhancer.setCallback(this);
            return enhancer.create();
        }
        /**
         *            
         * @param o     
         * @param method       
         * @param objects         
         * @param methodProxy          
         * @return
         * @throws Throwable
         */
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("cglib     :  /       ......");
            Object invoke = method.invoke(target, objects);
            System.out.println("cglib     :  /       ......");
            return invoke;
        }
        public static void main(String[] args) {
            // 1.    
            UserServiceImpl userService = new UserServiceImpl();
            // 2.      
            CglibProxyFactory cglibProxyFactory = new CglibProxyFactory(userService);
            // 3.           ,        
            UserService userServiceProxy = (UserService) cglibProxyFactory.createProxy();
            userServiceProxy.login();
            System.out.println("==================================");
            userServiceProxy.logout();
        }
    }
    
    테스트 결 과 는 다음 과 같다.
    cglib 동적 에이전트:로그 인/로그 인 전 논리 검사...
    사용자 로그 인...
    cglib 동적 에이전트:로그 인/로그 인 후 로그 인쇄...
    ==================================
    cglib 동적 에이전트:로그 인/로그 인 전 논리 검사...
    사용자 로그 인 출시...
    cglib 동적 에이전트:로그 인/로그 인 후 로그 인쇄...
    면접 문제 1:JDK 동적 에이전트 와 CGLIB 동적 에이전트 의 차이 점 은?
    ① JDK 동적 대 리 는 본질 적 으로 피 대리 대상 의 인 터 페 이 스 를 실현 하 는 것 이 고 CGLib 는 본질 적 으로 피 대리 대상 을 계승 하여 이 를 덮어 쓰 는 방법 이다.
    ② JDK 동적 에이 전 트 는 인 터 페 이 스 를 구현 한 클래스 생 성 에이전트 에 만 적용 되 며,CGLib 는 이 제한 이 없다.그러나 CGLib 는 계승 을 사용 하여 실현 되 기 때문에 CGLib 는final클래스,private 방법 과static방법 을 대리 할 수 없다.
    ③ JDK 동적 대 리 는 JDK 에서 자체 적 으로 가 져 온 것 으로 CGLib 동적 대 리 는 제3자jar 가방 을 도입 해 야 한다.
    ④ 호출 에이전트 방법 에서 JDK 동적 대 리 는 반사 체 제 를 통 해 호출 되 고 CGLib 는 FastClass 체 제 를 통 해 직접 호출 된다.(한 편의 글 을 보고 FastClass 의 간단 한 이 해 는 index 아래 표 시 를 인삼 으로 사용 하 는 것 이 라 고 소개 했다.호출 할 방법 을 직접 찾 아 호출 할 수 있다)
    성능 상 JDK 1.7 이전 에는 FastClass 메커니즘 을 사 용 했 기 때문에 CGLib 는 JDK 보다 실행 효율 이 빨 랐 지만,JDK 동적 에이전트 가 계속 최적화 되면 서 JDK 1.7 부터 JDK 동적 에이전트 가 CGLib 보다 훨씬 빨 라 졌 다.
    면접 문제 2:JDK 동적 대 리 는 왜 인 터 페 이 스 를 실현 한 클래스 생 성 대리 만 가능 합 니까?
    근본 적 인 원인 은 JDK 동적 에이 전 트 를 통 해 생 성 된 클래스 가 프 록 시 클래스 를 계 승 했 기 때문에 더 이상 클래스 에 대한 에이 전 트 를 계승 할 수 없습니다.
    총결산
    글 은 정 해진 시간 에 업데이트 되 지 않 습 니 다.가끔 은 하루 에 몇 편 을 더 업데이트 합 니 다.만약 에 지식 을 공 고 히 하 는 데 도움 이 된다 면 3 연 대 를 지원 하 세 요.나중에 조금씩 업데이트 할 것 입 니 다!저희 의 또 다른 콘 텐 츠 에 많은 관심 부 탁 드 리 겠 습 니 다!

    좋은 웹페이지 즐겨찾기