注解的方式在如今的项目中因为他的简洁性愈来愈被大众所喜欢,在咱们集成dubbox的时候,发现dubbox支持了注解方式,可是在咱们在用注解式集成的时候,发现消费者的对象在没有注入进去,一直都是报空指针异常.java
代码以下:spring
/** * <p> * bug反馈业务接口 * </p> * * @author wangguangdong * @version 1.0 * @Date 2016年10月12日16:18:30 */@AuthAnnotation@Controllerpublic class BugReportResource { private static final Logger LOG = Logger.getLogger(BugReportResource.class); @Reference(version = "1.0.0",interfaceClass = BugReportService.class) BugReportService bugReportService; }
通过博主辛苦的查找缘由,后来终于找到问题所在:
在spirng进行实例扫描的时候根本没法识别dubbo中的注解@Reference ,同时,在dubbo扫描的时候也没法识别Spring @Controller ,因此两个框架的扫描顺序要排列好,若是先扫了controller,这时候把控制器都实例化好了,再扫dubbo的服务,就会出现空指针,由于在实例化的时候是没有对应的消费者的实例的,因此就会形成没法注入,这也就是为何在咱们调用消费者服务的时候会形成空指针.数据库
下面是博主编排成功的代码.express
<mvc:annotation-driven /> <!-- 查找xxx路径下全部@Controller 注释类,添加与项目相关的controller --> <dubbo:annotation package="XXX.XXX.XXX.controller" /> <context:component-scan base-package="XXX.XXX.XXX.controller"/>
而后在查阅资料以后,博主又发现了另外一种解决办法:
在一个spring对象中注入dubbo消费者实例,而后在controller中注入这个服务实例便可,这种方法不受dubbo和spirng扫描顺序的影响.其实在项目中咱们可能也会有这样的设计(有些的架构改进会进行这样的设计,好比我吧全部的服务细粒度化拆分,并做为提供者注册给dubbo的server,而后我在消费者端多架构一个组合服务层(业务编排service层),进行dubbo子服务的组合,再讲组合后的服务注入到controller中供业务侧使用)apache
@Component public class DubboSupport { @Reference(version = "1.0.0",interfaceClass = BugReportService.class) BugReportService bugReportService; public BugReportService getBugReportService(){ return bugReportService; } }
dubbo启动时默认有重试机制和超时机制,某些业务场景下,若是不注意配置超时和重试,可能会引发一些异常。架构
超时机制的规则是若是在必定的时间内,provider没有返回,则认为本次调用失败mvc
重试机制在出现调用失败时,会再次调用。若是在配置的调用次数内都失败,则认为这次请求异常,抛出异常。(dubbo默认重试2次)框架
若是出现超时,一般是业务处理太慢或者发送io阻塞,可在服务提供方执行:jstack PID > jstack.log 分析线程都卡在哪一个方法调用上,这里就是慢的缘由。若是这个服务接口不能调优性能,请将timeout设大。ide
DUBBO消费端设置超时时间须要根据业务实际状况来设定,若是设置的时间过短,一些复杂业务须要很长时间完成,致使在设定的超时时间内没法完成正常的业务处理。这样消费端达到超时时间,那么dubbo会进行重试机制,不合理的重试在一些特殊的业务场景下可能会引起不少问题,须要合理设置接口超时时间。性能
好比发送邮件,可能就会发出多份重复邮件,执行注册请求时,就会插入多条重复的注册数据。
(1)合理配置超时和重连的思路
对于核心的服务中心,去除dubbo超时重试机制,并从新评估设置超时时间。
业务处理代码必须放在服务端,客户端只作参数验证和服务调用,不涉及业务流程处理
(2)Dubbo超时和重连配置示例
<!-- 服务调用超时设置为6秒,超时不重试--> <dubbo:service interface="com.provider.service.DemoService" ref="demoService" retries="0" timeout="5000"/>
(3)Dubbo消费者端统一的超时和重连配置
<!--统一的消费者配置--> <dubbo:consumer timeout="30000" retries="0" version="1.0.0"/>
dubbo在调用服务不成功时,默认会重试2次。Dubbo的路由机制,会把超时的请求路由到其余机器上,而不是本机尝试,因此 dubbo的重试机器也能必定程度的保证服务的质量。可是若是不合理的配置重试次数,当失败时会进行重试屡次,这样在某个时间点出现性能问题,调用方再连续重复调用,系统请求变为正常值的retries倍,系统压力会大增,容易引发服务雪崩,须要根据业务状况规划好如何进行异常处理,什么时候进行重试。
在重试发送的时候也可能会出现这样的问题:
好比有一个bug反馈,可是由于数据库io瓶颈,这时候这个服务阻塞了,而后过了一会查看数据库里有3条除了id外剩下都同样的数据(id是在服务提供者里生成的,这里只作异常例子举例).
这就是重试机制下,业务不合理的设计所形成的坑,这时候咱们处理的方式有两种:
合理规划业务(例如id放在服务上游生成,数据库主键惟一的机制)
吧服务增长幂等性设置(例如接口中增长消息id)
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>4.2.5.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.8.4</version> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> </exclusion> <exclusion> <groupId>com.101tec</groupId> <artifactId>zkclient</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.6</version> </dependency> <dependency> <groupId>com.101tec</groupId> <artifactId>zkclient</artifactId> <version>0.7</version> </dependency>