首先,项目先改造为spring boot工程
建议,采用下列方式引入spring boot依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
相关的依赖通过spring boot的pom.xml内置的版本进行管理,最大化保证jar相互兼容。
建议配置采用yml进行管理
通过yml的方式声明的方式,原本的注入@value
或者通过springEL语法${}
都是可以兼容使用。
除此之外,可以新增一种以对象注入的方式
约定配置
公共配置application.yml
存放/src/main/resources/
各个环境配置application-${profile}.yml
存放/src/main/resources/profiles
下
建议配置都写在同一个yml中,方便维护
加载特定环境配置
默认情况下,spring boot只会加载application.yml
,如果想加载application-${profile}.yml
,必须指定spring.profiles.active
属性
方式一
在supervisor启动脚本新增java -jar xxx.jar --spring.profiles.active=${profile}
,profile变量是所指定的环境名
方式二
在system-config.properties中配置spring.profiles.active
属性。在spring boot启动前加载system-config.properties
,即可获取spring.profiles.active
属性,从而让spring boot加载各个环境的配置
启动模板类
@SpringBootApplication
@ImportResource("classpath:spring-application.xml")
public class Application {
public static void main(String[] args) throws IOException {
Properties props = PropertiesLoaderUtils.loadProperties(new ClassPathResource("system-config.properties"));
SpringApplication app = new SpringApplication(Application.class);
app.setDefaultProperties(props);
app.run(args);
}
}
接入spring cloud
pom.xml引入依赖
新增dependency
节点
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
新增dependencyManagement
节点
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Brixton.SR7</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
启动类加入@EnableEurekaClient
配置eureka服务地址
提供rest服务
可以参考spring mvc的写法
有3个建议:
- http协议中,GET请求是有长度限制,建议采用POST请求。
- 在post请求中,参数应该放在http body中。因为在body中传递的是json参数对象,要加@RequestBody 注解。
- url名称和方法名一致。
@RestController
public class SmsStatController {
private final Logger logger = Logger.getLogger(getClass());
@Autowired
private SmsStatServiceImpl smsStatServiceImpl;
@PostMapping(value = "/getSmsMoneyTarget")
public List<SmsMoneyTargetResult> getSmsMoneyTarget(@RequestBody SmsStatQueryParam param) {
return smsStatServiceImpl.getSmsMoneyTarget(param);
}
}
调用方
参照提供方提供的接口编写。
调用方可以参照dubbo的方式写在api工程中,避免参数对象和结果对象重复定义。可读性较好,但是缺点是引入了强依赖。
@FeignClient(value = "sms-stat-server")
public interface SmsStatClient {
/**
* 获取累计概要指标的数据列表
* @param param
* @return
*/
@RequestMapping(value = "/getSmsMoneyTarget", method = RequestMethod.POST)
List<SmsMoneyTargetResult> getSmsMoneyTarget(SmsStatQueryParam param);
}
调用方可以实现HystrixCallBack接口,可以在调用失败的时候进行操作,比如服务降级或者返回一个默认值,避免远程方法报错。类似dubbo框架中的mock。
幂等问题
因为目前工程中很多接口未实现幂等,所以不可以超时重试。
spring cloud默认会尝试5次调用。在每一次调用中,尝试对某一提供方发起调用,若连接拒绝,则会进行下一个提供方的尝试。
提供方配置自定义超时时间及重试次数
@Configuration
public class FeignConfig {
@Bean
public Feign.Builder feignBuilder() {
Feign.Builder fb = Feign.builder();
fb.logLevel(Logger.Level.FULL);
fb.retryer(new Retryer.Default(100, SECONDS.toMillis(1), 1));
return fb;
}
@Bean
public Options feignOptions() {
return new Options(2 * 1000, 10 * 1000);
}
}
目前的问题
结果对象
在dubbo中,提供方返回的对象为Map等泛型,提供方在拿到这个Map后是可以得到里面的对象的。
而spring cloud采用的是json编码、解码,返回值如果不是特定的对象模型,解析出来是获取不到数据的。
建议,接口参数采用特定的模型对象。
参数对象
调用参数存在多个的情况。
如果都是基本类型,可以使用@requestParam注解进行传参,参数附在url上。
或者定义一个对象,将全部的参数都放在其中,通过http body进行传参。(提供方要提供POST请求)
已改造项目
可以进行参考
iportal-developer
sms-stat