Dubbo源码(6)-动态代理技术源码解析

Dubbo集群容错策略和动态代理策略 这就需要spi了,需要根据指定的配置或者是默认的配置,去找到对应的实现类加载进来,然后才可以调用到这个实现类的实例对象。注解标注了方法,在运行的时候会针对Protocol生成代理类,这个代理类在运行的时候动态根据url中的 protocol来获取那个key,默认是dubbo,也可以自己指定,如果指定了别的key,就会获取别的实现类的实例。这行配置,接着会根据配置使用定义好的MyProtocol了,通过上述方式,可以替换掉大量的dubbo内部的组件,写一个自己的jar包,然后配置一下即可。 阅读详情

本文主要参考自Dubbo官方文档、Dubbo项目源码以及网络文章和相关书籍,并附上自身的一些理解,如有遗漏或错误,还望海涵并指出。谢谢!

------本文基于Dubbo-2.6.1版本

一.Dubbo中的动态代理

1.1、Dubbo Invoker领域模型

在说Dubbo动态代理之前,先来看看Dubbo的Invoker领域模型。

任何框架或组件,总会有核心领域模型,比如:Spring 的 Bean,Struts 的 Action,Dubbo 的 Service,Napoli 的 Queue 等等。这个核心领域模型及其组成部分称为实体域,它代表着我们要操作的目标本身。实体域通常是线程安全的,不管是通过不变类,同步状态,或复制的方式。

服务域也就是行为域,它是组件的功能集,同时也负责实体域和会话域的生命周期管理, 比如 Spring 的 ApplicationContext,Dubbo 的 ServiceManager 等。服务域的对象通常会比较重,而且是线程安全的,并以单一实例服务于所有调用。

什么是会话?就是一次交互过程。会话中重要的概念是上下文,什么是上下文?比如我们说:“老地方见”,这里的“老地方”就是上下文信息。为什么说“老地方”对方会知道,因为我们前面定义了“老地方”的具体内容。所以说,上下文通常持有交互过程中的状态变量等。会话对象通常较轻,每次请求都重新创建实例,请求结束后销毁。

简而言之:把元信息交由实体域持有,把一次请求中的临时状态由会话域持有,由服务域贯穿整个 过程。

百度中关于领域模型的解释:

领域模型是对领域内的概念类或现实世界中对象的可视化表示。 又称概念模型、领域对象模型、分析对象模型。 它专注于分析问题领域本身,发掘重要的业务领域概念,并建立业务领域概念之间的关系。

Invoker是Dubbo 领域模型中非常重要的一个概念,很多设计思路都是向它靠拢。这就使得Invoker渗透在整个实现代码里。而Invoker的实现是基于动态代理的,这也是本文要讲解的重点。

1.2、Invoke在RPC过程中的作用

在整个Dubbo关于RPC通信过程的代码中出现了很多个Invoker,Invoker直译为执行器,那么这些Invoker的作用是什么呢?

下面来看一张图,简化了Dubbo RPC过程中的其他组件,来直观地看Invoker在这个过程中的作用:

在这里插入图片描述

可以看出,在服务提供端中,Invoker封装了具体的实现服务类。

当服务消费端需要通过RPC调用这个服务时,生成proxy调用对应的Invoker,借助网络通知到服务提供端Exporter,然后Exporter调用Invoker执行具体的服务逻辑。

可以看出,Invoker实质上就是由动态代理生成并封装了网络连接和数据处理的逻辑,以屏蔽底层的实现。这就是DUbbo动态代理技术的实际运用了。

二.RPC调用流程

在看源码之前,先来从宏观的层面了解下整个调用的流程,这里忽略了很多细节,只展示最重要的实现,如下图:

在这里插入图片描述

整体的流程如下:

  1. 客户端通过RPC调用Service接口的方法
  2. 通过动态代理生成一个Proxy代理对象,该对象实现了Service接口,内容大致如下:
public class proxy0 implements ClassGenerator.DC, EchoService, Service {
    public static Method[] methods;
    private InvocationHandler handler
    public void bye(Object paramObject) {
       Object[] arrayOfObject = new Object[1];
       arrayOfObject[0] = paramObject;
       Object localObject = this.handler.invoke(this, methods[0], arrayOfObject);
    }
    public String hello(String paramString){ Object[] arrayOfObject = new Object[1];
       arrayOfObject[0] = paramString;
       Object localObject = this.handler.invoke(this, methods[1], arrayOfObject);
       return (String)localObject;
    }
    public Object $echo(Object paramObject) {
       Object[] arrayOfObject = new Object[1];
       arrayOfObject[0] = paramObject;
       Object localObject = this.handler.invoke(this, methods[2], arrayOfObject);
       return (Object)localObject;
    }
    public proxy0() {
        public proxy0(InvocationHandler paramInvocationHandler) {
            this.handler = paramInvocationHandler; 
        } 
    }

该类通过dubbo-common模块的bytecode模块的 Proxy类使用Javassis动态代理技术生成。

代理类首先实现了Service接口,然后所有的重写方法调用都是集中在了InvocationHandler的invoke方法中执行,这里实质上就是调用了代理对象(封装了许多RPC细节)。

  1. 服务端接的Protocol收到了这个RPC调用。
  2. Protocol获取到被调用的Exporter对象
  3. Exporter对象获取到Invoker代理对象
  4. Invoker代理对象执行Wrapper包装类对象中对应的方法。实质上Wrapper对象内含有Service实现对象,如以下代码:
public class Wrapper1 extends Wrapper implements ClassGenerator.DC
{
       public static String[] pns;
       public static Map pts;
       public static String[] mns;
       public static String[] dmns;
       public static Class[] mts0;
       public static Class[] mts1;
       public static Class[] mts2;

       public String[] getPropertyNames()
       {
         return pns;
       }

       public boolean hasProperty(String paramString)
       {
         return pts.containsKey(paramString);
       }

       public Class getPropertyType(String paramString)
       {
         return (Class)pts.get(paramString);
       }

       public String[] getMethodNames()
       {
         return mns;
       }

       public String[] getDeclaredMethodNames()
       {
         return dmns;
       }

       public void setPropertyValue(Object paramObject1, String paramString, Object paramObject2)
       {
         ServiceImpl w;
         try
         {
           w = (ServiceImpl)paramObject1;
         }
         catch (Throwable localThrowable)
         {
           throw new IllegalArgumentException(localThrowable);
         }
         if (paramString.equals("test01"))
         {
           w.test01 = ((String)paramObject2);
           return;
         }
         if (paramString.equals("demoDAO"))
         {
           localServiceImpl.setDemoDAO((DemoDAO)paramObject2);
           return;
         }
         throw new NoSuchPropertyException("Not found property \"" + paramString + "\" filed or setter method in class com.alibaba.dubbo.demo.provider.ServiceImpl.");
       }

       public Object getPropertyValue(Object paramObject, String paramString)
       {
         ServiceImpl w;
         try
         {
           w = (ServiceImpl)paramObject;
    }
    catch (Throwable localThrowable)
        {throw new IllegalArgumentException(localThrowable);
        }
        if (paramString.equals("test01")) {return localServiceImpl.test01;
        }
        throw new NoSuchPropertyException("Not found property \"" + paramString + "\" filed or setter method in class com.alibaba.dubbo.demo.provider.ServiceImpl.");
    }
    public Object invokeMethod(Object paramObject, String paramString, Class[] paramArrayOfClass, Object[] paramArrayOfObject)
    throws InvocationTargetException
      {ServiceImpl w;
      try
    {
        w = (ServiceImpl)paramObject;
    }
      catch (Throwable localThrowable1)
      {
        throw new IllegalArgumentException(localThrowable1);
      }
      try
    {
        if ("hello".equals(paramString) && paramArrayOfClass.length == 1) {
            return w.hello((String)paramArrayOfObject[0]);
        }
        if ("bye".equals(paramString) && paramArrayOfClass.length == 1)
        {w.bye((Object)paramArrayOfObject[0]);
        return null;
        }
        if ("setDemoDAO".equals(paramString) && paramArrayOfClass.length == 1)
        {w.setDemoDAO((DemoDAO)paramArrayOfObject[0]);
        return null;
        }
    }
      catch (Throwable localThrowable2)
    {
        throw new InvocationTargetException(localThrowable2);
    }
      throw new NoSuchMethodException("Not found method \"" + paramString + "\" in class com.alibaba.dubbo.demo.provider.ServiceImpl.");
    }
}

该包装类由dubbo-common模块的bytecode模块的Wrapper类使用Javassist动态代理技术生成。

可以看到到了这一步,其实就是在调用包装类中包装的实现类的具体方法了。

三.动态代理相关源码解析

关于Dubbo的动态代理技术的使用,相关的源码集中在dubbo-rpc模块以及dubbo-common模块下的bytecode包。

dubbo-rpc远程调用模块包含了各种协议的抽象,以及动态代理,只包含一对一的调用,不关心集群的管理。

3.1、ProxyFactory

ProxyFactory接口位于dubbo-rpc模块下的dubbo-rpc-api子模块,定义了获取Proxy的方法,以SPI机制做动态拓展,默认使用的是JavassistProxyFactory作为拓展实现类(Javassist做底层的动态代理技术,性能优于Jdk动态代理)。

  • ProxyFactory
@SPI("javassist")
public interface ProxyFactory {

    /**
     * 获取指定的proxy
     *
     * @param invoker
     * @return proxy
     */
    @Adaptive({Constants.PROXY_KEY})
    <T> T getProxy(Invoker<T> invoker) throws RpcException;

    /**
     * 获取指定的Invoker
     *
     * @param <T>
     * @param proxy
     * @param type
     * @param url
     * @return invoker
     */
    @Adaptive({Constants.PROXY_KEY})
    <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;
}
  • 实现关系图
    在这里插入图片描述
3.1.1、AbstractProxyFactory
  • AbstractProxyFactory
public abstract class AbstractProxyFactory implements ProxyFactory {

    /*
     *   传入invoker获取proxy
     */
    public <T> T getProxy(Invoker<T> invoker) throws RpcException {
        // 接口数组
        Class<?>[] interfaces = null;
        // 获取invoker的url,再获取url中的interfaces配置
        String config = invoker.getUrl().getParameter("interfaces");
        // 解析接口配置
        if (config != null && config.length() > 0) {
            // 获取到接口全限定名数组
            String[] types = Constants.COMMA_SPLIT_PATTERN.split(config);
            if (types != null && types.length > 0) {
                // 额外申请接口数组长度+2
                interfaces = new Class<?>[types.length + 2];
                // 第一个位置放置invoker自身实现的接口
                interfaces[0] = invoker.getInterface();
                // EchoService接口用于回声测试
                interfaces[1] = EchoService.class;
                for (int i = 0; i < types.length; i++) {
                    // 使用反射生成接口class
                    interfaces[i + 1] = ReflectUtils.forName(types[i]);
                }
            }
        }
        if (interfaces == null) {
            interfaces = new Class<?>[]{invoker.getInterface(), EchoService.class};
        }
        // 模板方法模式,让具体实现类实现getProxy(invoker, interfaces)的逻辑
        return getProxy(invoker, interfaces);
    }

    public abstract <T> T getProxy(Invoker<T> invoker, Class<?>[] types);
}
3.1.2、JavassistProxyFactory

com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory是ProxyFactory的默认拓展实现类:

  • JavassistProxyFactory
/**
 * JavaassistRpcProxyFactory,ProxyFactory默认拓展实现类
 */
public class JavassistProxyFactory extends AbstractProxyFactory {

    @SuppressWarnings("unchecked")
    /*
    *   获取proxy,这里需要看Proxy类和InvokerInvocationHandler的源码
     */
    public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
        return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
    }

    /*
    *   获取invoker,不能够获取类名含有$的proxy
     */
    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        // TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
        final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
        return new AbstractProxyInvoker<T>(proxy, type, url) {
            @Override
            protected Object doInvoke(T proxy, String methodName,
                                      Class<?>[] parameterTypes,
                                      Object[] arguments) throws Throwable {
                return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
            }
        };
    }

}
3.2、InvokerInvocationHandler

com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler基于Jdk的InvocationHandler做了一层封装实现:

  • InvokerInvocationHandler
public class InvokerInvocationHandler implements InvocationHandler {

    private final Invoker<?> invoker;

    public InvokerInvocationHandler(Invoker<?> handler) {
        this.invoker = handler;
    }

    /*
    *   执行proxy的方法
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 获取方法名
        String methodName = method.getName();
        // 获取方法参数
        Class<?>[] parameterTypes = method.getParameterTypes();
        // 如果proxy为Object,则直接使用method执行
        if (method.getDeclaringClass() == Object.class) {
            return method.invoke(invoker, args);
        }
        // 下面三个方法统一使用invoker直接调用
        if ("toString".equals(methodName) && parameterTypes.length == 0) {
            return invoker.toString();
        }
        if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
            return invoker.hashCode();
        }
        if ("equals".equals(methodName) && parameterTypes.length == 1) {
            return invoker.equals(args[0]);
        }
        // 除此之外的其他用户方法,采用invoker.invoke的方式来执行
        return invoker.invoke(new RpcInvocation(method, args)).recreate();
    }

}
3.3、AbstractProxyInvoker

com.alibaba.dubbo.rpc.proxy.AbstractProxyInvoker实现了Invoker,可以获取到RPC调用的执行结果:

  • AbstractProxyInvoker
public abstract class AbstractProxyInvoker<T> implements Invoker<T> {

    // 被代理的接口实现类
    private final T proxy;
    // 被代理的接口
    private final Class<T> type;
    // 传入URL对象
    private final URL url;

    /*
    *   构造方法
     */
    public AbstractProxyInvoker(T proxy, Class<T> type, URL url) {
        if (proxy == null) {
            throw new IllegalArgumentException("proxy == null");
        }
        if (type == null) {
            throw new IllegalArgumentException("interface == null");
        }
        if (!type.isInstance(proxy)) {
            throw new IllegalArgumentException(proxy.getClass().getName() + " not implement interface " + type);
        }
        this.proxy = proxy;
        this.type = type;
        this.url = url;
    }

    public Class<T> getInterface() {
        return type;
    }

    public URL getUrl() {
        return url;
    }

    public boolean isAvailable() {
        return true;
    }

    public void destroy() {
    }

    /*
    *   执行代理方法,获取到RPC调用结果
     */
    public Result invoke(Invocation invocation) throws RpcException {
        try {
            return new RpcResult(doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments()));
        } catch (InvocationTargetException e) {
            return new RpcResult(e.getTargetException());
        } catch (Throwable e) {
            throw new RpcException("Failed to invoke remote proxy method " + invocation.getMethodName() + " to " + getUrl() + ", cause: " + e.getMessage(), e);
        }
    }

    protected abstract Object doInvoke(T proxy, String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Throwable;

    @Override
    public String toString() {
        return getInterface() + " -> " + (getUrl() == null ? " " : getUrl().toString());
    }


}
  • RpcResult
public class RpcResult implements Result, Serializable {

    private static final long serialVersionUID = -6925924956850004727L;
    // RPC调用结果
    private Object result;

    private Throwable exception;
    // 额外附加信息
    private Map<String, String> attachments = new HashMap<String, String>();

    public RpcResult() {
    }

    public RpcResult(Object result) {
        this.result = result;
    }

    public RpcResult(Throwable exception) {
        this.exception = exception;
    }

    public Object recreate() throws Throwable {
        if (exception != null) {
            throw exception;
        }
        return result;
    }

    /**
     * @see com.alibaba.dubbo.rpc.RpcResult#getValue()
     * @deprecated Replace to getValue()
     */
    @Deprecated
    public Object getResult() {
        return getValue();
    }

    /**
     * @see com.alibaba.dubbo.rpc.RpcResult#setValue(Object)
     * @deprecated Replace to setValue()
     */
    @Deprecated
    public void setResult(Object result) {
        setValue(result);
    }

    public Object getValue() {
        return result;
    }

    public void setValue(Object value) {
        this.result = value;
    }

    public Throwable getException() {
        return exception;
    }

    public void setException(Throwable e) {
        this.exception = e;
    }

    public boolean hasException() {
        return exception != null;
    }

    public Map<String, String> getAttachments() {
        return attachments;
    }

    /**
     * Append all items from the map into the attachment, if map is empty then nothing happens
     *
     * @param map contains all key-value pairs to append
     */
    public void setAttachments(Map<String, String> map) {
        if (map != null && map.size() > 0) {
            attachments.putAll(map);
        }
    }

    public String getAttachment(String key) {
        return attachments.get(key);
    }

    public String getAttachment(String key, String defaultValue) {
        String result = attachments.get(key);
        if (result == null || result.length() == 0) {
            result = defaultValue;
        }
        return result;
    }

    public void setAttachment(String key, String value) {
        attachments.put(key, value);
    }

    @Override
    public String toString() {
        return "RpcResult [result=" + result + ", exception=" + exception + "]";
    }
}
3.4、bytecode包

上述的代码都基于dubbo-rpc-api子模块进行分析,下面基于dubbo-common模块的bytecode包,基于Javassit动态编译技术做了高性能的动态代理实现,用以生成wrapper与proxy的代码。

// TODO

AxMath行间公式转化为office公式求和符号以及编号显示问题 AxMath行间公式转化为office公式求和符号以及编号显示问题问题描述解决方法 问题描述 首先打出axmath公式,如下: 转换后的OfficeMath公式: 字体先不说,word公式字体默认cambria math且无法编辑。比较难受的一点是求和符号与后面的 ai+bi2a_i+b_i^2ai​+bi2​比例不匹配啊!正常的比例应该是: (虽然也不太正常,将就下) 解决方法 点击变换后的office公式右侧,选择更改为"显示" 可以看到,多了一些软回车符号(⬇),如果你想删除它,不要直接选中 阅读详情

相关推荐

从分立到集成:深入解析Buck电路的核心模块与设计权衡

本文深入解析Buck电路的核心模块与设计权衡,从分立到集成方案的优缺点对比。详细探讨Buck电路的高效能量转换、小型化设计及灵活电压调节能力,并结合实际案例分享分立方案中的PWM生成、反馈环路设计及保护电路优化经验,为工程师提供实用设计参考。

weixin_29306317的博客 225

Dubbo源码解析-动态代理JDK篇

前言: 有关于动态代理,是一个长盛不衰的话题。无论是面试还是各个框架的应用,都是热点话题。 而关于Dubbo的动态代理,有两种实现方式:一种是JDK,另一种是Javassist。 本文来介绍下JDK动态代理的使用方式,并简单分析下其源码实现。 1.JDK动态打理示例 1.1 创建接口及实现类 // 接口 public interface Subject { String say(String name); } // 实现类 public class Rea...

恐龙弟旺仔的博客 1439

OpenBCI脑电实验避坑指南:如何用Python准确捕捉P300信号

本文详细介绍了使用OpenBCI和Python进行P300脑电信号实验的避坑指南,包括电极贴放、信号采集、信号处理和数据分析等关键步骤。通过实战经验和代码示例,帮助研究者避开常见陷阱,提高P300信号捕捉的准确率,适用于脑机接口和神经科学研究。

weixin_30316097的博客 553

Dubbo 动态代理策略有哪些?

这些动态代理策略可以根据不同的需求和场景进行选择,以满足不同的性能和扩展性要求。Dubbo 还提供了丰富的配置选项,可以根据需要进行灵活的配置和调整。Dubbo 是一个高性能、轻量级的 Java RPC 框架,它支持多种动态代理策略。

qq_33240556的博客 965

Visual SLAM算法笔记

最近在学习SLAM算法,这里作为阅读笔记记录和总结一下。对经典的单目SLAM/VO算法做了摘要和总结,比如Nister VO、MonoSLAM、PTAM、ORB-SLAM、LSD-SLAM、SVO、DSO等,对几个单目和IMU的融合算法也做了简单总结,比如MSCKF、OKVIS、IMU-Preintegration等。

MulinB的技术博客 3万+

C#实战:如何从零构建一个轻量级软PLC梯形图编辑器(附完整源码)

本文详细介绍了如何使用C#从零开始构建一个轻量级软PLC梯形图编辑器。内容涵盖项目架构设计、GDI+图形渲染、编辑交互实现以及核心的扫描执行引擎开发,并提供了定时器、计数器等高级功能的实现思路与完整源码,为开发者深入工业自动化领域提供了实战指南。

4k5l6j7h8的博客 258

Dubbo之ProxyFactory

为什么80%的码农都做不了架构师?>>> ...

weixin_34072857的博客 550

AD元件库构建及维护之——DbLib公共元件库的使用教程

AD元件库构建及维护之——DbLib元件库的使用教程

qq_43105486的博客 2万+

dubbo有哪些动态代理策略

JDK 动态代理:默认代理方式,适用于接口代理。Javassist 动态代理:性能较高,适用于高并发场景。ByteBuddy 动态代理:灵活性和性能兼顾,适用于复杂字节码操作场景。CGlib 动态代理:可用于没有接口的类代理,虽然在 Dubbo 中不常见。通过设置,你可以在代码中动态选择代理策略。

u012534547的博客 837

第一章 初识SpringBoot

提供大量的自动配置Spring和第三方库,开发者可以根据项目需求选择相关的starters依赖,而无需手动配置大量的Spring配置文件,开箱即用,无需配置XML,无代码生成。Spring Boot与Spring Cloud等框架集成,为构建微服务提供了强大的支持,并通过Spring Cloud实现服务注册、负载均衡、熔断等功能。本质上讲,Spring Boot就是Spring,它做了那些本应我们去做的Spring Bean配置等工作。以上就是一个简单的Spring Boot应用的创建和运行过程。

Calvin的博客 1581

基于 YOLOv26 的食品包装缺陷检测系统:智能视觉质检方案

本文提出了一种基于YOLOv26深度学习的食品包装缺陷智能检测系统。该系统能够自动识别多种常见包装缺陷,包括密封不良、破损、污染、标签错误等8类问题。相比传统人工检测方法,该系统具有高精度、多类别分类、实时推理等优势。文章详细介绍了系统架构,包含数据采集、预处理、YOLOv26检测模型和后处理四个核心模块,并提供了完整的环境配置和数据处理代码实现。该系统为食品包装行业提供了一种高效、准确的智能视觉质检解决方案。

一键难忘的博客 687

RPC实现原理之核心技术-动态代理

1. 动态代理调用流程 RPC的调用对用户来讲是透明的,内部具体是如何实现呢? 核心技术采用的就是动态代理,RPC 会自动给接口生成一个代理类,当我们在项目中注入初始化接口的时候,运行过程中实际绑定的是这个接口生成的代理类。 在接口方法被调用的时候,它实际上是被生成代理类拦截到了,这样就可以在生成的代理类里面,加入其他调用处理逻辑。 2. 为什么要加入动态代理 如果没有动态代理, 服务端大量的接口将不便于管理,需要大量的if判断,如果扩展了新的接口,需要更改调用逻辑, 不利于扩展维护。 动态代理可

Mirson - 多一些分享, 多一些进步 733

CAN轴控制流【6041,6040】

【代码】CAN轴控制流【6041,6040】

cfqq1989的博客 1783

Dubbo服务调用链路追踪:从动态代理到集群容错源码解析

Dubbo的调用链路设计体现了高质量RPC框架的架构思想:通过动态代理实现透明化远程调用,通过集群容错保证系统可靠性,通过负载均衡实现流量优化。深入理解Dubbo调用链路的每个环节,对于构建高可用分布式系统具有重要意义。随着Dubbo 3.x在云原生领域的持续演进,其调用链路将进一步优化,为微服务架构提供更强大的支持。Thymeleaf与AJAX的有机结合为Java论坛系统提供了强大的动态交互能力。Thymeleaf作为服务器端模板引擎,提供了强大的数据渲染能力和自然的模板特性AJAX。

yang572150653的博客 569

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Dubbo 2.7 源码解析 - Dubbo的AOP源码解析、Dubbo的动态编译Compile源码解析

Apache Dubbo 2.7 是一个高性能、轻量级的开源微服务框架,它提供了服务自动发现、负载均衡、服务治理等功能。在理解Dubbo的AOP(面向切面编程)和动态编译(Compile)机制之前,我们先简要回顾一下这两个概念在Dubbo中的应用场景,然后深入到源码层面进行解析。

qq_33240556的博客 648

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Dubbo服务调用的动态代理和负载均衡

Dubbo服务调用的动态代理及负载均衡源码解析请参见:http://manzhizhen.iteye.com/blog/2314514

weixin_34400525的博客 236

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

【Dubbo源码深度解析】:透彻理解RPC底层通信机制

掌握Dubbo底层原理,高效构建分布式服务。本java dubbo框架教程深入解析RPC通信机制,涵盖服务暴露、引用、负载均衡与容错策略,适用于微服务架构实践。核心源码剖析+实战示例,助你全面提升调优能力,值得收藏。

PixelFlow的博客 811

Dubbo源码解读与实战-基础知识(下)

在前面我们介绍 Dubbo 简化架构的时候提到过,Dubbo Provider 在启动时会将自身的服务信息整理成 URL 注册到注册中心,Dubbo Consumer 在启动时会向注册中心订阅感兴趣的 Provider 信息,之后 Provider 和 Consumer 才能建立连接,进行后续的交互。可见,一个稳定、高效的注册中心对基于 Dubbo 的微服务来说是至关重要的。Dubbo 目前支持 Consul、etcd、Nacos、ZooKeeper、Redis 等多种开源组件作为注册中心,并且在 Dubb

小小博客 923

深入解析Dubbo的@Adaptive动态适配机制

在分布式服务框架中,动态适配机制是实现组件灵活扩展的核心技术。Dubbo框架通过@Adaptive注解实现了基于URL参数的运行时动态适配,这种机制本质上是适配器模式的典型应用。从技术原理看,@Adaptive会触发动态代码生成过程,利用Javassist等字节码工具在内存中创建适配类,然后通过SPI机制加载具体实现。这种设计既保持了接口的稳定性,又提供了实现的可替换性,特别适合协议切换、负载均衡策略等需要运行时决策的场景。在实际工程中,合理使用@Adaptive可以显著提升Dubbo扩展点的灵活性,同时需

weixin_42116058的博客 123

java-reader手写框架篇:手写Jedis、easy-dubbo与简易MVC,彻底内化框架灵魂

**java-reader** 是一位资深Java工程师沉淀了300多篇原创笔记的学习历程仓库,覆盖算法、Java基础、框架实战、源码解析与中间件。而其中最能体现"深度"的部分,是**手写框架篇**:从零手写 Jedis 客户端与连接池、实现一个类 Dubbo 的 RPC 框架 easy-dubbo、以及一个简易 MVC 框架 easy-springmvc。本文带你快速理解这4个手写项目的核心思想

gitblog_00324的博客 326

从源码全面解析 dubbo 服务暴露的来龙去脉

对于 Java 开发者而言,关于 dubbo ,我们一般当做黑盒来进行使用,不需要去打开这个黑盒。但随着目前程序员行业的发展,我们有必要打开这个黑盒,去探索其中的奥妙。本期 dubbo 源码解析系列文章,将带你领略 dubbo 源码的奥秘。本期源码文章吸收了之前 Spring、Kakfa、JUC源码文章的教训,将不再一行一行的带大家分析源码,我们将一些不重要的部分当做黑盒处理,以便我们更快、更有效的阅读源码。虽然现在是互联网寒冬,但乾坤未定,你我皆是黑马!

爱敲代码的小黄 2821

从源码全面解析 dubbo 服务订阅的来龙去脉

对于 Java 开发者而言,关于 dubbo ,我们一般当做黑盒来进行使用,不需要去打开这个黑盒。但随着目前程序员行业的发展,我们有必要打开这个黑盒,去探索其中的奥妙。本期 dubbo 源码解析系列文章,将带你领略 dubbo 源码的奥秘。本期源码文章吸收了之前 Spring、Kakfa、JUC源码文章的教训,将不再一行一行的带大家分析源码,我们将一些不重要的部分当做黑盒处理,以便我们更快、更有效的阅读源码。虽然现在是互联网寒冬,但乾坤未定,你我皆是黑马!

爱敲代码的小黄 2371

Dubbo源码解读之动态代理

前言 或许我们已悉知Java的动态代理的方式:jdk——通过接口中的方法名,在动态生成的代理类中调用业务实现类的同名方法;cglib——通过继承业务类,生成的动态代理类是业务类的子类,通过重写业务方法进行代理。dubbo在沿用java的jdk方式外,还采取了javassist方式——通过字节码生成代替反射。 Dubbo代理概览 类图(这里只包括我们比较常用的代理类) 从类图我们可以看出Dubbo...

qq_30051265的博客 4821

从源码全面解析 dubbo 消费端服务调用的来龙去脉

对于 Java 开发者而言,关于 dubbo ,我们一般当做黑盒来进行使用,不需要去打开这个黑盒。但随着目前程序员行业的发展,我们有必要打开这个黑盒,去探索其中的奥妙。本期 dubbo 源码解析系列文章,将带你领略 dubbo 源码的奥秘。本期源码文章吸收了之前 Spring、Kakfa、JUC源码文章的教训,将不再一行一行的带大家分析源码,我们将一些不重要的部分当做黑盒处理,以便我们更快、更有效的阅读源码。虽然现在是互联网寒冬,但乾坤未定,你我皆是黑马!

爱敲代码的小黄 2484
上一篇: Dubbo源码(5)-领域模型及调用流程
下一篇: 数理统计及概率论-核心知识总结
BoringRong
BoringRong 领域专家: 后端开发技术领域 领域专家: 后端开发技术领域
博客等级 码龄9年 2万+粉丝 386原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BoringRong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值