文档章节

spring 集成 MetaQ

 逍遥`游
发布于 2017/03/31 10:48
字数 2244
阅读 101
收藏 0

service-metaq-config.xml(需要在web.xml<context-param>配置以便web启动的时候进行加载)

<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			classpath*:config/matrix.xml,
			classpath*:config/spring-config.xml,
			classpath*:config/spring-quartz.xml,
			classpath*:config/spring-transaction.xml,
			classpath*:config/spring-mybatis.xml,
			classpath*:config/dubbo-*.xml,
			classpath*:config/core-config.xml,
			classpath*:config/service-config.xml,
			classpath*:config/service-metaq-config.xml,
            classpath:config/codis-config.xml
		</param-value>
	</context-param>

1、配置消息会话工厂

在spring容器内配置metaqSessionFactory

<bean id="metaqSessionFactory" class="com.taobao.metamorphosis.client.extension.spring.MetaqMessageSessionFactoryBean">
       	<property name="zkConnect" value="${zkConnect}"/>
       	<property name="zkSessionTimeoutMs" value="${zkSessionTimeoutMs}"/>
      	<property name="zkConnectionTimeoutMs" value="${zkConnectionTimeoutMs}"/>
       	<property name="zkSyncTimeMs" value="${zkSyncTimeMs}"/>
    </bean>

主要是zookeeper参数配置,需要跟服务端的zk配置保持一致。更多参数参见AbstractMetaqMessageSessionFactory的javadoc。

2、消息转换器

MetaQ客户端提供了Java序列化实现的JavaSerializationMessageBodyConverter给你使用,你也可以自定义自己的消息body转换器,比如采用其他序列化协议,如protobufs,hessian等。配置一个消息body转换器,比如我们就使用Java序列化

<bean id="messageBodyConverter" class="com.xxx.metaq.hession.serializable.HessianMessageBodyConvert"/>

3、使用MetaqTemplate发送消息

<bean id ="metaqTemplate" class="com.taobao.metamorphosis.client.extension.spring.MetaqTemplate">    
       	<property name="messageSessionFactory" ref="metaqSessionFactory"/>
       	<property name="messageBodyConverter" ref="messageBodyConverter"/>
    </bean>

metaqTemplate用到了上面配置的metaqSessionFactory和messageBodyConverter,用来创建producer和转换消息体。

配置了metaqTemplate之后,你将可以在你要发送消息的JavaBean里引用这个对象,并使用它发送消息。

4、MessageBuilder创建消息并发送

创建一个发送metaq消息的类MetaqApiImpl

package com.xxx.metaq.api.impl;

import java.util.concurrent.Semaphore;

import javax.annotation.Resource;




import com.xxx.dlcommon.logger.Logger;
import com.xxx.dlcommon.logger.LoggerFactory;
import com.xxx.metaq.api.DlMetaqAPI;
import com.taobao.metamorphosis.client.extension.spring.MessageBuilder;
import com.taobao.metamorphosis.client.extension.spring.MetaqTemplate;
import com.taobao.metamorphosis.client.producer.SendMessageCallback;
import com.taobao.metamorphosis.client.producer.SendResult;

public class MetaqApiImpl implements DlMetaqAPI {
	
	private final static Logger logger = LoggerFactory.getLogger(MetaqApiImpl.class);
	private final static Semaphore permits = new Semaphore(2000);
	
	@Resource
	private MetaqTemplate metaqTemplate;
	
	public boolean syncSendMessage(Object message, String topic,String attribute){
		try {
			MessageBuilder builder = MessageBuilder.withTopic(topic).withBody(message).withAttribute(attribute);
			SendResult result  =  metaqTemplate.send(builder);
			this.printSendResult(result,topic,attribute);
			return result.isSuccess();
		} catch (InterruptedException e) {
			logger.error("同步推送metaq消息异常.", e);
		}
		return false;
	}

	public void asyncSendMessage(Object message, String topic,String attribute){
	    final String t = topic;
	    final String attr = attribute;
        while(true){
	        if (permits.tryAcquire()) {
	            try {
	            	MessageBuilder builder = MessageBuilder.withTopic(topic).withBody(message).withAttribute(attribute);
	            	metaqTemplate.send(builder, new SendMessageCallback() {
	                    public void onMessageSent(SendResult result) {
	                         printSendResult(result,t,attr);
	                    }
	                    public void onException(Throwable e) {
	                    	logger.error("异步推送metaq服务器响应异常.",e);
	                    }
	                });
	            	break;
	            }catch (Exception e) {
	            	logger.error("异步推送metaq消息异常", e);
	            }finally{
	            	permits.release();
	            }
	        }else{
	        	Thread.yield();
	        }
        }
	}
	private void printSendResult(SendResult result,String topic,String attr){
	    if(result !=null){
            logger.info("发送metaq消息服务器响应结果success=>{},topic=>{},attr=>{},offset=>{},partition=>{}",
                result.isSuccess(), topic, attr, result.getOffset(),
                (result.getPartition() != null ? result.getPartition().toString() : ""));
	    }else{
	        logger.info("发送metaq消息服务器响应结果为空.");
	    }
	}
}

注入到service-metaq-config.xml

<bean id="dlMetaqAPI" class="com.xxx.metaq.api.impl.MetaqApiImpl"></bean>

5、消息的订阅

<bean id="companyOrderCollection" class="com.taobao.metamorphosis.client.extension.spring.MetaqTopic">
		<property name="group" value="companyOrderCollection" />
		<property name="topic" value="orderdata" />
		<property name="maxBufferSize" value="1048576" />
	</bean>
	<bean id="companyOrderCommentCollection" class="com.taobao.metamorphosis.client.extension.spring.MetaqTopic">
		<property name="group" value="companyOrderCommentCollection" />
		<property name="topic" value="orderdata" />
		<property name="maxBufferSize" value="1048576" />
	</bean>

配置了订阅者的分组,想要订阅的topic以及maxBufferSize大小。

6、继承DefaultMessageListener

/**
 * 订单评价消息处理
 * @author lushuai
 *
 */
public class OrderCommentMsgListener extends DlMessageListener<OrderMessage>{
	
	private static final Logger       logger = LoggerFactory.getLogger(OrderCommentMsgListener.class);
	
	@Resource
	private DlOrderCommentAPI dlOrderCommentAPI;
	@Resource
	private DlorderServiceAPI dlorderServiceAPI;
	@Resource
	private DlBizBaseInfoAPI dlBizBaseInfoAPI;
    @Override
    public boolean filter(String arg0, Message arg1) {
        return true;
    }

    @Override
    public void recieveMessage(MetaqMessage<OrderMessage> message) {
        logger.info("single msg attribute------>" + message.getAttribute());
        logger.info("single msg body----------->" + message.getBody().toString());
        System.out.println("-------------->Single Received Message:"+message.getBody().toString());
        System.out.println("-------------->Single Received Message:"+message.getBody().getOrderNo());
        try {
        	//如果订单"完成",更新订单商品对应的常购信息
			if(null != message && null != message.getBody() && null != message.getBody().getOrderNo() && ("finish".equals(message.getAttribute()) || "update".equals(message.getAttribute()))){
			    ServiceResult<OrderDTO> serviceResult = dlorderServiceAPI.searchOrderByOrderId(message.getBody().getOrderNo());
			    Map<String, Object> mapParam = new HashMap<String, Object>();
                mapParam.put("orderNo", message.getBody().getOrderNo());
                //通过订单号获取订单评价表状态
                ServiceResult<List<DlOrderCommentDTO>> serviceResult1 = dlOrderCommentAPI.getOrderCommentDetailList(mapParam,
                        null);
			    if(serviceResult.getSuccess() && serviceResult.getResult() != null && serviceResult.getResult().getStatus().equals(OrderCommon.ORDER_HAVE_FINISH) && serviceResult1==null){  //判断如果是交易完成
			        DlOrderCommentDTO orderCommentDTO = new DlOrderCommentDTO();
			        orderCommentDTO.setBuyerId(serviceResult.getResult().getBuyerId());
			        orderCommentDTO.setSellerId(serviceResult.getResult().getSellerId());
			        Map<String, Object> map = new HashMap<String, Object>();
			        map.put("companyId", serviceResult.getResult().getBuyerId());
			        ServiceResult<DlBizBaseInfoDTO> result = dlBizBaseInfoAPI.getBizBaseInfo(map);
			        if(result.getSuccess() && result.getResult() != null){
			            orderCommentDTO.setBuyerType(result.getResult().getCompanyType().equals("S01")?"01":"02");
			        }
			        orderCommentDTO.setOrderNo(serviceResult.getResult().getOrderNo());
			        orderCommentDTO.setAmount(serviceResult.getResult().getAmount());
			        orderCommentDTO.setPlaceOrderTime(serviceResult.getResult().getDate()); //下单时间
                    orderCommentDTO.setFinishOrderTime(serviceResult.getResult().getConfirmDate()); //订单完成时间
			        dlOrderCommentAPI.addOrderComment(orderCommentDTO);
			    }
			}
		} catch (Exception e) {
			logger.error(e.getMessage());
		}
    }

    @Override
    public void recieveMessages(List<MetaqMessage<OrderMessage>> messages) {
    	try {
    		for(MetaqMessage<OrderMessage> message: messages){
                logger.info("multi msg------>" + message.getAttribute());
                logger.info("multi msg------>" + message.getBody().toString());
                System.out.println("-------------->Multi Received Message:"+message.getBody().toString());
                System.out.println("-------------->Multi Received Message:"+message.getBody().getOrderNo());
                if(null != message && null != message.getBody() && null != message.getBody().getOrderNo() && ("finish".equals(message.getAttribute()) || "update".equals(message.getAttribute()))){
                    ServiceResult<OrderDTO> serviceResult = dlorderServiceAPI.searchOrderByOrderId(message.getBody().getOrderNo());
                    Map<String, Object> mapParam = new HashMap<String, Object>();
                    mapParam.put("orderNo", message.getBody().getOrderNo());
                    //通过订单号获取订单评价表状态
                    ServiceResult<List<DlOrderCommentDTO>> serviceResult1 = dlOrderCommentAPI.getOrderCommentDetailList(mapParam,
                            null);
                    if(serviceResult.getSuccess() && serviceResult.getResult() != null && serviceResult.getResult().getStatus().equals(OrderCommon.ORDER_HAVE_FINISH) && serviceResult1.getResult()==null){  //判断如果是交易完成
                        DlOrderCommentDTO orderCommentDTO = new DlOrderCommentDTO();
                        orderCommentDTO.setBuyerId(serviceResult.getResult().getBuyerId());
                        orderCommentDTO.setSellerId(serviceResult.getResult().getSellerId());
                        //获取买家名称
                        Map<String, Object> map = new HashMap<String, Object>();
                        map.put("companyId", serviceResult.getResult().getBuyerId());
                        ServiceResult<DlBizBaseInfoDTO> result = dlBizBaseInfoAPI.getBizBaseInfo(map);
                        if(result.getSuccess() && result.getResult() != null){
                            orderCommentDTO.setBuyerType(result.getResult().getCompanyType().equals("S01")?"01":"02");
                            orderCommentDTO.setBuyerName(result.getResult().getCompanyName());
                            orderCommentDTO.setBuyerAreaCode(result.getResult().getRegAreaCode());
                        }
                        //获取卖家名称
                        map.clear();
                        map.put("companyId", serviceResult.getResult().getSellerId());
                        ServiceResult<DlBizBaseInfoDTO> result1 = dlBizBaseInfoAPI.getBizBaseInfo(map);
                        if(result1.getSuccess() && result1.getResult() != null){
                            orderCommentDTO.setSellerName(result1.getResult().getCompanyName());
                            orderCommentDTO.setSellerAreaCode(result1.getResult().getRegAreaCode());
                        }
                        orderCommentDTO.setCreatedPerson(CompanyCommon.OPERATING_PERSON);
                        orderCommentDTO.setUpdatedPerson(CompanyCommon.OPERATING_PERSON);
                        orderCommentDTO.setOrderNo(serviceResult.getResult().getOrderNo());
                        orderCommentDTO.setAmount(serviceResult.getResult().getAmount());
                        orderCommentDTO.setPlaceOrderTime(serviceResult.getResult().getDate()); //下单时间
                        orderCommentDTO.setFinishOrderTime(serviceResult.getResult().getConfirmDate()); //订单完成时间
                        dlOrderCommentAPI.addOrderComment(orderCommentDTO);
                    }
    	        }
        	}
		} catch (Exception e) {
			logger.error(e.getMessage());
		}
    }

}

 

/**
 * 消息消费监听器代替metaq Client提供的com.taobao.metamorphosis.client.extension.spring.DefaultMessageListener</br>
 * <tt>说明:</tt></br>
 * <tt>1.使用此监听器是原来的com.taobao.metamorphosis.client.extension.spring.MessageListenerContainer需要换成com.xxx.metaq.listener.DlMessageListenerContainer</tt></br>
 * <tt>2.通过配置isMultiple可实现是否批量触发消息给消费者。默认isMultiple=true。若消费者不需要批量消费消息。设置isMultiple=false即可(等同于使用com.taobao.metamorphosis.client.extension.spring.DefaultMessageListener)
 * 当isMultiple=false消费者必须实现{@link com.xxx.metaq.listener.DlMessageListener#recieveMessage(MetaqMessage)}</tt></br>
 * <tt>3.通过配置maxSize设置每次触发消息条数默认200条</tt></br>
 * <tt>4.通过waitTime设置等待时长默认500ms</tt></br>
 * <tt>5.建议当isMultiple=true,若不是特殊需要建议maxSize与waitTime使用默认值。同时分别实现{@link com.xxx.metaq.listener.DlMessageListener#recieveMessage(MetaqMessage)}与{@link com.xxx.metaq.listener.DlMessageListener#recieveMessages(List)}</br>
 * </tt>
 * <tt>6.{@link com.xxx.metaq.listener.DlMessageListener#filter(String, Message)}可实现消息过滤。若不需要过滤消息直接返回true,返回false表示当条消息不需要拉取到client</tt></br>
 *  <tt>示例代码</tt>
    <pre>
 *     class A extends DlMessageListener<Object>{
 *      public void recieveMessages(List<MetaqMessage<Object>> msgs) {
            logger.info("ticket接收到->" + msgs.size());
            this.dealWithMsg(msgs);
        }

        public void recieveMessage(MetaqMessage<Object> msg) {
            if (msg != null) {
                List<MetaqMessage<Object>> msgs = new ArrayList<MetaqMessage<Object>>();
                msgs.add(msg);
                this.dealWithMsg(new ArrayList<MetaqMessage<Object>>());
            }
        }
        
                    只消费消息Attribute是ticket的消息
        public boolean filter(String group, Message message) {
                return "ticket".equals(message.getAttribute());
        }
        
        private void dealWithMsg(List<MetaqMessage<Object>> msgs) {
                //            do something
        }
 *     }
 *  </pre>
 * @Filename: DlMessageListener.java
 * @Version: 1.0
 * @Author: WL
 * @date:2016年4月29日 下午5:19:41
 *
 */
public abstract class DlMessageListener<T> extends DefaultMessageListener<T>
                                                                            implements
                                                                            ConsumerMessageFilter,
                                                                            org.springframework.beans.factory.InitializingBean,
                                                                            DisposableBean,
                                                                            BeanNameAware {
    private MessageBodyConverter<?> messageBodyConverter;
    static final Logger             logger = LoggerFactory.getLogger(DefaultMessageListener.class);

    public abstract void recieveMessages(List<MetaqMessage<T>> msgs);

    public abstract void recieveMessage(MetaqMessage<T> msg);

    public abstract boolean filter(String group, Message message);

    /**
     * @param msg
     * @see com.taobao.metamorphosis.client.extension.spring.DefaultMessageListener#onReceiveMessages(com.taobao.metamorphosis.client.extension.spring.MetaqMessage)
     */
    @Override
    public void onReceiveMessages(MetaqMessage<T> msg) {
        logger.info("消息传到错误..");
        logger.info("msgId->" + msg.getId());
    }

    /**
     * @param name
     * @see org.springframework.beans.factory.BeanNameAware#setBeanName(java.lang.String)
     */
    @Override
    public void setBeanName(String name) {
        this.name = name;
    }

    /**
     * @param group
     * @param message
     * @return
     * @see com.taobao.metamorphosis.consumer.ConsumerMessageFilter#accept(java.lang.String, com.taobao.metamorphosis.Message)
     */
    @Override
    public boolean accept(String group, Message message) {
        return this.filter(group, message);
    }

    @Override
    public void recieveMessages(Message message) throws InterruptedException {

        if (this.messageBodyConverter != null) {
            try {
                T body = (T) this.messageBodyConverter.fromByteArray(message.getData());
                this.trigger(new MetaqMessage<T>(message, body));
                //                this.onReceiveMessages(new MetaqMessage<T>(message, body));
            } catch (Exception e) {
                logger.error(
                    "Convert message body from byte array failed,msg id is " + message.getId()
                            + " and topic is " + message.getTopic(), e);
                message.setRollbackOnly();
            }
        } else {
            this.trigger(new MetaqMessage<T>(message, null));
            //            this.onReceiveMessages(new MetaqMessage<T>(message, null));
        }
    }

    private void trigger(MetaqMessage<T> msg) {
        Lock lock = new ReentrantLock();
        try {
            //            lock.lock();
            if (this.isMultiple) {
                logger.debug("消费者[" + getName() + "]当前缓存消息记录数->" + message.size());
                try {
                    lock.lock();
                    if (message.size() == maxSize) {
                        logger.info("消费者[" + getName() + "]达到设置[" + maxSize + "]条数触发消息.");
                        this.releaseMessage();
                    }
                } catch (Exception e) {
                } finally {
                    lock.unlock();
                }
                message.add(msg);
                //启动后台线程
                await();
            } else {
                this.recieveMessage(msg);
            }
        } catch (Exception e) {
        } finally {
            //            lock.unlock();
        }
    }

    private void await() {
        try {
            if (mark.compareAndSet(false, true)) {
                logger.info("消费者[" + getName() + "]启动后台线程等待消息.");
                Runnable run = new Runnable() {
                    public void run() {
                        timeWorker();
                    }
                };
                getExecutor().execute(run);
            }
        } catch (Exception e) {
            logger.info("消费者[" + getName() + "]后台线程等待消息异常.", e);
        }
    }

    private void timeWorker() {
        long st = System.currentTimeMillis();
        long en = 0;
        long diff = 0;
        logger.info("消费者[" + getName() + "]设置超时时长为->" + waitTime);
        while (mark.get()) {
            if (diff >= waitTime && message.size() > 0 && mark.compareAndSet(true, false)) {
                logger.info("消费者[" + getName() + "]超过设置等待时间[" + waitTime + "]触发[" + message.size()
                            + "]消息.");
                releaseMessage();
                en = 0;
            }
            en = System.currentTimeMillis();
            diff = en - st;
        }
    }

    private void releaseMessage() {
        logger.info("消费者[" + getName() + "]开始释放缓存消息...");
        Lock lock = new ReentrantLock();
        try {
            lock.lock();
            logger.info("消费者[" + getName() + "]释放[" + message.size() + "]条消息.");
            if (message.size() > 0) {
                List<MetaqMessage<T>> temp = new ArrayList<MetaqMessage<T>>(message);
                message.clear();
                this.recieveMessages(temp);
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.info("消费者[" + getName() + "]释放缓存消息异常.", e);
        } finally {
            lock.unlock();
            logger.info("消费者[" + getName() + "]释放缓存消息完成.");
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        if (this.processThreads > 0) {
            this.executor = Executors.newFixedThreadPool(this.processThreads);
        }

    }

    @Override
    public void destroy() throws Exception {
        if (this.executor != null) {
            this.executor.shutdown();
            this.executor = null;
        }
    }

    @Override
    public Executor getExecutor() {
        return this.executor;
    }

    private AtomicBoolean                       mark           = new AtomicBoolean(false);

    private int                                 processThreads = -1;
    private ExecutorService                     executor;

    /**
     * 达到多条触发 默认200 仅当isMultiple=true 生效
     */
    private Integer                             maxSize        = 200;
    /**
     * 等待时间 默认500ms仅当isMultiple=true生效
     */
    private Long                                waitTime       = 500l;
    private ArrayBlockingQueue<MetaqMessage<T>> message        = new ArrayBlockingQueue<MetaqMessage<T>>(
                                                                   maxSize, true);
    /**
     * 是否多条触发 默认true
     */
    private Boolean                             isMultiple     = true;

    protected String                            name;

    /**
     * @param name
     * The name to set.
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * @return Returns the name
     */
    public String getName() {
        return name;
    }

    protected void setExecutor(ExecutorService executor) {
        this.executor = executor;
    }

    /**
     * 默认true
     */
    public void setIsMultiple(Boolean isMultiple) {
        this.isMultiple = isMultiple;
    }

    /**
     * 默认200大小
     * The maxSize to set.
     */
    public void setMaxSize(Integer maxSize) {
        this.maxSize = maxSize;
    }

    /**
     * 默认值 200ms
     * The waitTime to set.
     */
    public void setWaitTime(Long waitTime) {
        this.waitTime = waitTime;
    }

    /**
     * Returns the threads number for processing messages.
     * 
     * @return
     */
    public int getProcessThreads() {
        return this.processThreads;
    }

    public MessageBodyConverter<?> getMessageBodyConverter() {
        return this.messageBodyConverter;
    }

    public void setMessageBodyConverter(MessageBodyConverter<?> messageBodyConverter) {
        this.messageBodyConverter = messageBodyConverter;
    }

    /**
     * Set the threads number for processing messages.
     * 
     * @param processThreads
     */
    public void setProcessThreads(int processThreads) {
        if (processThreads < 0) {
            throw new IllegalArgumentException("Invalid processThreads value:" + processThreads);
        }
        this.processThreads = processThreads;
    }
}

 

onReceiveMessages收到的是封装Message后的MetaqMessage对象,
它会使用你配置的消息体转换器将byte数组转换成java.util.Date对象,
你可以直接通过getBody获取上文metaqTemplate例子中发送的日期对象。

7 、配置MessageListenerContainer

<bean id="companyOrderCollection" class="com.taobao.metamorphosis.client.extension.spring.MetaqTopic">
		<property name="group" value="companyOrderCollection" />
		<property name="topic" value="orderdata" />
		<property name="maxBufferSize" value="1048576" />
	</bean>
	<bean id="companyOrderCommentCollection" class="com.taobao.metamorphosis.client.extension.spring.MetaqTopic">
		<property name="group" value="companyOrderCommentCollection" />
		<property name="topic" value="orderdata" />
		<property name="maxBufferSize" value="1048576" />
	</bean>
	<bean id="orderMessageListener" class="com.xxx.dlcompany.service.util.OrderMessageConsumer">
		<property name="processThreads" value="10" />
	</bean>
	<bean id="orderCommentMessageListener" class="com.xxx.dlcompany.service.util.OrderCommentMsgListener">
		<property name="processThreads" value="10" />
	</bean>
	<bean id="listenerContainer" class="com.xxx.metaq.listener.DlMessageListenerContainer">
		<property name="messageSessionFactory" ref="metaqSessionFactory" />
		<property name="messageBodyConverter" ref="messageBodyConverter" />
		<property name="subscribers">
			<map>
				<entry key-ref="companyOrderCollection" value-ref="orderMessageListener" />
				<entry key-ref="companyOrderCommentCollection" value-ref="orderCommentMessageListener" />
			</map>
		</property>
	</bean>

 

© 著作权归作者所有

粉丝 1
博文 5
码字总数 20213
作品 0
大连
程序员
私信 提问
后台服务程序框架技术选型方案

后台服务程序框架技术选型方案 1.硬件环境 公司服务器 2.软件环境 2.1 操作系统 CentOS 7 2.2 反向代理/web服务器 Nginx 2.3 应用服务器 tomcat 2.4 数据库 mysql or oracle mysql oracle 现...

zzuqiang
2016/08/26
1K
0
Metamorphosis(Metaq)在项目中的使用

Metamorphosis(Metaq)在项目中的使用 metaq的wiki介绍参考如下:metaq-wiki;服务端下载地址:http://download.csdn.net/detail/facetoqiang/9595008 也可以在google资源库重下载(记得翻墙):...

zzuqiang
2016/08/04
246
0
从企业应用技术团队到互联网技术团队

互联网应用特点: 直接面向用户,用户数量不可控 业务简单 体验至上 性能至上 长期调整的产品 主线业务基本不变,附属业务很多,如价格调整,促销 新兴互联网应用大多从烧钱开始 产品要求快速...

闲大赋
2014/11/15
401
1
深入 Spring Boot : 快速集成 Dubbo + Hystrix

背景 Hystrix 旨在通过控制那些访问远程系统、服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。Hystrix具备拥有回退机制和断路器功能的线程和信号隔离,请求缓存和请求打包,以...

小致dad
2018/07/02
392
0
Spring Boot学习资源

Spring Boot 入门 http://blog.csdn.net/isea533/article/details/50278205 ---------------------------------------------------------- Spring Boot 静态资源处理 http://blog.csdn.net/c......

IamOkay
2017/02/17
442
0

没有更多内容

加载失败,请刷新页面

加载更多

一、docker 入坑(win10和Ubuntu 安装)

前言 终究还是绕不过去了,要学的知识真的是太多了,好在我们还有时间,docker 之前只闻其声,不曾真正的接触过,现在docker 越来越火,很多公司也都开始使用了。所以对于我们程序员而言,又...

quellanan2
24分钟前
4
0
AutoCompleteTextView

小技巧按菜单键 当菜单打开之前会调用onMenuOpened(int featereId,Menu menu),可以重写这个方法,弹出对话框或者Popmenu 再布局中添加控件AutoCompleteTextView. <AutoCompleteTextVie...

逆天游云
27分钟前
4
0
谷歌软件商店:推出5美元会员 可用数百个软件

腾讯科技讯,谷歌和苹果是全球两大智能手机操作系统的运营者,两家公司旗下分别拥有占据行业垄断地位的谷歌软件商店和苹果软件商店。据外媒最新消息,手机软件商店的商业模式正在发生一些变化...

linuxCool
50分钟前
3
0
RocketMQ 多副本前置篇:初探raft协议

Raft协议是分布式领域解决一致性的又一著名协议,主要包含Leader选举、日志复制两个部分。 温馨提示: 本文根据raft官方给出的raft动画进行学习,其动画展示地址:http://thesecretlivesofda...

中间件兴趣圈
50分钟前
3
0
elasticsearch 6.8.0 添加认证

1. 修改elasticsearch-6.8.0/config/elasticsearch.yml 最后添加一行:xpack.security.enabled: true 2. 初始化用户和密码 ./bin/elasticsearch-setup-passwords interactive 我这里初始化为......

coord
51分钟前
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部