spring cloud 学习(1) - 基本的SOA示例
有过dubbo/dubbox使用经验的朋友,看到下面这张图,一定很熟悉,就是SOA架构的最基本套路。
与dubbo对比,上图的3大要素中,spring cloud是借助以下组件来实现的:
1、注册中心:
spring cloud默认使用eureka server来做注册中心,而dubbo默认使用的是zookeeper。eureka的注册信息是保存在一个双层的Map对象中的,换句话说在内存中,不象zookeeper是长久保存在节点中。
2、服务提供方:
spring-web(Spring MVC)提供了完善的http rest服务框架,用这一套就能提供rest服务。(目前spring cloud官方提供的示例基本上都是http rest服务,理论上讲,应该也可以扩展成rpc服务,而dubbo是以rpc为主的,这点有些区别)
3、服务消费方:
依赖于spring-web,负载均衡采用ribbon组件来完成,大致原理是从注册中心发现可用服务的信息,缓存在本地,然后按一定的负载均衡算法进行调用。(跟dubbo类似,只不过dubbo是自己实现的负载均衡)
下面是这三方的最基本示例:
一、项目结构
注:spring-cloud是完全基于Spring Boot来构建项目的,所以对spring boot不熟悉的,建议先看本博客的spring boot系列。
register-center 即 eureka 注册中心
service-api 为服务契约
service-consumer 为服务消费方
service-provider 为服务提供方
二、register-center
2.1 依赖项
buildscript {
repositories {
maven {
url "http://maven.aliyun.com/nexus/content/groups/public/"
}
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.4.RELEASE")
}
} apply plugin: 'spring-boot' dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:Dalston.RELEASE"
}
} dependencies {
compile 'org.springframework.cloud:spring-cloud-starter-eureka-server'
compile 'org.springframework.boot:spring-boot-starter-actuator'
testCompile 'org.springframework.boot:spring-boot-starter-test'
}
2.2 main入口程序
package com.cnblogs.yjmyzz.spring.cloud.study; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; /**
* Created by 菩提树下的杨过 on 2017/6/17.
*/
@SpringBootApplication
@EnableEurekaServer
public class RegisterServer { public static void main(String[] args) {
SpringApplication.run(RegisterServer.class, args);
}
}
主要是靠最上面的@EnableEurekaServer这个注解,其它完全没有花头。
2.3 配置
server:
port: 8000 eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://localhost:8000/eureka
解释一下:
注册中心本身也是一个服务,也可以当成普通服务向其它注册中心来注册,由于本示例中,只有一个eureka server自己就充当注册中心,也不需要跟其它注册中心同步注册信息,所以都设置成false。最后一行的defaultZone,初次接触可以先不管,先理解成注册中心对外暴露的地址即可。
2.4 启动
启动后,浏览http://localhost:8000/,可以看到类似下图:
现在没有任何服务注册,所以在Application里,显示No instances available.
三、service-api
为了方便后面讲解,先定义一个服务接口,以及对应的DTO
package com.cnblogs.yjmyzz.spring.cloud.study.api; import com.cnblogs.yjmyzz.spring.cloud.study.dto.UserDTO; /**
* Created by 菩提树下的杨过 on 2017/6/17.
*/
public interface UserService { UserDTO findUser(Integer userId);
}
以及
package com.cnblogs.yjmyzz.spring.cloud.study.dto; import lombok.Data; /**
* Created by 菩提树下的杨过 on 2017/6/17.
*/
@Data
public class UserDTO { private Integer userId; private String userName;
}
四、service-provider
4.1 依赖项
buildscript {
repositories {
maven {
url "http://maven.aliyun.com/nexus/content/groups/public/"
}
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.4.RELEASE")
}
} apply plugin: 'spring-boot' dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:Dalston.RELEASE"
}
} dependencies {
compile(project(":service-api"))
compile 'org.springframework.cloud:spring-cloud-starter-eureka'
compile 'org.springframework.boot:spring-boot-starter-actuator'
compile 'org.springframework.boot:spring-boot-starter-web'
testCompile 'org.springframework.boot:spring-boot-starter-test'
}
4.2 接口实现
package com.cnblogs.yjmyzz.spring.cloud.study.service.impl; import com.cnblogs.yjmyzz.spring.cloud.study.api.UserService;
import com.cnblogs.yjmyzz.spring.cloud.study.dto.UserDTO;
import org.springframework.stereotype.Service; @Service("userService")
public class UserServiceImpl implements UserService { @Override
public UserDTO findUser(Integer userId) {
UserDTO user = new UserDTO();
user.setUserId(userId);
user.setUserName("菩提树下的杨过");
return user;
}
}
这里只是随便示意一下,直接返回一个固定的UserDTO实例。
4.3 controller
package com.cnblogs.yjmyzz.spring.cloud.study.controller; import com.cnblogs.yjmyzz.spring.cloud.study.api.UserService;
import com.cnblogs.yjmyzz.spring.cloud.study.dto.UserDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController; @RestController
public class UserController { @Autowired
private UserService userService; @GetMapping("/user/{id}")
public UserDTO findUser(@PathVariable Integer id) {
return userService.findUser(id);
}
}
这里用了一个新的注解GetMapping,相当于之前SpringMVC中@RequestMapping(method = RequestMethod.GET),更简洁而已。
到目前为止,都跟常规的SpringMVC无异。
4.4 main入口
package com.cnblogs.yjmyzz.spring.cloud.study; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; /**
* Created by yangjunming on 2017/6/17.
*/
@EnableDiscoveryClient
@SpringBootApplication
public class ServiceProvider { public static void main(String[] args) {
SpringApplication.run(ServiceProvider.class, args);
}
}
依旧还是@EnableDiscoveryClient挑大梁,表明这是一个eureka的客户端程序(即:能向eureka server注册)
4.5 配置
server:
port: 8001 spring:
application:
name: "service-provider-demo"
eureka:
instance:
prefer-ip-address: true
client:
service-url:
defaultZone: http://localhost:8000/eureka/
应该不难理解,最后那几行,表示用自己IP地址向 http://localhost:8000/eureka/注册
4.6 启动
启动成功后,再看eureka 刚才的页面,会发现已经注册进来了。
注:大家可以把service-provider多启动几个实例(端口错开,不要冲突即可),然后再观察下这个界面,可以看到注册了多个provider实例
五、service-consumer
5.1 依赖项
buildscript {
repositories {
maven {
url "http://maven.aliyun.com/nexus/content/groups/public/"
}
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.4.RELEASE")
}
} apply plugin: 'spring-boot' dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:Dalston.RELEASE"
}
} dependencies {
compile(project(":service-api"))
compile 'org.springframework.cloud:spring-cloud-starter-eureka'
compile 'org.springframework.boot:spring-boot-starter-actuator'
compile 'org.springframework.cloud:spring-cloud-starter-ribbon'
compile 'org.springframework.boot:spring-boot-starter-web'
testCompile 'org.springframework.boot:spring-boot-starter-test'
}
5.2 建一个调用的Controller
package com.cnblogs.yjmyzz.spring.cloud.study.service.controller; import com.cnblogs.yjmyzz.spring.cloud.study.dto.UserDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate; import java.util.List; /**
* Created by yangjunming on 2017/6/17.
*/
@RestController
public class OrderController { @Autowired
private RestTemplate restTemplate; @Autowired
private LoadBalancerClient loadBalancerClient; @Autowired
private DiscoveryClient discoveryClient; @GetMapping("/order/{userId}/{orderNo}")
public String findOrder(@PathVariable Integer userId, @PathVariable String orderNo) {
UserDTO user = restTemplate.getForEntity("http://SERVICE-PROVIDER-DEMO/user/" + userId, UserDTO.class).getBody();
if (user != null) {
return user.getUserName() + " 的订单" + orderNo + " 找到啦!";
} return "用户不存在!";
} @GetMapping("/user-instance")
public List<ServiceInstance> showInfo() {
return this.discoveryClient.getInstances("SERVICE-PROVIDER-DEMO");
} @GetMapping("/log-instance")
public ServiceInstance chooseInstance() {
return this.loadBalancerClient.choose("SERVICE-PROVIDER-DEMO");
} }
这里暴露了3个url,一个个来看:
a. /order/{userId}/{orderNo} 这个用来示例如何调用service-provider中的方法,注意这里我们并没有用http://localhost:8001/user/1 来调用,而通过http://service-provider-demo/user/ 指定service-provider的application name,让系统从注册中心去发现服务。
b. /user-instance , /log-instance 这二个url 用来辅助输出从注册中心发现的服务实例相关的信息,并非必须。
这里面还有二个注入的实例:restTemplate 、loadBalancerClient ,分别用来发起rest的http请求,以及使用负载均衡从可用的服务列表中,挑出一个可用实例。
5.3 main入口
package com.cnblogs.yjmyzz.spring.cloud.study.service; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate; @EnableDiscoveryClient
@SpringBootApplication
public class ServiceConsumer { @Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
} public static void main(String[] args) {
SpringApplication.run(ServiceConsumer.class, args);
}
}
依然靠二个关键的注解:@EnableDiscoveryClient、@LoadBalanced,特别是@LoadBalanced,经过这个修饰的restTemplate,就不是普通的restTemplate了,而是具备负载均衡能力的restTemplate,即每次都会用负载均衡算法,从可用服务列表中,挑一个进行调用。
5.3 启动
可以从eukera中看到,service-provider与service-consumer都注册进来了。
调用一下试试:http://localhost:8002/order/1/1000,成功的话会看到下面的输出
注:此时可以把注册中心eureka server停掉,然后再调用下http://localhost:8002/order/1/1000,会发现仍然可以正常调用,说明注册中心的服务列表,在本机是有缓存的,这跟dubbo/dubbox类似。
另外还可以验证下负载均衡,方法如下:
先把service-provider启2个,开二个终端窗口:
java -jar xxx.jar --server.port=9001
java -jar xxx.jar --server.port=9002
这样就能跑二个应用起来,然后看注册中心
然后再调用下consumer的log-instance
可以看到,这次选择的是9002端口应对的实例,然后再刷新一下:
这回选择的是另一个端口9001的实例,说明负载均衡确实起作用了。
至此,一个最基本的SOA框架雏形搭建起来了,当然还有很多地方需要完善,比如:注册中心如何做到HA,服务融断如何处理,注册中心如何安全认证(防止其它服务乱注册)等等,后面再讲。
附:文中示例源码 https://github.com/yjmyzz/spring-cloud-demo
spring cloud 学习(1) - 基本的SOA示例的更多相关文章
- Spring Cloud学习(一):Eureka服务注册与发现
1.Eureka是什么 Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的. Eureka ...
- spring cloud 学习(9) - turbine stream无法在eureka注册的解决办法
turbine是啥就不多解释了,初次接触的可以移步spring cloud 学习(4) - hystrix 服务熔断处理 拉到最后看一下,turbine stream默认情况下启动成功后,eureka ...
- spring cloud 学习资料
spring cloud 学习资料 网址 拜托!面试请不要再问我Spring Cloud底层原理 https://mp.weixin.qq.com/s/ZH-3JK90mhnJPfdsYH2yDA
- Spring Boot和Spring Cloud学习资源推荐
Spring Boot和Spring Cloud学习资源推荐 比较好的学习资源,分享一下. 1.Spring Boot官方文档:http://projects.spring.io/spring-b ...
- Spring Cloud 学习 之 Spring Cloud Eureka(源码分析)
Spring Cloud 学习 之 Spring Cloud Eureka(源码分析) Spring Boot版本:2.1.4.RELEASE Spring Cloud版本:Greenwich.SR1 ...
- Spring Cloud学习之-什么是Spring Cloud?
SpringCloud 什么是微服务? 要想学习微服务,首先需要知道什么是微服务?为什么会有微服务?相信看完架构的发展史读者就会明白 架构发展史 单体应用架构 如图所示:将所有的模块,所有内容(页面. ...
- Spring Cloud 学习笔记(二)——Netflix
4 Spring Cloud Netflix Spring Cloud 通过自动配置和绑定到Spring环境和其他Spring编程模型惯例,为Spring Boot应用程序提供Netflix OSS集 ...
- Spring Cloud 学习笔记(一)——入门、特征、配置
[TOC] 0 放在前面 0.1 参考文档 http://cloud.spring.io/spring-cloud-static/Brixton.SR7/ https://springcloud.cc ...
- Spring Cloud学习笔记-008
继承特性 通过上节的示例实践,当使用Spring MVC的注解来绑定服务接口时,几乎完全可以从服务提供方的Controller中依靠复制操作,构建出相应的服务客户端绑定接口.既然存在这么多复制操作,自 ...
随机推荐
- Angular 下的 directive (part 1)
directive 指令 Directive components 指令部分 使用指令自动引导一个AngularJS应用.ngApp指令指定应用程序的根元素,通常是放在页面的根元素如: < ...
- netty学习总结(一)
netty是一个nio框架,将java的nio进行了一个封装,形成了一个高性能,高可用的网络编程框架,很多的框架都是基于netty的,所以学好netty是很有用的,而且netty本身的代码结构设计,以 ...
- idea如何导入一个maven项目
1.import project 2.选择maven项目 3.选择第二个external moudle,选择maven, 4.点击next,一次点击1,2,3,4 5.设置maven环境 6.点击ok ...
- tensorflow函数(2)
并行计算能让代价大的算法计算加速执行,TensorFlow也在实现上对复杂操作进行了有效的改进.大部分核相关的操作都是设备相关的实现,比如GPU.下面是一些重要的操作/核: 操作组 操作 Maths ...
- react 的JSX语法需要注意哪些点?
注释方式 ReactDOM.render( <div> {/*JSX 中的注释方式*/} </div>, document.getElementById('root') ) j ...
- jTessBoxEditor工具进行Tesseract3.02.02样本训练
1.背景 前文已经简要介绍tesseract ocr引擎的安装及基本使用,其中提到使用-l eng参数来限定语言库,可以提高识别准确率及识别效率. 本文将针对某个网站的验证码进行样本训练,形成自己的语 ...
- ExpressMapper- The New .NET Mapper!
推荐,据测试比手工映射的效率还高. https://www.codeproject.com/Tips/1009198/Expressmapper-The-New-NET-Mapper
- 一步一步学习IdentityServer3 (1)
学习之初: IdentityServer3我自己最开始了解到的就是做一个SSO单点登录,后面发现还有单独的认证服务功能,其实它还可以做APIs的访问控制,资源授权,另外还可以为提供第三方登录,其他的自 ...
- MVC4是不是类似于html页+ashx页之间用JSON通过AJAX交换数据这种方式、?
不是,可以讲mvc模式是借鉴于java下面的mvc开发模式,为开发者公开了更多的内容和控制,更易于分工合作,与单元测试,借用官方的说法:MVC (Model.View.Controller)将一个We ...
- MVC插件
MVC插件 最近领导让我搞一下插件化,就是实现多个web工程通过配置文件进行组装.之前由于做过一个简单的算是有点经验,当时使用的不是area,后来通过翻看orchard源码有点启发,打算使用area改 ...