>  기사  >  Java  >  Java의 프록시 메커니즘에 대한 자세한 분석

Java의 프록시 메커니즘에 대한 자세한 분석

黄舟
黄舟원래의
2017-10-13 10:10:471454검색

이 기사는 주로 Java 프록시 메커니즘에 대한 자세한 해석을 소개합니다. 여기 있는 모든 사람과 공유하여 참조할 수 있습니다.

동적 프록시는 실제로 사용자가 지정한 모든 인터페이스를 기반으로 클래스 바이트를 동적으로 생성하는 java.lang.reflect.Proxy 클래스입니다. 이 클래스는 프록시 클래스를 상속하고 사용자가 지정한 모든 인터페이스(사용자가 전달하는 인터페이스)를 구현합니다. 매개변수) 배열) 그런 다음 지정한 클래스 로더를 사용하여 클래스 바이트를 시스템에 로드하고 마지막으로 해당 클래스의 객체를 생성하고 해당 메소드 멤버인 invocationHandler와 같은 객체의 일부 값을 초기화합니다. 모든 인터페이스에. 초기화 후 개체는 호출 클라이언트에 반환됩니다. 이러한 방식으로 클라이언트는 모든 인터페이스를 구현하는 프록시 개체를 얻습니다. 예제 분석을 참조하세요.

1. 비즈니스 인터페이스 클래스


public interface BusinessProcessor {
 public void processBusiness();
}

2. 비즈니스 구현 클래스


public class BusinessProcessorImpl implements BusinessProcessor {
 public void processBusiness() {
 System.out.println("processing business.....");
 }
}

3. 비즈니스 에이전트 클래스


rreee

4명의 고객 신청 수업 종료


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class BusinessProcessorHandler implements InvocationHandler {
 private Object target = null;
 BusinessProcessorHandler(Object target){
 this.target = target;
 }
 public Object invoke(Object proxy, Method method, Object[] args)
  throws Throwable {
 System.out.println("You can do something here before process your business");
 Object result = method.invoke(target, args);
 System.out.println("You can do something here after process your business");
 return result;
 }
}

이제 인쇄 결과를 살펴보겠습니다.


import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
public class Test {
 public static void main(String[] args) {
 BusinessProcessorImpl bpimpl = new BusinessProcessorImpl();
 BusinessProcessorHandler handler = new BusinessProcessorHandler(bpimpl);
 BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(bpimpl.getClass().getClassLoader(), bpimpl.getClass().getInterfaces(), handler);
 bp.processBusiness();
 }
}

결과를 통해 이전에 수행할 수 있었던 Proxy의 역할을 쉽게 확인할 수 있습니다. 핵심 비즈니스 방법 이후에는 로깅, 보안 메커니즘 등과 같이 수행하려는 일부 보조 작업을 수행합니다.

이제 위 클래스가 어떻게 작동하는지 분석해 보겠습니다.

카테고리 1, 2에 대해서는 별로 할 말이 없습니다. 먼저 카테고리 3을 살펴보겠습니다. InvocationHandler 인터페이스의 호출 메소드를 구현합니다. 실제로 이 클래스는 Proxy에서 최종적으로 호출하는 고정 인터페이스 메서드입니다. 프록시는 클라이언트의 비즈니스 방법이 어떻게 구현되는지는 중요하지 않습니다. 클라이언트가 Proxy를 호출하면 InvocationHandler의 호출 인터페이스만 호출하므로 실제로 구현된 메서드는 호출 메서드에서 호출되어야 합니다. 관계는 다음과 같습니다.


You can do something here before process your business
processing business.....
You can do something here after process your business

그럼 bp는 어떤 객체인가요? 기본 메소드를 변경하여 살펴보겠습니다.

 BusinessProcessorImpl bpimpl = new BusinessProcessorImpl();
 BusinessProcessorHandler handler = new BusinessProcessorHandler(bpimpl);
BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(....);
bp.processBusiness()-->invocationHandler.invoke()-->bpimpl.processBusiness();

출력 결과:


 public static void main(String[] args) {
 BusinessProcessorImpl bpimpl = new BusinessProcessorImpl();
 BusinessProcessorHandler handler = new BusinessProcessorHandler(bpimpl);
 BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(bpimpl.getClass().getClassLoader(), bpimpl.getClass().getInterfaces(), handler);
 bp.processBusiness();
 System.out.println(bp.getClass().getName());
 }

bp는 $Proxy0 클래스의 객체로 밝혀졌습니다. 그렇다면 이 수업은 어떤 모습일까요? 좋아요 이 클래스를 인쇄하기 위한 두 가지 메소드를 더 작성하고 그것이 무엇인지 살펴보겠습니다. 머리가 세 개이고 팔이 여섯 개인 경우는 무엇입니까? main 아래에 다음 두 가지 정적 메서드를 작성합니다.


You can do something here before process your business
processing business.....
You can do something here after process your business
$Proxy0

메인 메소드를 다시 작성하세요


public static String getModifier(int modifier){
 String result = "";
 switch(modifier){
  case Modifier.PRIVATE:
  result = "private";
  case Modifier.PUBLIC:
  result = "public";
  case Modifier.PROTECTED:
  result = "protected";
  case Modifier.ABSTRACT :
  result = "abstract";
  case Modifier.FINAL :
  result = "final";
  case Modifier.NATIVE :
  result = "native";
  case Modifier.STATIC :
  result = "static";
  case Modifier.SYNCHRONIZED :
  result = "synchronized";
  case Modifier.STRICT :
  result = "strict";
  case Modifier.TRANSIENT :
  result = "transient";
  case Modifier.VOLATILE :
  result = "volatile";
  case Modifier.INTERFACE :
  result = "interface";
 }
 return result;
 }
 public static void printClassDefinition(Class clz){
 String clzModifier = getModifier(clz.getModifiers());
 if(clzModifier!=null && !clzModifier.equals("")){
  clzModifier = clzModifier + " ";
 }
 String superClz = clz.getSuperclass().getName();
 if(superClz!=null && !superClz.equals("")){
  superClz = "extends " + superClz;
 }
 Class[] interfaces = clz.getInterfaces();
 String inters = "";
 for(int i=0; i<interfaces.length; i++){
  if(i==0){
  inters += "implements ";
  }
  inters += interfaces[i].getName();
 }
 System.out.println(clzModifier +clz.getName()+" " + superClz +" " + inters );
 System.out.println("{");
 Field[] fields = clz.getDeclaredFields();
 for(int i=0; i<fields.length; i++){
  String modifier = getModifier(fields[i].getModifiers());
  if(modifier!=null && !modifier.equals("")){
  modifier = modifier + " ";
  }
  String fieldName = fields[i].getName();
  String fieldType = fields[i].getType().getName();
  System.out.println("  "+modifier + fieldType + " "+ fieldName + ";");
 }
 System.out.println();
 Method[] methods = clz.getDeclaredMethods();
 for(int i=0; i<methods.length; i++){
  Method method = methods[i];
  String modifier = getModifier(method.getModifiers());
  if(modifier!=null && !modifier.equals("")){
  modifier = modifier + " ";
  }
  String methodName = method.getName();
  Class returnClz = method.getReturnType();
  String retrunType = returnClz.getName();
  Class[] clzs = method.getParameterTypes();
  String paraList = "(";
  for(int j=0; j<clzs.length; j++){
  paraList += clzs[j].getName();
  if(j != clzs.length -1 ){
   paraList += ", ";
  }
  }
  paraList += ")";
  clzs = method.getExceptionTypes();
  String exceptions = "";
  for(int j=0; j<clzs.length; j++){
  if(j==0){
   exceptions += "throws ";
  }
  exceptions += clzs[j].getName();
  if(j != clzs.length -1 ){
   exceptions += ", ";
  }
  }
  exceptions += ";";
  String methodPrototype = modifier +retrunType+" "+methodName+paraList+exceptions;
  System.out.println("  "+methodPrototype );
 }
 System.out.println("}");
 }

이제 출력을 살펴보겠습니다.


 public static void main(String[] args) {
 BusinessProcessorImpl bpimpl = new BusinessProcessorImpl();
 BusinessProcessorHandler handler = new BusinessProcessorHandler(bpimpl);
 BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(bpimpl.getClass().getClassLoader(), bpimpl.getClass().getInterfaces(), handler);
 bp.processBusiness();
 System.out.println(bp.getClass().getName());
 Class clz = bp.getClass();
 printClassDefinition(clz);
 }

분명히 Proxy.newProxyInstance 메소드는 다음 작업을 수행합니다.


1. 인터페이스에서 인터페이스를 구현하기 위해 전달된 두 번째 매개변수 인터페이스를 기반으로 클래스를 동적으로 생성합니다. 이 예에서는 BusinessProcessor 인터페이스의 processBusiness 메소드입니다. 그리고 Proxy 클래스를 상속하고 hashcode, toString 및 equals와 같은 세 가지 메서드를 다시 작성합니다. 구체적인 구현은 ProxyGenerator.generateProxyClass(...)를 참조하세요. 이 예에서는 $Proxy0 클래스


2가 생성되고 새로 생성된 클래스는 전달된 첫 번째 매개변수 classloder를 통해 jvm에 로드됩니다. $Proxy0 클래스


3을 로드하려고 합니다. 세 번째 매개변수를 사용하여 $Proxy0의 $Proxy0(InvocationHandler) 생성자를 호출하여 $Proxy0 객체를 생성하고 인터페이스 매개변수를 사용하여 해당 인터페이스의 메서드를 모두 순회합니다. 그리고 메소드 객체 초기화 객체를 생성합니다. 여러 메소드 멤버 변수


4는 $Proxy0의 인스턴스를 클라이언트에 반환합니다.

지금은 괜찮아요. 클라이언트가 이를 어떻게 조정하는지 살펴보겠습니다. 그러면 명확해질 것입니다.



1. 클라이언트가 얻는 것은 $Proxy0의 인스턴스 객체입니다. $Proxy0은 BusinessProcessor를 상속하므로 BusinessProcessor로 변환하는 데 문제가 없습니다.


You can do something here before process your business
processing business.....
You can do something here after process your business
$Proxy0
$Proxy0 extends java.lang.reflect.Proxy implements com.tom.proxy.dynamic.BusinessProcessor
{
  java.lang.reflect.Method m4;
  java.lang.reflect.Method m2;
  java.lang.reflect.Method m0;
  java.lang.reflect.Method m3;
  java.lang.reflect.Method m1;
  void processBusiness();
  int hashCode();
  boolean equals(java.lang.Object);
  java.lang.String toString();
}

2, bp.processBusiness();


실제로 $Proxy0.processBusiness()를 호출한 다음 $Proxy0.processBusiness()의 구현은 InvocationHandler를 통해 호출 메소드를 호출하는 것입니다!

요약

위 내용은 Java의 프록시 메커니즘에 대한 자세한 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.