Dubbo兼容Springcloud发布组件。Feign 插件,使Dubbo可以消费spring cloud 服务,同时构建基于dubbo的rest服务...

该协议主要是为了支持老项目可以消费springcloud提供的接口,并可以利用dubbo的服务发现,构建出一个springboot rest集群, dubbo与springboot结合时,不需要dubbo再次导出rest服务。而是由springboot提供rest服务dubbo端只负责注册,构建服务目录。

Git: spring-boot-starter-dubbo Example: dubbo-demo

###依赖jar包

<!--Feign 支持-->
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>

###核心代码


public class FeignProtocol extends AbstractProxyProtocol {


    private static ObjectFactory<HttpMessageConverters> objectFactory = new ObjectFactory<HttpMessageConverters>() {
        [@Override](https://my.oschina.net/u/1162528)
        public HttpMessageConverters getObject() throws BeansException {
            return getApplicationContext().getBean(HttpMessageConverters.class);
        }
    };

    protected <T> Runnable doExport(T impl, final Class<T> type, URL url) throws RpcException {

        //不做任何操作,由springboot对外提供该服务,dubbo只负责注册服务
        return new Runnable() {
            [@Override](https://my.oschina.net/u/1162528)
            public void run() {
                RequestMappingHandlerMapping requestMappingHandlerMapping = getApplicationContext().getBean(RequestMappingHandlerMapping.class);
                Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestMappingHandlerMapping.getHandlerMethods();
                for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethods.entrySet()) {
                    Object bean = entry.getValue().getBean();
                    if (type.isAssignableFrom(AopUtils.getTargetClass(bean))) {
                        requestMappingHandlerMapping.unregisterMapping(entry.getKey());
                    }
                }
            }
        };
    }

    protected <T> T doRefer(Class<T> type, URL url) throws RpcException {

        int timeout = url.getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);
        int connections = url.getParameter(Constants.CONNECTIONS_KEY, 20);
        int retries = url.getParameter(Constants.RETRIES_KEY, 0);

        String schema = "http://";
        if (url.getPort() == 443 || url.getPort() == 8433) {
            schema = "https://";
        }

        String api = schema + url.getHost() + ":" + url.getPort();

        FeignClient feignClient = type.getAnnotation(FeignClient.class);

        if (feignClient != null) {
            //如果feign注解携带url,将以url为准
            if (!StringUtils.isBlank(feignClient.url())) {
                api = getEnvironment().resolvePlaceholders(feignClient.url());
            }

            if (!StringUtils.isBlank(feignClient.path())) {
                api = api + ("/" + feignClient.path()).replaceAll("[/]+", "/");
            }
        }

        return target(api, type, connections, timeout, retries);
    }


    public int getDefaultPort() {
        //该端口与springboot保持一致
        String port = getEnvironment().resolvePlaceholders("${server.port}");
        return !StringUtils.isBlank(port) ? Integer.parseInt(port) : 8080;
    }

    public static <T> T target(String url, Class<T> type) {
        return target(url, type, 20, 3000, 0);
    }

    public static <T> T target(String url, Class<T> type, int connections, int timeout, int retries) {
        SSLContext sslContext = SSLContexts.createSystemDefault();
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.INSTANCE)
                .register("https", new SSLConnectionSocketFactory(sslContext))
                .build();

        PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(timeout)
                .setSocketTimeout(timeout)
                .build();

        CloseableHttpClient httpClient = HttpClientBuilder.create()
                .setConnectionManager(manager)
                .setDefaultRequestConfig(requestConfig)
                .setMaxConnPerRoute(connections)
                .setMaxConnTotal(connections)
                .setRetryHandler(new DefaultHttpRequestRetryHandler(0, true))
                .setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy())
                .build();
        return HystrixFeign.builder()
                .requestInterceptors(getApplicationContext().getBeansOfType(RequestInterceptor.class).values())
                .contract(new SpringMvcContract())
                .encoder(new SpringEncoder(objectFactory))
                .decoder(new SpringDecoder(objectFactory))
                .client(new ApacheHttpClient(httpClient))
                .errorDecoder(new ErrorDecoder.Default())
                .retryer(new Retryer.Default(100, 500, retries))
                .target(type, url);
    }

    @SuppressWarnings("unchecked")
    private static WebApplicationContext getApplicationContext() {
        Field contextsFiled = ReflectionUtils.findField(SpringExtensionFactory.class, "contexts");
        contextsFiled.setAccessible(true);
        for (ApplicationContext applicationContext : (Set<ApplicationContext>) ReflectionUtils.getField(contextsFiled, null)) {
            if (applicationContext instanceof WebApplicationContext) {
                return (WebApplicationContext) applicationContext;
            }
        }
        throw new RpcException("not find webApplicationContext!");
    }

    private static Environment getEnvironment() {
        return getApplicationContext().getEnvironment();
    }

}

###exmaple


@Value("${server.port}")
private int port;

//服务端,多协议发布服务
[@Bean](https://my.oschina.net/bean)
public ServiceBean<UserService> userServiceServiceBean(@Autowired UserService userService) {
    ServiceBean<UserService> serviceBean = new ServiceBean<UserService>();
    serviceBean.setInterface(UserService.class);
    serviceBean.setRef(userService);
    serviceBean.setProtocols(Arrays.asList(new ProtocolConfig("dubbo"), new ProtocolConfig("feign", port)));
    return serviceBean;
}

[@Bean](https://my.oschina.net/bean)
//消费端,此种方式可以避免使用@Reference注解,保持与spring注解一致
public ReferenceBean<UserService> userService() {
    ReferenceBean<UserService> bean = new ReferenceBean<UserService>();
    bean.setInterface(UserService.class);
    return bean;
}

###接口

@FeignClient(path = "/user")
public interface UserService {

    @RequestMapping(value = "{id}", method = RequestMethod.GET)
    User findOne(@PathVariable(value = "id") Integer id);

    @RequestMapping(value = "{id}", method = RequestMethod.DELETE)
    void delete(@PathVariable(value = "id") Integer id);

    @RequestMapping(value = "/", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
    void save(@RequestBody User user);

    @RequestMapping(value = "/", method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE)
    void update(@RequestBody User user);

    @RequestMapping(value = "/findAll", method = RequestMethod.GET)
    List<User> findAll();

}

转载于:https://my.oschina.net/u/1774332/blog/876900

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值