0

0

Java中动态创建接口的方法

黄舟

黄舟

发布时间:2017-09-21 10:10:03

|

3205人浏览过

|

来源于php中文网

原创

这篇文章主要介绍了java中如何动态创建接口的实现方法的相关资料,需要的朋友可以参考下

有很多应用场景,用到了接口动态实现,下面举几个典型的应用:

1、mybatis / jpa 等orm框架,可以在接口上加注解进行开发,不需要编写实现类,运行时动态产生实现。

2、dubbo等分布式服务框架,消费者只需要引入接口就可以调用远程的实现,分析源代码,其实在消费端产生了接口的代理实现,再由代理调用远程接口。

3、spring aop 这是最典型的动态代理了。

立即学习Java免费学习笔记(深入)”;

创建接口的动态实现,有二种最常用的方式:JDK动态代理和CGLIB动态代理。

代理模式是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个真实对象的访问。

代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。

通过代理层这一中间层,有效的控制对于真实委托类对象的直接访问,同时可以实现自定义的控制策略(spring的AOP机制),设计上获得更大的灵活性。

下面用JDK动态代理加一点简单的代码来演示这个过程:

1、接口


package com.yhouse.modules.daos;

public interface IUserDao {
  public String getUserName();
}

2、创建代理


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

3、运行时调用接口的方法时的实现(这一过程也称为接口的方法实现)


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!";
  } 

}

4、测试


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

}

在这段测试代码中,并没有接口的任何实现,大家猜猜会是什么结果?

控制台打印:

极限网络办公Office Automation
极限网络办公Office Automation

专为中小型企业定制的网络办公软件,富有竞争力的十大特性: 1、独创 web服务器、数据库和应用程序全部自动傻瓜安装,建立企业信息中枢 只需3分钟。 2、客户机无需安装专用软件,使用浏览器即可实现全球办公。 3、集成Internet邮件管理组件,提供web方式的远程邮件服务。 4、集成语音会议组件,节省长途话费开支。 5、集成手机短信组件,重要信息可直接发送到员工手机。 6、集成网络硬

下载

说明接口在调用时,把实现委托给了代理,最后具体要做的就是这个代理里面的处理:

在上面这段代码当中,可以看出,拿到了接口的method以及args,那么就可以做很多的事情,如根据方法名或者配合方法上面的注解来实现比较丰富的功能。

一个简单的例子只是用来说明这个原理,下面再举一个远程接口动态调用的例子来加深理解。

1、创建代理类和目标类需要实现共同的接口Service


package com.markliu.remote.service;
/**
 * Service接口。代理类和被代理类抖需要实现该接口
 */
public interface Service {
  public String getService(String name, int number);
}

2、服务器端创建RemoteService类,实现了Service 接口。


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

3、创建封装客户端请求和返回结果信息的Call类

为了便于按照面向对象的方式来处理客户端与服务器端的通信,可以把它们发送的信息用 Call 类来表示。一个 Call 对象表示客户端发起的一个远程调用,它包括调用的类名或接口名、方法名、方法参数类型、方法参数值和方法执行结果。


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方法
}

4、创建动态代理模式中实际的业务处理类,实现了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 {

    // 封装请求信息
    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;
  }
}

5、创建获取代理类的工厂RemoteServiceProxyFactory


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

6、创建底层Socket通信的Connector类,负责创建拦截、发送和接受Call对象


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

7、创建远程服务器


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

8、创建本地客户端


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

控制台打印结果:

这个过程可以简单的归纳为:本地接口调用(客户端)--->本地接口代理实现(客户端)---->远程实现(服务器端)

相关文章

java速学教程(入门到精通)
java速学教程(入门到精通)

java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

65

2026.01.16

全民K歌得高分教程大全
全民K歌得高分教程大全

本专题整合了全民K歌得高分技巧汇总,阅读专题下面的文章了解更多详细内容。

121

2026.01.16

C++ 单元测试与代码质量保障
C++ 单元测试与代码质量保障

本专题系统讲解 C++ 在单元测试与代码质量保障方面的实战方法,包括测试驱动开发理念、Google Test/Google Mock 的使用、测试用例设计、边界条件验证、持续集成中的自动化测试流程,以及常见代码质量问题的发现与修复。通过工程化示例,帮助开发者建立 可测试、可维护、高质量的 C++ 项目体系。

33

2026.01.16

java数据库连接教程大全
java数据库连接教程大全

本专题整合了java数据库连接相关教程,阅读专题下面的文章了解更多详细内容。

39

2026.01.15

Java音频处理教程汇总
Java音频处理教程汇总

本专题整合了java音频处理教程大全,阅读专题下面的文章了解更多详细内容。

19

2026.01.15

windows查看wifi密码教程大全
windows查看wifi密码教程大全

本专题整合了windows查看wifi密码教程大全,阅读专题下面的文章了解更多详细内容。

85

2026.01.15

浏览器缓存清理方法汇总
浏览器缓存清理方法汇总

本专题整合了浏览器缓存清理教程汇总,阅读专题下面的文章了解更多详细内容。

19

2026.01.15

ps图片相关教程汇总
ps图片相关教程汇总

本专题整合了ps图片设置相关教程合集,阅读专题下面的文章了解更多详细内容。

11

2026.01.15

ppt一键生成相关合集
ppt一键生成相关合集

本专题整合了ppt一键生成相关教程汇总,阅读专题下面的的文章了解更多详细内容。

47

2026.01.15

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2.6万人学习

C# 教程
C# 教程

共94课时 | 7万人学习

Java 教程
Java 教程

共578课时 | 47.4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号