亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java中如何動(dòng)態(tài)創(chuàng)建接口的實(shí)現(xiàn)方法

 更新時(shí)間:2017年09月20日 15:20:28   作者:蝦米&老黃牛  
這篇文章主要介紹了Java中如何動(dòng)態(tài)創(chuàng)建接口的實(shí)現(xiàn)方法的相關(guān)資料,需要的朋友可以參考下

有很多應(yīng)用場(chǎng)景,用到了接口動(dòng)態(tài)實(shí)現(xiàn),下面舉幾個(gè)典型的應(yīng)用:

1、mybatis / jpa 等orm框架,可以在接口上加注解進(jìn)行開發(fā),不需要編寫實(shí)現(xiàn)類,運(yùn)行時(shí)動(dòng)態(tài)產(chǎn)生實(shí)現(xiàn)。

2、dubbo等分布式服務(wù)框架,消費(fèi)者只需要引入接口就可以調(diào)用遠(yuǎn)程的實(shí)現(xiàn),分析源代碼,其實(shí)在消費(fèi)端產(chǎn)生了接口的代理實(shí)現(xiàn),再由代理調(diào)用遠(yuǎn)程接口。

3、spring aop 這是最典型的動(dòng)態(tài)代理了。

創(chuàng)建接口的動(dòng)態(tài)實(shí)現(xiàn),有二種最常用的方式:JDK動(dòng)態(tài)代理和CGLIB動(dòng)態(tài)代理。

代理模式是一種常用的設(shè)計(jì)模式,其目的就是為其他對(duì)象提供一個(gè)代理以控制對(duì)某個(gè)真實(shí)對(duì)象的訪問。

代理類負(fù)責(zé)為委托類預(yù)處理消息,過濾消息并轉(zhuǎn)發(fā)消息,以及進(jìn)行消息被委托類執(zhí)行后的后續(xù)處理。

通過代理層這一中間層,有效的控制對(duì)于真實(shí)委托類對(duì)象的直接訪問,同時(shí)可以實(shí)現(xiàn)自定義的控制策略(spring的AOP機(jī)制),設(shè)計(jì)上獲得更大的靈活性。

下面用JDK動(dòng)態(tài)代理加一點(diǎn)簡(jiǎn)單的代碼來演示這個(gè)過程:

1、接口

package com.yhouse.modules.daos;

public interface IUserDao {
  public String getUserName();
}

2、創(chuàng)建代理

package com.yhouse.modules.daos;

import java.lang.reflect.Proxy;
/**
 * 創(chuàng)建代理
 * @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;
  }
}

3、運(yùn)行時(shí)調(diào)用接口的方法時(shí)的實(shí)現(xiàn)(這一過程也稱為接口的方法實(shí)現(xiàn))

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 {    
    //如果傳進(jìn)來是一個(gè)已實(shí)現(xiàn)的具體類(本次演示略過此邏輯)
    if (Object.class.equals(method.getDeclaringClass())) { 
      try { 
        return method.invoke(this, args); 
      } catch (Throwable t) { 
        t.printStackTrace(); 
      } 
    //如果傳進(jìn)來的是一個(gè)接口(核心)
    } else { 
      return run(method, args); 
    } 
    return null;
  }
  
  /**
   * 實(shí)現(xiàn)接口的核心方法 
   * @param method
   * @param args
   * @return
   */
  public Object run(Method method,Object[] args){ 
    //TODO     
    //如遠(yuǎn)程http調(diào)用
    //如遠(yuǎn)程方法調(diào)用(rmi)
    //....
    return "method call success!";
  } 

}

4、測(cè)試

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());
  }

}

在這段測(cè)試代碼中,并沒有接口的任何實(shí)現(xiàn),大家猜猜會(huì)是什么結(jié)果?

控制臺(tái)打印:

說明接口在調(diào)用時(shí),把實(shí)現(xiàn)委托給了代理,最后具體要做的就是這個(gè)代理里面的處理:

在上面這段代碼當(dāng)中,可以看出,拿到了接口的method以及args,那么就可以做很多的事情,如根據(jù)方法名或者配合方法上面的注解來實(shí)現(xiàn)比較豐富的功能。

一個(gè)簡(jiǎn)單的例子只是用來說明這個(gè)原理,下面再舉一個(gè)遠(yuǎn)程接口動(dòng)態(tài)調(diào)用的例子來加深理解。

1、創(chuàng)建代理類和目標(biāo)類需要實(shí)現(xiàn)共同的接口Service

package com.markliu.remote.service;
/**
 * Service接口。代理類和被代理類抖需要實(shí)現(xiàn)該接口
 */
public interface Service {
  public String getService(String name, int number);
}

2、服務(wù)器端創(chuàng)建RemoteService類,實(shí)現(xiàn)了Service 接口。

package com.markliu.remote.serviceimpl;
import com.markliu.remote.service.Service;
/**
 * 服務(wù)器端目標(biāo)業(yè)務(wù)類,被代理對(duì)象
 */
public class RemoteService implements Service {
  @Override
  public String getService(String name, int number) {
    return name + ":" + number;
  }
}

3、創(chuàng)建封裝客戶端請(qǐng)求和返回結(jié)果信息的Call類

為了便于按照面向?qū)ο蟮姆绞絹硖幚砜蛻舳伺c服務(wù)器端的通信,可以把它們發(fā)送的信息用 Call 類來表示。一個(gè) Call 對(duì)象表示客戶端發(fā)起的一個(gè)遠(yuǎn)程調(diào)用,它包括調(diào)用的類名或接口名、方法名、方法參數(shù)類型、方法參數(shù)值和方法執(zhí)行結(jié)果。

package com.markliu.local.bean;
import java.io.Serializable;
/**
 * 請(qǐng)求的javabean
 */
public class Call implements Serializable{
  private static final long serialVersionUID = 5386052199960133937L;
  private String className; // 調(diào)用的類名或接口名
  private String methodName; // 調(diào)用的方法名
  private Class<?>[] paramTypes; // 方法參數(shù)類型
  private Object[] params; // 調(diào)用方法時(shí)傳入的參數(shù)值
  /**
   * 表示方法的執(zhí)行結(jié)果 如果方法正常執(zhí)行,則 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方法
}

4、創(chuàng)建動(dòng)態(tài)代理模式中實(shí)際的業(yè)務(wù)處理類,實(shí)現(xiàn)了InvocationHandler 接口

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 {

    // 封裝請(qǐng)求信息
    Call call = new Call(classType.getName(), method.getName(), method.getParameterTypes(), args);
    // 創(chuàng)建鏈接
    Connector connector = new Connector();
    connector.connect(host, port);
    // 發(fā)送請(qǐng)求
    connector.sendCall(call);
    // 獲取封裝遠(yuǎn)程方法調(diào)用結(jié)果的對(duì)象
    connector.close();
    Object returnResult = call.getResult();
    return returnResult;
  }
}

5、創(chuàng)建獲取代理類的工廠RemoteServiceProxyFactory

package com.markliu.local.service;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

/**
 * 動(dòng)態(tài)創(chuàng)建RemoteService代理類的工廠
 */
public class RemoteServiceProxyFactory {

  public static Object getRemoteServiceProxy(InvocationHandler h) {
    Class<?> classType = ((ServiceInvocationHandler) h).getClassType();
    // 獲取動(dòng)態(tài)代理類
    Object proxy = Proxy.newProxyInstance(classType.getClassLoader(), 
        new Class[]{classType}, h);
    return proxy;
  }
}

6、創(chuàng)建底層Socket通信的Connector類,負(fù)責(zé)創(chuàng)建攔截、發(fā)送和接受Call對(duì)象

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

/**
 * 負(fù)責(zé)創(chuàng)建鏈接
 */
public class Connector {
  private Socket linksocket;
  private InputStream in;
  private ObjectInputStream objIn;
  private OutputStream out;
  private ObjectOutputStream objOut;

  public Connector(){}
  /**
   * 創(chuàng)建鏈接
   */
  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);
  }
  /**
   * 發(fā)送請(qǐng)求call對(duì)象
   */
  public void sendCall(Call call) throws IOException {
    objOut.writeObject(call);
  }
  /**
   * 獲取請(qǐng)求對(duì)象
   */
  public Call receive() throws ClassNotFoundException, IOException {
    return (Call) objIn.readObject();
  }
  /**
   * 簡(jiǎn)單處理關(guān)閉鏈接
   */
  public void close() {
    try {
      linksocket.close();
      objIn.close();
      objOut.close();
      in.close();
      out.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

7、創(chuàng)建遠(yuǎn)程服務(wù)器

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("遠(yuǎn)程服務(wù)器啟動(dòng)......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);
        // 對(duì)象輸入流讀取請(qǐng)求的call對(duì)象
        Call call = (Call) objIn.readObject();
        System.out.println("客戶端發(fā)送的請(qǐng)求對(duì)象:" + call);
        call = getCallResult(call);
        // 發(fā)送處理的結(jié)果回客戶端
        objOut.writeObject(call);
        objIn.close();
        in.close();
        objOut.close();
        out.close();
        socket.close();
    }
  }

  /**
   * 通過反射機(jī)制調(diào)用call中指定的類的方法,并將返回結(jié)果設(shè)置到原call對(duì)象中
   */
  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);
    // 獲取所要調(diào)用的方法
    Method method = classType.getMethod(methodName, paramsTypes);
    Object result = method.invoke(remoteService, params);
    call.setResult(result);
    return call;
  }
}

8、創(chuàng)建本地客戶端

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("調(diào)用遠(yuǎn)程方法getService的結(jié)果:" + result);
  }
}

控制臺(tái)打印結(jié)果:

這個(gè)過程可以簡(jiǎn)單的歸納為:本地接口調(diào)用(客戶端)--->本地接口代理實(shí)現(xiàn)(客戶端)---->遠(yuǎn)程實(shí)現(xiàn)(服務(wù)器端)

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 詳解Java弱引用(WeakReference)的理解與使用

    詳解Java弱引用(WeakReference)的理解與使用

    這篇文章主要介紹了Java弱引用(WeakReference)的理解與使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • 基于Java編寫一個(gè)粽子大作戰(zhàn)小游戲

    基于Java編寫一個(gè)粽子大作戰(zhàn)小游戲

    端午節(jié),又稱龍舟節(jié)、重午節(jié),是中國(guó)的傳統(tǒng)節(jié)日之一,每年農(nóng)歷五月初五慶祝,雖然端午假期已經(jīng)過去了,小編還是用Java編寫了一個(gè)粽子大作戰(zhàn)小游戲,感興趣的可以了解一下
    2023-06-06
  • Java單線程程序?qū)崿F(xiàn)實(shí)現(xiàn)簡(jiǎn)單聊天功能

    Java單線程程序?qū)崿F(xiàn)實(shí)現(xiàn)簡(jiǎn)單聊天功能

    這篇文章主要介紹了Java單線程程序?qū)崿F(xiàn)實(shí)現(xiàn)簡(jiǎn)單聊天功能,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • Spring實(shí)戰(zhàn)之容器中的工程Bean用法示例

    Spring實(shí)戰(zhàn)之容器中的工程Bean用法示例

    這篇文章主要介紹了Spring實(shí)戰(zhàn)之容器中的工程Bean用法,結(jié)合實(shí)例形式分析了Sring框架容器中的工程Bean相關(guān)配置、使用操作技巧,需要的朋友可以參考下
    2019-11-11
  • SpringBoot中時(shí)間類型 序列化、反序列化、格式處理示例代碼

    SpringBoot中時(shí)間類型 序列化、反序列化、格式處理示例代碼

    這篇文章主要介紹了SpringBoot中時(shí)間類型 序列化、反序列化、格式處理示例代碼,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-08-08
  • 劍指Offer之Java算法習(xí)題精講二叉樹與N叉樹

    劍指Offer之Java算法習(xí)題精講二叉樹與N叉樹

    跟著思路走,之后從簡(jiǎn)單題入手,反復(fù)去看,做過之后可能會(huì)忘記,之后再做一次,記不住就反復(fù)做,反復(fù)尋求思路和規(guī)律,慢慢積累就會(huì)發(fā)現(xiàn)質(zhì)的變化
    2022-03-03
  • Java 淺談 高并發(fā) 處理方案詳解

    Java 淺談 高并發(fā) 處理方案詳解

    這篇文章主要介紹了淺談Java高并發(fā)解決方案以及高負(fù)載優(yōu)化方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java使用新浪微博API開發(fā)微博應(yīng)用的基本方法

    Java使用新浪微博API開發(fā)微博應(yīng)用的基本方法

    這篇文章主要介紹了Java使用新浪微博API開發(fā)微博應(yīng)用的基本方法,文中還給出了一個(gè)不使用任何SDK實(shí)現(xiàn)Oauth授權(quán)并實(shí)現(xiàn)簡(jiǎn)單的發(fā)布微博功能的實(shí)現(xiàn)方法,需要的朋友可以參考下
    2015-11-11
  • Java實(shí)現(xiàn)Twitter的分布式自增ID算法snowflake

    Java實(shí)現(xiàn)Twitter的分布式自增ID算法snowflake

    這篇文章主要介紹了Java實(shí)現(xiàn)Twitter的分布式自增ID算法snowflake,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • java中接口(interface)及使用方法示例

    java中接口(interface)及使用方法示例

    這篇文章主要介紹了java中接口(interface)及使用方法示例,涉及接口定義的簡(jiǎn)單介紹以及Java語言代碼示例,具有一定借鑒價(jià)值,需要的朋友可以參考下。
    2017-11-11

最新評(píng)論