Java의 프록시 모드 상세 정보 및 인스턴스 코드

6271 단어 java프록시 모드
java 프록시 모드 상세 정보
선언:
어떤 경우, 한 고객이 하나의 대상을 직접 인용하고 싶지 않거나 인용할 수 없으며, 이때 대리라고 불리는 제3자를 통해 간접 인용을 실현할 수 있다.대리 대상은 클라이언트와 목표 대상 사이에서 중개 역할을 할 수 있고 대리 대상을 통해 고객이 볼 수 없는 내용과 서비스를 삭제하거나 고객이 필요로 하는 추가 서비스를 추가할 수 있다.
간단하게 말하자면 에이전트 모델은 하나의 에이전트 대상을 통해 실제 대상에 접근하고 장식 모델처럼 대상에 기능을 추가할 수 있다.
정적 에이전트
이른바 정적 에이전트는 프로그램이 실행되기 전에 에이전트 클래스가 존재한다. 즉, 우리가 코드를 작성할 때 에이전트 클래스의 코드를 다 썼고, 동적 에이전트는 프로그램이 실행될 때 자동으로 에이전트 클래스를 생성한다.
묘사하기에는 너무 추상적이어서 코드를 보면 어떻게 된 일인지 알 수 있다
main

public class Main {

  public static void main(String[] args) {
    Water water = new Water();
    WaterProxy waterProxy = new WaterProxy(water);
    waterProxy.drink();
  }

}

인터페이스

// 
public interface Drink {
  void drink();
}
피대리류

// 
public class Water implements Drink {

  @Override
  public void drink() {
    System.out.println("drink water");
  }

}

대리류

// 
// 
public class DrinkProxy implements Drink {
  
  private Drink drinkImpl;
  
  // Water 
  public DrinkProxy(Drink drinkImpl) {
    this.drinkImpl = drinkImpl;
  }
  
  @Override
  public void drink() {
    // 
    System.out.println("before drink");
    // 
    drinkImpl.drink();
    // 
    System.out.println("after drink");
  }

}

실행 결과

before drink
drink water
after drink
동적 에이전트
때때로 우리는 대리류가 대리하는 종류만 바꾸고 싶지만, 대리 대상이 실제 대상을 집행하는 방법은 앞뒤가 똑같다. 이른바 철타의 대리류, 흐르는 물의 피대리류다.정적 에이전트를 사용하면 에이전트만 같은 인터페이스의 클래스를 실현할 수 있고 임의의 클래스를 에이전트하려면 중복된 에이전트 클래스를 많이 써야 한다.이때 우리는 동적 에이전트를 사용할 수 있다. 자바는 동적 에이전트를 실현하기 위해 비교적 편리한 도구를 제공했다.
java.lang.reflect.Proxy 클래스에서 에이전트 객체를 동적으로 생성할 수 있는 방법

/**
   * ,  
   *InvocationHandler invoke 
   *
   * @param  loader  
   * @param  interfaces  
   * @param  h  InvocationHandler 
   * @return  
   */
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h)

InvocationHandler 인터페이스

/**
 * InvocationHandler
 * invoke 
 */
public interface InvocationHandler {

  /**
   * @param   
   * @param  method  
   * @param  args  
   * @return  
   */
  public Object invoke(Object proxy, Method method, Object[] args)
}


묘사는 항상 비교적 추상적이니, 역시 실례를 보는 것이 비교적 이해하기 쉽다
예제
InvocationHandler 인터페이스 구현 클래스

public class CommonInvocationHandler implements InvocationHandler {
  
  // 
  private Object proxied;
  
  public CommonInvocationHandler(Object proxied) {
    this.proxied = proxied;
  }
  
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    // 
    System.out.println("before doing something");
    // 
    Object result = method.invoke(proxied, args);
    // 
    System.out.println("after doing something");;
    return result;
  }

}

Main

public class Main {

  public static void main(String[] args) {
    // 
    Water water = new Water();
    // 
    Drink waterProxy = 
        (Drink) Proxy.newProxyInstance(water.getClass().getClassLoader(),
            water.getClass().getInterfaces(), 
            new CommonInvocationHandler(water));
    // 
    waterProxy.drink();
  }

}

결과 내보내기

before doing something
drink water
after doing something
구체적인 피프록시 대상을 원하지 않을 수도 있지만, 반드시 상응하는 인터페이스(인터페이스가 없는 클래스는 cglib로 동적 프록시를 실현할 수 있음)가 있어야만 동적 프록시 대상을 얻을 수 있다.최근에 비교적 핫한 Retrofit처럼 성명된 인터페이스를 통해 동적 에이전트를 사용하여 네트워크 요청을 직접 합니다.
예제
간단하게 레트로핏을 시뮬레이션해 볼게요.
POST 메모

//Post 
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface POST {
 String value() default "";
}
Query 메모

//Post 
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface POST {
 String value() default "";
}
서비스 인터페이스

public interface Service {
  // POST 
  @POST("/login")
  //@Query 
  void login(@Query("username")String username, 
      @Query("password")String password);
}
Main

public class Main {

  public static void main(String[] args) {
    //  Service 
    Service service = (Service) Proxy.newProxyInstance(Service.class.getClassLoader(),
        new Class[] { Service.class }, new InvocationHandler() {

          @Override
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //  
            String retativePath = ((POST) method.getAnnotations()[0]).value();
            System.out.println("relative path: " + retativePath);
            //  
            Annotation[][] parameterAnnotations = method.getParameterAnnotations();
            //  
            for (int i = 0; i < parameterAnnotations.length; i++) {
              if (parameterAnnotations[i].length != 0) {
                for (int j = 0; j < parameterAnnotations[i].length; j++) {
                  Query query = (Query) parameterAnnotations[i][j];
                  System.out.println(query.value() + ": " + args[i].toString());
                }
              }
            }
            return null;
          }
        });
    //  
    service.login("hello", "world");
  }

}

읽어주셔서 감사합니다. 여러분에게 도움이 되었으면 좋겠습니다. 본 사이트에 대한 지지에 감사드립니다!

좋은 웹페이지 즐겨찾기