欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Java是如何通過接口來創(chuàng)建代理并進行http請求

 更新時間:2021年06月11日 11:41:47   作者:你就像甜甜的益達  
今天給大家?guī)淼闹R是關(guān)于Java的,文章圍繞Java是如何通過接口來創(chuàng)建代理并進行http請求展開,文中有非常詳細的介紹及代碼示例,需要的朋友可以參考下

場景

現(xiàn)在想要做這么一個事情,公司的dubbo服務(wù)都是內(nèi)網(wǎng)的,但是提供了一個對外的出口,通過鏈接就能請求到對應(yīng)的dubbo服務(wù)。(具體怎么做的應(yīng)該就是個網(wǎng)關(guān),然后將http請求轉(zhuǎn)為dubbo請求,通過泛化調(diào)用去進行調(diào)用。代碼看不到。)現(xiàn)在為了方便測試,我需要將配置的接口,通過http請求去請求對應(yīng)的鏈接。

分析

項目的思想其實跟mybatis-spring整合包的思想差不多,都是生成代理去執(zhí)行接口方法。
http://www.dbjr.com.cn/article/153378.htm
項目是個簡單的spring項目就行了,然后項目引入項目的api,然后通過配置對應(yīng)的服務(wù)名稱,通過spring生成代理,注入spring容器,然后執(zhí)行方法就是根據(jù)對應(yīng)的域名+接口全路徑+方法名去進行請求,參數(shù)是json。為了方便項目使用了hutool工具類,直接使用fastjson去進行序列化。

操作

首先創(chuàng)建工廠bean,就是用來返回代理的FactoryBean

import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.Proxy;

/**
 * @Title:相對于BeanFactory這個大工廠,這是一個小工廠,專門用于創(chuàng)建某種類型的bean(默認創(chuàng)建的是單例bean)
 * @Description 創(chuàng)建代理對象
 * @Version
 */
public class HttpProxyFactoryBean<T> implements FactoryBean<T> {

    /**
     *【注意】
     * 這里之所以可以進行自動裝配,是因為當(dāng)前的這個HttpProxyFactoryBean是會被注冊到Spring中的
     * 只不過它的注冊方式 跟一般的不一樣(一般會在類上,加一個如@Component、@Service這樣的注解 )
     * 它是通過注冊BeanDefinition的方式注冊的,可能會注冊多個,而其中的每一個HttpProxyFactoryBean實例都會被自動裝配同一個HttpProxyInvocationHandler實例
     *
     * 也有等價的做法是:
     * 利用ApplicationContextAware接口的setApplicationContext獲取到applicationContext,
     * 然后把applicationContext 作為屬性設(shè)置到當(dāng)前類中
     *  再利用applicationContext的getBean方法來獲取InvocationHandler的實例
     */
    @Autowired
    private HttpProxyInvocationHandler httpProxyInvocationHandler;

    private Class<T> rpcInterface;

    public HttpProxyFactoryBean(Class<T> rpcInterface){
        this.rpcInterface = rpcInterface;
    }


    @Override
    public T getObject() throws Exception {
        //這里應(yīng)該放ComputerService接口
        return (T)Proxy.newProxyInstance(rpcInterface.getClassLoader(),new Class[]{rpcInterface} ,httpProxyInvocationHandler);
    }

    @Override
    public Class<?> getObjectType() {
        return rpcInterface;
    }

}

每一個動態(tài)代理類都必須要實現(xiàn)InvocationHandler這個接口

每一個動態(tài)代理類都必須要實現(xiàn)InvocationHandler這個接口,并且每個代理類的實例都關(guān)聯(lián)到了一個handler,當(dāng)我們通過代理對象調(diào)用一個方法的時候,這個方法的調(diào)用就會被轉(zhuǎn)發(fā)為由InvocationHandler這個接口的 invoke 方法來進行調(diào)用。

我們可以直接將實現(xiàn)InvocationHandler的實現(xiàn)類注入spring容器中,然后每一個接口走同一個innvoke方法,當(dāng)然也可以每一個都new一個,然后可以在構(gòu)造方法中塞入特定的一些參數(shù)。我這邊因為對應(yīng)的每一個代理沒啥特殊的就走同一個了:
定義一些參數(shù),請求的urlproxy.serverUrl,和請求添加的項目,proxy.project

import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description 把服務(wù)方法的調(diào)用轉(zhuǎn)換為對遠程服務(wù)的http請求
 * @Version
 */
@Component
public class HttpProxyInvocationHandler implements InvocationHandler {

    @Value("${proxy.serverUrl}")
    private String serverUrl;

    @Value("${proxy.project}")
    private String serverProject;

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Class<?> declaringClass = method.getDeclaringClass();
        if (Object.class.equals(declaringClass)) {
            return method.invoke(this, args);
        }

        String methodName = method.getName();
        String name = method.getDeclaringClass().getName();

        //拼接請求地址
        String url = serverUrl + name + "/" + methodName;
//        String url = "http://test:8080/soa/com.rdd.TestService/createActivity";
        HashMap<String, String> paramMap = new HashMap<>();
    
//        String result = HttpRequest.post(url).headerMap(paramMap, true).body("[" + JSONObject.toJSONString(args) + "]").execute().body();
        String result = HttpRequest.post(url).headerMap(paramMap, true).body(JSONObject.toJSONString(args)).execute().body();

        System.out.println(">>>" + url + "的響應(yīng)結(jié)果為:" + result);

        //將響應(yīng)結(jié)果轉(zhuǎn)換為接口方法的返回值類型
        Class<?> returnType = method.getReturnType();
        if (returnType.isPrimitive() || String.class.isAssignableFrom(returnType)) {
            if (returnType == int.class || returnType == Integer.class) {
                return Integer.valueOf(result);
            } else if (returnType == long.class || returnType == Long.class) {
                return Long.valueOf(result);
            }
            return result;
        } else if (Collection.class.isAssignableFrom(returnType)) {
            return JSONArray.parseArray(result, Object.class);
        } else if (Map.class.isAssignableFrom(returnType)) {
            return JSON.parseObject(result, Map.class);
        } else {
            return JSONObject.parseObject(result, returnType);
        }
    }
}

最后后將對應(yīng)的工廠bean封裝成bean定義,注入到spring容器中

我們的接口一般都是jar形式的,我就簡單的寫在一個proxy.txt文件中,然后去讀取對應(yīng)的接口全路徑,注入到spring容器中,當(dāng)然也可以通過掃描某個包,自定義注解等等方式實現(xiàn)。

import cn.hutool.core.io.file.FileReader;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.*;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @Title:bean工廠的后置處理器,用于動態(tài)注冊bean
 * @Date 2021/3/23 10:13
 * @Description
 * @Version
 */
@Component
@PropertySource("classpath:application.properties")
public class HttpProxyRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    /**
     * 該方法用來注冊更多的bean到spring容器中
     *
     * @param beanDefinitionRegistry
     * @throws BeansException
     */
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        //默認UTF-8編碼,可以在構(gòu)造中傳入第二個參數(shù)做為編碼
        FileReader fileReader = new FileReader("proxy.txt");
        List<String> classStrList = fileReader.readLines();
        Set<Class<?>> proxyClazzSet = new HashSet<>();
        for (String s : classStrList) {
            if (StringUtils.isBlank(s)) {
                continue;
            }
            try {
                Class<?> aClass = Class.forName(s);
                proxyClazzSet.add(aClass);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }

        for (Class<?> targetClazz : proxyClazzSet) {
            BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(targetClazz);
            GenericBeanDefinition definition = (GenericBeanDefinition) beanDefinitionBuilder.getRawBeanDefinition();
            //設(shè)置構(gòu)造方法的參數(shù)  對于Class<?>,既可以設(shè)置為Class,也可以傳Class的完全類名
            //definition.getConstructorArgumentValues().addGenericArgumentValue(targetClazz);
            definition.getConstructorArgumentValues().addGenericArgumentValue(targetClazz.getName());

            //Bean的類型,指定為某個代理接口的類型
            definition.setBeanClass(HttpProxyFactoryBean.class);
            //表示 根據(jù)代理接口的類型來自動裝配
            definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
            beanDefinitionRegistry.registerBeanDefinition(targetClazz.getName(),definition);
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }
}

到此這篇關(guān)于詳解Java是如何通過接口來創(chuàng)建代理并進行http請求的文章就介紹到這了,更多相關(guān)java創(chuàng)建代理進行http請求內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論