Heim > Java > javaLernprogramm > Hauptteil

So erstellen Sie dynamisch Schnittstellen in Java

黄舟
Freigeben: 2017-09-21 10:10:03
Original
3024 Leute haben es durchsucht

In diesem Artikel werden hauptsächlich relevante Informationen zum dynamischen Erstellen von Schnittstellenimplementierungsmethoden in Java vorgestellt.

Es gibt viele Anwendungsszenarien, die die dynamische Implementierung von Schnittstellen verwenden Typische Beispiele: Anwendungen:

1. ORM-Frameworks wie mybatis/jpa können durch Hinzufügen von Anmerkungen zur Schnittstelle entwickelt werden. Es ist nicht erforderlich, Implementierungsklassen zu schreiben, und die Implementierung wird dynamisch zur Laufzeit generiert.

2. In verteilten Service-Frameworks wie Dubbo müssen Verbraucher nur die Schnittstelle einführen, um die Remote-Implementierung aufzurufen. Nach der Analyse des Quellcodes wird festgestellt, dass die Proxy-Implementierung der Schnittstelle tatsächlich generiert wird Verbraucherseite, und dann ruft der Proxy die Remote-Schnittstelle auf.

3. Spring Aop Dies ist der typischste dynamische Proxy.

Es gibt zwei gängigste Methoden zum Erstellen einer dynamischen Implementierung einer Schnittstelle: der dynamische JDK-Proxy und der dynamische CGLIB-Proxy.

Das Proxy-Muster ist ein häufig verwendetes Entwurfsmuster. Sein Zweck besteht darin, einen Proxy für andere Objekte bereitzustellen, um den Zugriff auf ein reales Objekt zu steuern.

Die Proxy-Klasse ist für die Vorverarbeitung von Nachrichten für die Delegate-Klasse, das Filtern von Nachrichten und das Weiterleiten von Nachrichten sowie für die Durchführung der Folgeverarbeitung verantwortlich, nachdem die Nachrichten von der Delegate-Klasse ausgeführt wurden.

Über die mittlere Schicht der Proxy-Schicht kann der direkte Zugriff auf echte Delegate-Klassenobjekte effektiv gesteuert und benutzerdefinierte Steuerungsstrategien (AOP-Mechanismus von Spring) implementiert werden größere Flexibilität im Design.

Im Folgenden wird der dynamische JDK-Proxy verwendet und ein einfacher Code hinzugefügt, um diesen Prozess zu demonstrieren:

1 Schnittstelle


package com.yhouse.modules.daos;

public interface IUserDao {
  public String getUserName();
}
Nach dem Login kopieren

2 . Erstellen Sie einen Proxy


package com.yhouse.modules.daos;

import java.lang.reflect.Proxy;
/**
 * 创建代理
 * @author clonen.cheng
 *
 */
public class Invoker {
  
  
  public Object getInstance(Class<?> cls){    
    MethodProxy invocationHandler = new MethodProxy();    
    Object newProxyInstance = Proxy.newProxyInstance( 
        cls.getClassLoader(), 
        new Class[] { cls }, 
        invocationHandler); 
    return (Object)newProxyInstance;
  }
}
Nach dem Login kopieren

3. Implementierung beim Aufruf der Schnittstellenmethode zur Laufzeit (dieser Vorgang wird auch Schnittstellenmethodenimplementierung genannt)


package com.yhouse.modules.daos;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MethodProxy implements InvocationHandler {

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {    
    //如果传进来是一个已实现的具体类(本次演示略过此逻辑)
    if (Object.class.equals(method.getDeclaringClass())) { 
      try { 
        return method.invoke(this, args); 
      } catch (Throwable t) { 
        t.printStackTrace(); 
      } 
    //如果传进来的是一个接口(核心)
    } else { 
      return run(method, args); 
    } 
    return null;
  }
  
  /**
   * 实现接口的核心方法 
   * @param method
   * @param args
   * @return
   */
  public Object run(Method method,Object[] args){ 
    //TODO     
    //如远程http调用
    //如远程方法调用(rmi)
    //....
    return "method call success!";
  } 

}
Nach dem Login kopieren

4. Test


In diesem Testcode gibt es keine Implementierung der Schnittstelle Ergebnis?
package com.yhouse.modules.daos;

public class ProxyTest {

  
  public static void main(String[] args) {
    IUserDao invoker=(IUserDao)new Invoker().getInstance(IUserDao.class);
    System.out.println(invoker.getUserName());
  }

}
Nach dem Login kopieren


Konsolendruck:

Das bedeutet, dass beim Aufruf der Schnittstelle die Implementierung an den Agenten delegiert wird und der letzte Schritt erfolgt ist in diesem Agenten Verarbeitung:

Im obigen Code ist ersichtlich, dass Sie nach dem Abrufen der Methode und der Argumente der Schnittstelle viele Dinge tun können, z B. basierend auf dem Methodennamen oder Verwenden Sie die Anmerkungen über der Methode, um umfangreichere Funktionen zu implementieren.

Ein einfaches Beispiel soll dieses Prinzip veranschaulichen. Hier ist ein weiteres Beispiel für den dynamischen Aufruf einer Remote-Schnittstelle, um das Verständnis zu vertiefen.

1. Beim Erstellen der Proxy-Klasse und der Zielklasse muss der gemeinsame Schnittstellendienst implementiert werden.


2. Erstellen Sie die RemoteService-Klasse Seite und implementieren Sie die Service-Schnittstelle.
package com.markliu.remote.service;
/**
 * Service接口。代理类和被代理类抖需要实现该接口
 */
public interface Service {
  public String getService(String name, int number);
}
Nach dem Login kopieren


3. Erstellen Sie eine Call-Klasse, die Kundenanfragen und zurückgegebene Ergebnisinformationen kapselt
package com.markliu.remote.serviceimpl;
import com.markliu.remote.service.Service;
/**
 * 服务器端目标业务类,被代理对象
 */
public class RemoteService implements Service {
  @Override
  public String getService(String name, int number) {
    return name + ":" + number;
  }
}
Nach dem Login kopieren

Um die Bearbeitung von Kunden- und Kundenanfragen in einem zu erleichtern objektorientiert Für die serverseitige Kommunikation können die von ihnen gesendeten Informationen durch die Call-Klasse dargestellt werden. Ein Call-Objekt stellt einen vom Client initiierten Remote-Aufruf dar, der den Namen der aufrufenden Klasse oder Schnittstelle, den Methodennamen, den Methodenparametertyp, den Methodenparameterwert und das Ergebnis der Methodenausführung umfasst.


4. Erstellen Sie die eigentliche Geschäftsverarbeitungsklasse im dynamischen Proxy-Modus und implementieren Sie die InvocationHandler-Schnittstelle
package com.markliu.local.bean;
import java.io.Serializable;
/**
 * 请求的javabean
 */
public class Call implements Serializable{
  private static final long serialVersionUID = 5386052199960133937L;
  private String className; // 调用的类名或接口名
  private String methodName; // 调用的方法名
  private Class<?>[] paramTypes; // 方法参数类型
  private Object[] params; // 调用方法时传入的参数值
  /**
   * 表示方法的执行结果 如果方法正常执行,则 result 为方法返回值,
   * 如果方法抛出异常,那么 result 为该异常。
   */
  private Object result;
  public Call() {}
  public Call(String className, String methodName, Class<?>[] paramTypes, Object[] params) {
    this.className = className;
    this.methodName = methodName;
    this.paramTypes = paramTypes;
    this.params = params;
  }
  // 省略了get和set方法
}
Nach dem Login kopieren


5. Erstellen Sie eine Factory zum Abrufen von Proxy-Klassen, RemoteServiceProxyFactory
package com.markliu.local.service;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import com.markliu.local.bean.Call;

public class ServiceInvocationHandler implements InvocationHandler {

  private Class<?> classType;
  private String host;
  private Integer port;

  public Class<?> getClassType() {
    return classType;
  }
  public ServiceInvocationHandler(Class<?> classType, String host, Integer port) {
    this.classType = classType;
    this.host = host;
    this.port = port;
  }
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

    // 封装请求信息
    Call call = new Call(classType.getName(), method.getName(), method.getParameterTypes(), args);
    // 创建链接
    Connector connector = new Connector();
    connector.connect(host, port);
    // 发送请求
    connector.sendCall(call);
    // 获取封装远程方法调用结果的对象
    connector.close();
    Object returnResult = call.getResult();
    return returnResult;
  }
}
Nach dem Login kopieren


6. Erstellen Sie eine Connector-Klasse für die zugrunde liegende Socket-Kommunikation, die für das Abfangen und Senden verantwortlich ist und Empfangen von Anrufobjekten
package com.markliu.local.service;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

/**
 * 动态创建RemoteService代理类的工厂
 */
public class RemoteServiceProxyFactory {

  public static Object getRemoteServiceProxy(InvocationHandler h) {
    Class<?> classType = ((ServiceInvocationHandler) h).getClassType();
    // 获取动态代理类
    Object proxy = Proxy.newProxyInstance(classType.getClassLoader(), 
        new Class[]{classType}, h);
    return proxy;
  }
}
Nach dem Login kopieren


7 Erstellen Sie einen Remote-Server

package com.markliu.local.service;
// 省略import

/**
 * 负责创建链接
 */
public class Connector {
  private Socket linksocket;
  private InputStream in;
  private ObjectInputStream objIn;
  private OutputStream out;
  private ObjectOutputStream objOut;

  public Connector(){}
  /**
   * 创建链接
   */
  public void connect(String host, Integer port) throws UnknownHostException, IOException {
    linksocket = new Socket(host, port);
    in = linksocket.getInputStream();
    out = linksocket.getOutputStream();
    objOut = new ObjectOutputStream(out);
    objIn = new ObjectInputStream(in);
  }
  /**
   * 发送请求call对象
   */
  public void sendCall(Call call) throws IOException {
    objOut.writeObject(call);
  }
  /**
   * 获取请求对象
   */
  public Call receive() throws ClassNotFoundException, IOException {
    return (Call) objIn.readObject();
  }
  /**
   * 简单处理关闭链接
   */
  public void close() {
    try {
      linksocket.close();
      objIn.close();
      objOut.close();
      in.close();
      out.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}
Nach dem Login kopieren


8 Lokaler Client

package com.markliu.remote.main;
// 省略import

public class RemoteServer {

  private Service remoteService;
  public RemoteServer() {
    remoteService = new RemoteService();
  }
  public static void main(String[] args) throws Exception {
    RemoteServer server = new RemoteServer();
    System.out.println("远程服务器启动......DONE!");
    server.service();
  }

  public void service() throws Exception {
    @SuppressWarnings("resource")
    ServerSocket serverSocket = new ServerSocket(8001);
    while (true) {
        Socket socket = serverSocket.accept();
        InputStream in = socket.getInputStream();
        ObjectInputStream objIn = new ObjectInputStream(in);
        OutputStream out = socket.getOutputStream();
        ObjectOutputStream objOut = new ObjectOutputStream(out);
        // 对象输入流读取请求的call对象
        Call call = (Call) objIn.readObject();
        System.out.println("客户端发送的请求对象:" + call);
        call = getCallResult(call);
        // 发送处理的结果回客户端
        objOut.writeObject(call);
        objIn.close();
        in.close();
        objOut.close();
        out.close();
        socket.close();
    }
  }

  /**
   * 通过反射机制调用call中指定的类的方法,并将返回结果设置到原call对象中
   */
  private Call getCallResult(Call call) throws Exception {
    String className = call.getClassName();
    String methodName = call.getMethodName();
    Object[] params = call.getParams();
    Class<?>[] paramsTypes = call.getParamTypes();

    Class<?> classType = Class.forName(className);
    // 获取所要调用的方法
    Method method = classType.getMethod(methodName, paramsTypes);
    Object result = method.invoke(remoteService, params);
    call.setResult(result);
    return call;
  }
}
Nach dem Login kopieren


Konsolendruckergebnis:

package com.markliu.local.main;
import java.lang.reflect.InvocationHandler;
import com.markliu.local.service.RemoteServiceProxyFactory;
import com.markliu.local.service.ServiceInvocationHandler;
import com.markliu.remote.service.Service;

public class LocalClient {
  public static void main(String[] args) {
    String host = "127.0.0.1";
    Integer port = 8001;
    Class<?> classType = com.markliu.remote.service.Service.class;
    InvocationHandler h = new ServiceInvocationHandler(classType, host, port);
    Service serviceProxy = (Service) RemoteServiceProxyFactory.getRemoteServiceProxy(h);
    String result = serviceProxy.getService("SunnyMarkLiu", 22);
    System.out.println("调用远程方法getService的结果:" + result);
  }
}
Nach dem Login kopieren

Dieser Vorgang kann einfach zusammengefasst werden als: lokaler Schnittstellenaufruf (Client) - -->Proxy-Implementierung der lokalen Schnittstelle (Client)---->Remote-Implementierung (Server)

Das obige ist der detaillierte Inhalt vonSo erstellen Sie dynamisch Schnittstellen in Java. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage