1. 程式人生 > >dubbo的consumer代理的生成方式原始碼

dubbo的consumer代理的生成方式原始碼

dubbo的consumer只需要在配置檔案中配置一個介面的地址,並不需要這個介面有具體的實現類,就可以生成這個介面的代理,通過代理遠端呼叫provider中的方法。

和JDK還有CGlib不同,dubbo的consumer生成代理是通過dubbo中的一個com.alibaba.dubbo.common.bytecode.Proxy來生成的,使用了javassist工具來生成代理類的位元組碼。

如果在程式碼中使用

Object obj=ApplicationContextUtil.getBean("orderService");

可以發現obj的class並不是com.alibaba.dubbo.common.bytecode.Proxy,而是類似com.alibaba.dubbo.common.bytecode.Proxy26這樣的(後面的數字不一定是26),這個Proxy26就是最終生成的代理類,他的父類就是Object,但是有對應介面中的方法。

如果在程式碼中使用       

Map<String,BeanDefinition> map=ApplicationContextUtil.getBeanDefinitions();
BeanDefinition definition=map.get(service);
String className=definition.getBeanClassName();

可以看到className是com.alibaba.dubbo.config.spring.ReferenceBean。

dubbo在spring配置檔案中的配置可以是這樣的:

<dubbo:reference id="orderService" interface="test.orderService" protocol="dubbo" check="false"/>   

<dubbo >標籤是由com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler來解析的。

DubboNamespaceHandler類是這樣的

packagecom.alibaba.dubbo.config.spring.schema;
 
importcom.alibaba.dubbo.common.Version;
importcom.alibaba.dubbo.config.ApplicationConfig;
importcom.alibaba.dubbo.config.ConsumerConfig;
importcom.alibaba.dubbo.config.ModuleConfig;
importcom.alibaba.dubbo.config.MonitorConfig;
importcom.alibaba.dubbo.config.ProtocolConfig;
importcom.alibaba.dubbo.config.ProviderConfig;
importcom.alibaba.dubbo.config.RegistryConfig;
importcom.alibaba.dubbo.config.spring.AnnotationBean;
importcom.alibaba.dubbo.config.spring.ReferenceBean;
importcom.alibaba.dubbo.config.spring.ServiceBean;
 
importorg.springframework.beans.factory.xml.NamespaceHandlerSupport;
 
/**
 * DubboNamespaceHandler
 *
 * @author william.liangf
 * @export
 */
public class DubboNamespaceHandler extends NamespaceHandlerSupport {
 
    static {
        Version.checkDuplicate(DubboNamespaceHandler.class);
    }
 
    public void init() {
       registerBeanDefinitionParser("application", newDubboBeanDefinitionParser(ApplicationConfig.class, true));
       registerBeanDefinitionParser("module", newDubboBeanDefinitionParser(ModuleConfig.class, true));
       registerBeanDefinitionParser("registry", newDubboBeanDefinitionParser(RegistryConfig.class, true));
       registerBeanDefinitionParser("monitor", newDubboBeanDefinitionParser(MonitorConfig.class, true));
        registerBeanDefinitionParser("provider",new DubboBeanDefinitionParser(ProviderConfig.class, true));
       registerBeanDefinitionParser("consumer", newDubboBeanDefinitionParser(ConsumerConfig.class, true));
       registerBeanDefinitionParser("protocol", newDubboBeanDefinitionParser(ProtocolConfig.class, true));
       registerBeanDefinitionParser("service", newDubboBeanDefinitionParser(ServiceBean.class, true));
       registerBeanDefinitionParser("reference", newDubboBeanDefinitionParser(ReferenceBean.class, false));
       registerBeanDefinitionParser("annotation", newDubboBeanDefinitionParser(AnnotationBean.class, true));
    }
 
}
所以<dubbo:reference>對應的就是com.alibaba.dubbo.config.spring.ReferenceBean

ReferenceBean的定義是這樣的:

public class ReferenceBean<T> extends ReferenceConfig<T>
  implements FactoryBean,ApplicationContextAware, InitializingBean, DisposableBean
ReferenceBean實現了org.springframework.beans.factory.FactoryBean介面,因此ReferenceBean是一個FactoryBean,spring對FactoryBean不會直接構造他的實現類來作為代理類,而是通過FactoryBean的getObject()方法來獲得代理類。

ReferenceBean實現了org.springframework.beans.factory.InitializingBean介面,實現了這個介面的類需要實現afterPropertiesSet()方法,並且在初始化結束後呼叫該方法。dubbo的consumer的代理類也是在這個方法中生成。

 ReferenceBean的afterPropertiesSet()方法是這樣的:

   @SuppressWarnings({"unchecked"})
    public void afterPropertiesSet() throwsException {
        if (getConsumer() == null) {
            Map<String, ConsumerConfig>consumerConfigMap = applicationContext == null ? null :BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext,ConsumerConfig.class, false, false);
            if (consumerConfigMap != null&& consumerConfigMap.size() > 0) {
                ConsumerConfig consumerConfig =null;
                for (ConsumerConfig config :consumerConfigMap.values()) {
                    if (config.isDefault() ==null || config.isDefault().booleanValue()) {
                        if (consumerConfig !=null) {
                            throw newIllegalStateException("Duplicate consumer configs: " + consumerConfig+ " and " + config);
                        }
                        consumerConfig =config;
                    }
                }
                if (consumerConfig != null) {
                   setConsumer(consumerConfig);
                }
            }
        }
        if (getApplication() == null
                && (getConsumer() ==null || getConsumer().getApplication() == null)) {
            Map<String,ApplicationConfig> applicationConfigMap = applicationContext == null ? null: BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext,ApplicationConfig.class, false, false);
            if (applicationConfigMap != null&& applicationConfigMap.size() > 0) {
                ApplicationConfigapplicationConfig = null;
                for (ApplicationConfig config :applicationConfigMap.values()) {
                    if (config.isDefault() == null ||config.isDefault().booleanValue()) {
                        if (applicationConfig!= null) {
                            throw newIllegalStateException("Duplicate application configs: " +applicationConfig + " and " + config);
                        }
                        applicationConfig =config;
                    }
                }
                if (applicationConfig != null){
                   setApplication(applicationConfig);
                }
            }
        }
        if (getModule() == null
                && (getConsumer() ==null || getConsumer().getModule() == null)) {
            Map<String, ModuleConfig>moduleConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext,ModuleConfig.class, false, false);
            if (moduleConfigMap != null&& moduleConfigMap.size() > 0) {
                ModuleConfig moduleConfig =null;
                for (ModuleConfig config :moduleConfigMap.values()) {
                    if (config.isDefault() ==null || config.isDefault().booleanValue()) {
                        if (moduleConfig !=null) {
                            throw newIllegalStateException("Duplicate module configs: " + moduleConfig +" and " + config);
                        }
                        moduleConfig = config;
                    }
                }
                if (moduleConfig != null) {
                    setModule(moduleConfig);
                }
            }
        }
        if ((getRegistries() == null ||getRegistries().size() == 0)
                && (getConsumer() ==null || getConsumer().getRegistries() == null ||getConsumer().getRegistries().size() == 0)
                && (getApplication() ==null || getApplication().getRegistries() == null ||getApplication().getRegistries().size() == 0)) {
            Map<String, RegistryConfig>registryConfigMap = applicationContext == null ? null :BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext,RegistryConfig.class, false, false);
            if (registryConfigMap != null&& registryConfigMap.size() > 0) {
                List<RegistryConfig>registryConfigs = new ArrayList<RegistryConfig>();
                for (RegistryConfig config :registryConfigMap.values()) {
                    if (config.isDefault() ==null || config.isDefault().booleanValue()) {
                       registryConfigs.add(config);
                    }
                }
                if (registryConfigs != null&& registryConfigs.size() > 0) {
                   super.setRegistries(registryConfigs);
                }
            }
        }
        if (getMonitor() == null
                && (getConsumer() ==null || getConsumer().getMonitor() == null)
                && (getApplication() ==null || getApplication().getMonitor() == null)) {
            Map<String, MonitorConfig>monitorConfigMap = applicationContext == null ? null :BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext,MonitorConfig.class, false, false);
            if (monitorConfigMap != null&& monitorConfigMap.size() > 0) {
                MonitorConfig monitorConfig =null;
                for (MonitorConfig config :monitorConfigMap.values()) {
                    if (config.isDefault() ==null || config.isDefault().booleanValue()) {
                        if (monitorConfig !=null) {
                            throw newIllegalStateException("Duplicate monitor configs: " + monitorConfig +" and " + config);
                        }
                        monitorConfig = config;
                    }
                }
                if (monitorConfig != null) {
                    setMonitor(monitorConfig);
                }
            }
        }
        Boolean b = isInit();
        if (b == null && getConsumer()!= null) {
            b = getConsumer().isInit();
        }
        if (b != null &&b.booleanValue()) {
            getObject();
        }
}

主要是按照預設的配置初始化了一些屬性,最後呼叫了getObject()方法,得到代理類

getObject()方法:

 public Object getObject() throws Exception {
    return get();
  }

get()方法在ReferenceBean的父類com.alibaba.dubbo.config.ReferenceConfig中:

  public synchronized T get() {
    if (this.destroyed) {
      throw new IllegalStateException("Alreadydestroyed!");
    }
    if (this.ref == null) {
      init();
    }
    return this.ref;
  }
最後呼叫了init()方法:
    private void init() {
        if (initialized) {
            return;
        }
        initialized = true;
        if (interfaceName == null ||interfaceName.length() == 0) {
            throw newIllegalStateException("<dubbo:reference interface=\"\" />interface not allow null!");
        }
        // 獲取消費者全域性配置
        checkDefault();
        appendProperties(this);
        if (getGeneric() == null &&getConsumer() != null) {
           setGeneric(getConsumer().getGeneric());
        }
        if (ProtocolUtils.isGeneric(getGeneric())){
            interfaceClass =GenericService.class;
        } else {
            try {
                interfaceClass =Class.forName(interfaceName, true, Thread.currentThread()
                        .getContextClassLoader());
            } catch (ClassNotFoundException e){
                throw newIllegalStateException(e.getMessage(), e);
            }
           checkInterfaceAndMethods(interfaceClass, methods);
        }
        String resolve =System.getProperty(interfaceName);
        String resolveFile = null;
        if (resolve == null || resolve.length()== 0) {
            resolveFile =System.getProperty("dubbo.resolve.file");
            if (resolveFile == null ||resolveFile.length() == 0) {
                File userResolveFile = newFile(new File(System.getProperty("user.home")),"dubbo-resolve.properties");
                if (userResolveFile.exists()) {
                    resolveFile =userResolveFile.getAbsolutePath();
                }
            }
            if (resolveFile != null &&resolveFile.length() > 0) {
                Properties properties = newProperties();
                FileInputStream fis = null;
                try {
                    fis = newFileInputStream(new File(resolveFile));
                    properties.load(fis);
                } catch (IOException e) {
                    throw newIllegalStateException("Unload " + resolveFile + ", cause: "+ e.getMessage(), e);
                } finally {
                    try {
                        if (null != fis)fis.close();
                    } catch (IOException e) {
                       logger.warn(e.getMessage(), e);
                    }
                }
                resolve =properties.getProperty(interfaceName);
            }
        }
        if (resolve != null &&resolve.length() > 0) {
            url = resolve;
            if (logger.isWarnEnabled()) {
                if (resolveFile != null&& resolveFile.length() > 0) {
                    logger.warn("Usingdefault dubbo resolve file " + resolveFile + " replace " +interfaceName + "" + resolve + " to p2p invoke remoteservice.");
                } else {
                    logger.warn("Using -D"+ interfaceName + "=" + resolve + " to p2p invoke remoteservice.");
                }
            }
        }
        if (consumer != null) {
            if (application == null) {
                application =consumer.getApplication();
            }
            if (module == null) {
                module = consumer.getModule();
            }
            if (registries == null) {
                registries =consumer.getRegistries();
            }
            if (monitor == null) {
                monitor =consumer.getMonitor();
            }
        }
        if (module != null) {
            if (registries == null) {
                registries =module.getRegistries();
            }
            if (monitor == null) {
                monitor = module.getMonitor();
            }
        }
        if (application != null) {
            if (registries == null) {
                registries =application.getRegistries();
            }
            if (monitor == null) {
                monitor = application.getMonitor();
            }
        }
        checkApplication();
        checkStubAndMock(interfaceClass);
        Map<String, String> map = newHashMap<String, String>();
        Map<Object, Object> attributes =new HashMap<Object, Object>();
        map.put(Constants.SIDE_KEY,Constants.CONSUMER_SIDE);
        map.put(Constants.DUBBO_VERSION_KEY,Version.getVersion());
        map.put(Constants.TIMESTAMP_KEY,String.valueOf(System.currentTimeMillis()));
        if (ConfigUtils.getPid() > 0) {
            map.put(Constants.PID_KEY,String.valueOf(ConfigUtils.getPid()));
        }
        if (!isGeneric()) {
            String revision =Version.getVersion(interfaceClass, version);
            if (revision != null &&revision.length() > 0) {
                map.put("revision",revision);
            }
 
            String[] methods =Wrapper.getWrapper(interfaceClass).getMethodNames();
            if (methods.length == 0) {
                logger.warn("NO methodfound in service interface " + interfaceClass.getName());
                map.put("methods",Constants.ANY_VALUE);
            } else {
                map.put("methods",StringUtils.join(new HashSet<String>(Arrays.asList(methods)),","));
            }
        }
        map.put(Constants.INTERFACE_KEY,interfaceName);
        appendParameters(map, application);
        appendParameters(map, module);
        appendParameters(map, consumer,Constants.DEFAULT_KEY);
        appendParameters(map, this);
        String prifix =StringUtils.getServiceKey(map);
        if (methods != null &&methods.size() > 0) {
            for (MethodConfig method : methods){
                appendParameters(map, method,method.getName());
                String retryKey =method.getName() + ".retry";
                if (map.containsKey(retryKey)){
                    String retryValue =map.remove(retryKey);
                    if("false".equals(retryValue)) {
                        map.put(method.getName()+ ".retries", "0");
                    }
                }
                appendAttributes(attributes,method, prifix + "." + method.getName());
               checkAndConvertImplicitConfig(method, map, attributes);
            }
        }
        //attributes通過系統context進行儲存.
       StaticContext.getSystemContext().putAll(attributes);
        ref = createProxy(map);
}
init()方法把配置檔案中的配置項經過判斷和拼裝,最後全放到了一個map中,最後呼叫createProxy()方法來生成代理類:
   @SuppressWarnings({"unchecked","rawtypes", "deprecation"})
    private T createProxy(Map<String,String> map) {
        URL tmpUrl = new URL("temp","localhost", 0, map);
        final boolean isJvmRefer;
        if (isInjvm() == null) {
            if (url != null &&url.length() > 0) { //指定URL的情況下,不做本地引用
                isJvmRefer = false;
            } else if(InjvmProtocol.getInjvmProtocol().isInjvmRefer(tmpUrl)) {
                //預設情況下如果本地有服務暴露,則引用本地服務.
                isJvmRefer = true;
            } else {
                isJvmRefer = false;
            }
        } else {
            isJvmRefer =isInjvm().booleanValue();
        }
 
        if (isJvmRefer) {
            URL url = newURL(Constants.LOCAL_PROTOCOL, NetUtils.LOCALHOST, 0,interfaceClass.getName()).addParameters(map);
            invoker = refprotocol.refer(interfaceClass,url);
            if (logger.isInfoEnabled()) {
                logger.info("Using injvmservice " + interfaceClass.getName());
            }
        } else {
            if (url != null &&url.length() > 0) { // 使用者指定URL,指定的URL可能是對點對直連地址,也可能是註冊中心URL
                String[] us =Constants.SEMICOLON_SPLIT_PATTERN.split(url);
                if (us != null &&us.length > 0) {
                    for (String u : us) {
                        URL url =URL.valueOf(u);
                        if (url.getPath() ==null || url.getPath().length() == 0) {
                            url =url.setPath(interfaceName);
                        }
                        if(Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
                           urls.add(url.addParameterAndEncoded(Constants.REFER_KEY,StringUtils.toQueryString(map)));
                        } else {
                           urls.add(ClusterUtils.mergeUrl(url, map));
                        }
                    }
                }
            } else { // 通過註冊中心配置拼裝URL
                List<URL> us =loadRegistries(false);
                if (us != null &&us.size() > 0) {
                    for (URL u : us) {
                        URL monitorUrl =loadMonitor(u);
                        if (monitorUrl != null){
                           map.put(Constants.MONITOR_KEY, URL.encode(monitorUrl.toFullString()));
                        }
                       urls.add(u.addParameterAndEncoded(Constants.REFER_KEY,StringUtils.toQueryString(map)));
                    }
                }
                if (urls == null || urls.size()== 0) {
                    throw newIllegalStateException("No such any registry to reference " +interfaceName + " on the consumer " + NetUtils.getLocalHost() +" use dubbo version " + Version.getVersion() + ", please config<dubbo:registry address=\"...\" /> to your springconfig.");
                }
            }
 
            if (urls.size() == 1) {
                invoker =refprotocol.refer(interfaceClass, urls.get(0));
            } else {
                List<Invoker<?>>invokers = new ArrayList<Invoker<?>>();
                URL registryURL = null;
                for (URL url : urls) {
                    invokers.add(refprotocol.refer(interfaceClass,url));
                    if(Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
                        registryURL = url; // 用了最後一個registry url
                    }
                }
                if (registryURL != null) { // 有 註冊中心協議的URL
                    // 對有註冊中心的Cluster 只用AvailableCluster
                    URL u =registryURL.addParameter(Constants.CLUSTER_KEY, AvailableCluster.NAME);
                    invoker = cluster.join(newStaticDirectory(u, invokers));
                } else { // 不是 註冊中心的URL
                    invoker = cluster.join(newStaticDirectory(invokers));
                }
            }
        }
 
        Boolean c = check;
        if (c == null && consumer != null){
            c = consumer.isCheck();
        }
        if (c == null) {
            c = true; // default true
        }
        if (c &&!invoker.isAvailable()) {
            throw newIllegalStateException("Failed to check the status of the service " +interfaceName + ". No provider available for the service " + (group== null ? "" : group + "/") + interfaceName + (version ==null ? "" : ":" + version) + " from the url " +invoker.getUrl() + " to the consumer " + NetUtils.getLocalHost() +" use dubbo version " + Version.getVersion());
        }
        if (logger.isInfoEnabled()) {
            logger.info("Refer dubboservice " + interfaceClass.getName() + " from url " +invoker.getUrl());
        }
        // 建立服務代理
        return (T)proxyFactory.getProxy(invoker);
    }

createProxy()方法載入了和註冊中心有關的配置,其中還區分了是否是本地jvm的服務,如果本地有服務,那就直接用本地的。

 最後呼叫proxyFactory.getProxy(this.invoker)方法來生成代理類

proxyFactory是com.alibaba.dubbo.rpc.ProxyFactory介面的實現類,預設由com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory類來實現,他的getProxy()方法來自他的父類com.alibaba.dubbo.rpc.proxy.AbstractProxyFactory:

    public <T> TgetProxy(Invoker<T> invoker) throws RpcException {
        Class<?>[] interfaces = null;
        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) {
                interfaces = newClass<?>[types.length + 2];
                interfaces[0] =invoker.getInterface();
                interfaces[1] =EchoService.class;
                for (int i = 0; i <types.length; i++) {
                    interfaces[i + 1] =ReflectUtils.forName(types[i]);
                }
            }
        }
        if (interfaces == null) {
            interfaces = newClass<?>[]{invoker.getInterface(), EchoService.class};
        }
        return getProxy(invoker, interfaces);
}

最後的getProxy()方法在AbstractProxyFactory中是個抽象方法,實現的方法在子類JavassistProxyFactory中:
    @SuppressWarnings("unchecked")
    public <T> TgetProxy(Invoker<T> invoker, Class<?>[] interfaces) {
        return (T)Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
    }

這裡生成了代理類並建立了代理物件,可以在程式碼中引用,比如這樣:
public class OrderController {
    @Autowired
    private OrderService orderService;
    public void testDubboService() throws Exception{
       orderService.selectByOrderId();
    }
}


相關推薦

dubbo的consumer代理生成方式原始碼

dubbo的consumer只需要在配置檔案中配置一個介面的地址,並不需要這個介面有具體的實現類,就可以生成這個介面的代理,通過代理遠端呼叫provider中的方法。 和JDK還有CGlib不同,dubbo的consumer生成代理是通過dubbo中的一個com.aliba

dubbo原始碼分析-consumer端1-consumer代理生成

        dubbo(官網地址)是一個分散式服務框架,致力於提供高效能和透明化的RPC遠端服務呼叫方案,是阿里巴巴SOA服務化治理方案的核心框架。目前,阿里巴巴內部已經不再使用dubbo,但對很對未到一定量級的公司來說,dubbo依然是一個很好的選擇。        

AOP代理物件生成方式

1 AbstractAutoProxyCreator 類分析 /** * Create a proxy with the

數據庫主鍵生成方式 轉http://blog.csdn.net/w183705952/article/details/7102920

digg .com 表示 加鎖 -m 之間 sequence 權力 ont 1) assigned主鍵由外部程序負責生成,無需Hibernate參與。2) hilo通過hi/lo 算法實現的主鍵生成機制,需要額外的數據庫表保存主鍵生成歷史狀態。3) seqhilo與hilo

hibernate 主鍵生成方式

程序 操作 外部 解鎖 數據庫表 body 要求 讀寫 字符串表 1)assigned主鍵由外部程序負責生成,無需Hibernate參與。2)hilo通過hi/lo 算法實現的主鍵生成機制,需要額外的數據庫表保存主鍵生成歷史狀態。3)seqhilo與hilo 類似,通過hi

python時間生成方式

%x ear 程序 sta 指定 utc時間 一個 utc 大小 程序 第一版 #coding=utf-8 import time def get_year_mon_day(): time_array = time.localtime() result= u

獲取動態代理生成的.class文件

clas htm 插入 www. syntax 父類 系統 實現類 error 生成代理類,並寫入硬盤:配置系統屬性sun.misc.ProxyGenerator.saveGeneratedFile為true,代理類生成時將自動將生成的代理類寫入硬盤 ? 1 2

webservice客戶端生成方式

IE ide lib 自動 返回 client idea pro 選項 1.idea中File-new-Project 在彈出框中選擇java選項,選擇WebServices Client, 2.選擇Use library: 在本地中找到相關的lib包使用 (1)axi

Maven基礎(3):代理設定方式

在很多場景下,maven不能直接訪問到外網時,使用代理是其中常見的一種方式。這篇文章整理一下常見的maven中設定代理的方法。 代理伺服器 代理伺服器的搭建,可以使用nginx,或者更為專業一點的使用squid,輕鬆實現http和https方式。具體方式可以參看如下文章:

嵌入式裝置LCD模組漢字型檔檔案生成方式

近期有專案需要用的LCD顯示沐足顯示一些中文,對比了下帶字型檔的模組要比不帶字型檔的模組要貴得多,想想那就自己建立字型檔吧,能剩下不少費用,再說裝置內部的FLASH大把的容量,不利用也有點浪費了。 下文轉載自:http://www.rationmcu.com/elecjc/356.html

keras實現DCGAN生成mnist原始碼

演算法原理 具體演算法原理,在這裡不再闡述,可以參考: https://blog.csdn.net/stdcoutzyx/article/details/53872121 https://ask.julyedu.com/question/7681 基於keras的原始碼 fr

子集生成方式

1.增量構造法 void print_subset(int n, int* A, int cur) { for (int i = 0; i < cur; i++)printf("%d ", A[i]);//列印當前集合 printf("\n"); int s = cur ? A[cu

C#——後臺管理端多級選單的生成方式

現在大多的應用程式(後端)都有選單,不管是在左側還是上面,介面基本都是基於現有的UI框架或者網上找的單獨的選單的外掛。而實現的方式,大部分都是使用的AJAX形式來完成。前段時間,在總結一些過往的專案時,發現了一些不同的實現的方式,這裡想總結一下。所以也就有了這篇文章~~ 我建立的測試Demo

以太坊HD錢包地址生成方式

使用nodeJs生成以太坊HD錢包地址 程式碼 var bip39 = require('bip39') var hdkey = require('ethereumjs-wallet/hdkey') var util = require('ethereumjs-util') v

【轉】支付寶 二維碼/轉賬碼/生成方式,突破二維碼生成數量的限制

支付寶收款的幾種方式: 通過xposed 設定金額/備註.然後可以得到一張二維碼.這是傳統的方式. 通過支付寶的介面,自己拼接字串.然後根據字串生成一個二維碼對於 對於傳統方式.支付寶限制了一天二維碼的生成數量.在這之間簡直是好用得不要不要得.但是突然間支付寶爸爸說.你搞那麼多二維碼幹啥.還

CGLIB動態代理示例與原始碼解析

1. 原理,代理模式 代理模式的本質:呼叫方--->代理方--->實現方。 1.1 動態代理模式步驟       生成代理類二進位制位元組碼,可配置引數生成檔案。       classloader load二進位制位元組碼,生成Class物件( 可使

同學們自行調研Linux下軟體安裝的幾種方式(原始碼安裝, rpm安裝, yum安裝). 重點要理解rpm安裝和yum安裝的區別.

一、原始碼安裝 原始碼安裝的步驟就是:編譯原始碼,然後安裝 1.1 安裝準備 a. 首先用yum安裝gcc,用於編譯原始碼 b. 官網下載原始碼包 c. winSCP windows與linux傳輸檔案(如果直接用要安裝軟體的linux電腦下載就不用傳輸了) 1

Mybatis 學習筆記(三)——使用Mapper代理方式實現資料增刪改查

一、介紹   Mapper代理的方式只需要程式設計師編寫 Mapper.xml 檔案及 Mapper介面。   本文是基於上一篇文章:Mybatis 學習筆記——原生DAO實現資料增刪改查,所以接下來的內容是以其為基礎的,如果有什麼不懂的請留言或檢視上一篇。所

支付寶免籤不可改備註(支付寶 二維碼/轉賬碼/生成方式,微信收款維碼)

支付寶 二維碼/轉賬碼/生成方式,微信收款維碼 先介紹下支付寶收款的幾種方式: 通過xposed 設定金額/備註.然後生成二維碼.(受支付寶限制一天二維碼的生成數量20個) 通過支付寶的介面,自己拼接字串.然後根據字串生成一個二維碼對於(可改備註,使用者改備註則會掉單) 下面就是我們的改備註

支付寶免籤、解決最新版支付寶10.1.50拉起問題!(支付寶 二維碼/轉賬碼/生成方式,微信收款維碼)

已解決最新版支付寶(10.1.50)部分機型拉不起支付寶問題。 微信,支付寶,收款二維碼實時生成,訂單監控,免籤支,付支付系統,個人收款,收款二維碼 微信和支付寶個人支付二維碼生成與監控!有JAVA介面回撥,個人收款好助手! 實現收款即時到個人微信或支付寶賬戶!方便安全。 這