SpringCloud概述
谈到SpringCloud之前,先看看微服务带来的问题,接口地址如何管理、容错机制、负载均衡、网关、路由策略、高并发情况下,怎么接口限流、断路(服务宕机如何处理)。
微服务解决框架-SpringCloud、Dubbo
SpringBoot和SpringCloud的关系
- SpringBoot简化xml配置,快速整合框架
- SpringCloud是一整套微服务解决方案--RPC远程调用
关系SpringBoot的SpringMVC暴露接口,而SpringCloud管理接口,存在依赖关系。
SpringCloud解决问题
配置管理(注册中心Eureka,Dubbo的是Zookeeper)、服务发现、服务注册、断路器(非常重要,容错机制、限流、调用接口失败如何解决)、路由策略(接口分发那台机器上去)、负载均衡、全局锁、分布式会话、客户端调用、接口网关、服务管理系统。
服务注册和发现(Eureka)
什么是Eureka
官方的介绍在这里Eureka wiki。Eureka是Netflix开源的一个RESTful服务,主要用于服务的注册发现。Eureka由两个组件组成:Eureka服务器和Eureka客户端。Eureka服务器用作服务注册服务器。Eureka客户端是一个java客户端,用来简化与服务器的交互、作为轮询负载均衡器,并提供服务的故障切换支持。Netflix在其生产环境中使用的是另外的客户端,它提供基于流量、资源利用率以及出错状态的加权负载均衡。
Eureka的吸引力来源于以下几点:
- 开源:大家可以对实现一探究竟,甚至修改源码。
- 可靠:经过Netflix多年的生产环境考验,使用应该比较靠谱省心
- 功能齐全:不但提供了完整的注册发现服务,还有Ribbon等可以配合使用的服务。
- 基于Java:对于Java程序员来说,使用起来,心里比较有底。
- spring cloud可以使用Spring Cloud, 与Eureka进行了很好的集成,使用起来非常方便。
搭建注册中心、服务提供者、服务消费者
实现服务注册
1.创建Eurekaserver项目
2.Maven依赖
-
<parent>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-parent</artifactId>
-
<version>1.5.2.RELEASE</version>
-
<relativePath /> <!-- lookup parent from repository -->
-
</parent>
-
<properties>
-
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
-
<java.version>1.8</java.version>
-
</properties>
-
<dependencies>
-
<!--eureka server -->
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-starter-eureka-server</artifactId>
-
</dependency>
-
<!-- spring boot test -->
-
<dependency>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-test</artifactId>
-
<scope>test</scope>
-
</dependency>
-
</dependencies>
-
<dependencyManagement>
-
<dependencies>
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-dependencies</artifactId>
-
<version>Dalston.RC1</version>
-
<type>pom</type>
-
<scope>import</scope>
-
</dependency>
-
</dependencies>
-
</dependencyManagement>
-
<build>
-
<plugins>
-
<plugin>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-maven-plugin</artifactId>
-
</plugin>
-
</plugins>
-
</build>
-
<repositories>
-
<repository>
-
<id>spring-milestones</id>
-
<name>Spring Milestones</name>
-
<url>https://repo.spring.io/milestone</url>
-
<snapshots>
-
<enabled>false</enabled>
-
</snapshots>
-
</repository>
-
</repositories>
3.配置application.yml
-
server:
-
port: 8888
-
eureka:
-
instance:
-
hostname: localhost
-
client:
-
registerWithEureka: false
-
fetchRegistry: false
-
serviceUrl:
-
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
4.启动EurekaServer
-
@SpringBootApplication
-
@EnableEurekaServer
-
public class App {
-
public static void main(String[] args) {
-
SpringApplication.run(App.class, args);
-
}
-
}
5.打开EurekaServer界面
可以看到没有服务注册,我们现在新建一个服务类注册服务上去
服务提供者
创建一个服务提供者 会员服务工程,提供会员查询服务信息。
1.创建项目service-member
2.Maven依赖
-
<parent>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-parent</artifactId>
-
<version>1.5.2.RELEASE</version>
-
<relativePath /> <!-- lookup parent from repository -->
-
</parent>
-
<properties>
-
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
-
<java.version>1.8</java.version>
-
</properties>
-
<dependencies>
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-starter-eureka</artifactId>
-
</dependency>
-
<dependency>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-web</artifactId>
-
</dependency>
-
<dependency>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-test</artifactId>
-
<scope>test</scope>
-
</dependency>
-
</dependencies>
-
<dependencyManagement>
-
<dependencies>
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-dependencies</artifactId>
-
<version>Dalston.RC1</version>
-
<type>pom</type>
-
<scope>import</scope>
-
</dependency>
-
</dependencies>
-
</dependencyManagement>
-
<build>
-
<plugins>
-
<plugin>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-maven-plugin</artifactId>
-
</plugin>
-
</plugins>
-
</build>
-
<repositories>
-
<repository>
-
<id>spring-milestones</id>
-
<name>Spring Milestones</name>
-
<url>https://repo.spring.io/milestone</url>
-
<snapshots>
-
<enabled>false</enabled>
-
</snapshots>
-
</repository>
-
</repositories>
3.application.yml配置
-
eureka:
-
client:
-
serviceUrl:
-
defaultZone: http://localhost:8888/eureka/
-
server:
-
port: 8762
-
spring:
-
application:
-
name: service-member
4.服务接口
-
@RestController
-
public class MemberController {
-
@RequestMapping("/getUserList")
-
public List<String> getUserList() {
-
List<String> listUser = new ArrayList<String>();
-
listUser.add("zhangsan");
-
listUser.add("lisi");
-
listUser.add("yushengjun");
-
return listUser;
-
}
-
}
5.发布服务
通过注解@EnableEurekaClient表明自己是一个eurekaClient
-
@SpringBootApplication
-
@EnableEurekaClient
-
public class AppMember {
-
public static void main(String[] args) {
-
SpringApplication.run(AppMember.class, args);
-
}
-
}
6.演示效果
服务名称已经注册到Eureka上了
服务消费者
1.创建项目service-order
2.Maven依赖
-
<parent>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-parent</artifactId>
-
<version>1.5.2.RELEASE</version>
-
<relativePath /> <!-- lookup parent from repository -->
-
</parent>
-
<properties>
-
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
-
<java.version>1.8</java.version>
-
</properties>
-
<dependencies>
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-starter-eureka</artifactId>
-
</dependency>
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-starter-ribbon</artifactId>
-
</dependency>
-
<dependency>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-web</artifactId>
-
</dependency>
-
<dependency>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-test</artifactId>
-
<scope>test</scope>
-
</dependency>
-
</dependencies>
-
<dependencyManagement>
-
<dependencies>
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-dependencies</artifactId>
-
<version>Dalston.RC1</version>
-
<type>pom</type>
-
<scope>import</scope>
-
</dependency>
-
</dependencies>
-
</dependencyManagement>
-
<build>
-
<plugins>
-
<plugin>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-maven-plugin</artifactId>
-
</plugin>
-
</plugins>
-
</build>
-
<repositories>
-
<repository>
-
<id>spring-milestones</id>
-
<name>Spring Milestones</name>
-
<url>https://repo.spring.io/milestone</url>
-
<snapshots>
-
<enabled>false</enabled>
-
</snapshots>
-
</repository>
-
</repositories>
3.application.yml配置
-
eureka:
-
client:
-
serviceUrl:
-
defaultZone: http://localhost:8888/eureka/
-
server:
-
port: 8764
-
spring:
-
application:
-
name: service-order
4.编写service,调用server-member
-
@SuppressWarnings("unchecked")
-
@Service
-
public class MemberService {
-
@Autowired
-
RestTemplate restTemplate;
-
public List<String> getOrderByUserList() {
-
return restTemplate.getForObject("http://service-member/getUserList", List.class);
-
}
-
}
5.编写controller,调用service。
-
@RestController
-
public class MemberController {
-
@Autowired
-
MemberService memberService;
-
@RequestMapping("/getOrderUserAll")
-
public List<String> getOrderUserList(){
-
return memberService.getOrderByUserList();
-
}
-
}
6.发布
-
@EnableEurekaClient
-
@SpringBootApplication
-
public class OderApp {
-
public static void main(String[] args) {
-
SpringApplication.run(OderApp.class, args);
-
}
-
/**
-
* 必须加上,不然启动不了
-
* @return
-
*/
-
@Bean //加入bean容器中
-
@LoadBalanced //支持负载均衡
-
RestTemplate restTemplate() {
-
return new RestTemplate();
-
}
-
}
这时候可以消费服务,并且Eureka注册中心也多了一个service-order服务
SpringCloud调用服务原理
会员服务注册到注册中心里面,订单服务获取真实的访问地址,通过httpclient去访问会员服务获取数据。
SpringCloud实现负载均衡
怎么实现负载均衡nginx、lvs、HAproxy、F5
SpringCloud中负载均衡,使用Rebbion技术
什么是Rebbion
ribbion是一个负载均衡客户端,类似nginx反向代理,可以很好的控制http和tcp的一些行为。Feign默认集成rebbion。
使用Rebbion负载均衡
1.修改会员服务工程代码区分端口项目
-
@Value("${server.port}")
-
private String serverport;
-
@RequestMapping("/getUserList")
-
public ArrayList<String> getUserList() {
-
ArrayList<String> listUser = new ArrayList<String>();
-
listUser.add("zhangsan");
-
listUser.add("lisi");
-
listUser.add("流浪者");
-
listUser.add("端口号"+serverport);
-
return listUser;
-
}
2.启动两次会员工程项目,并且端口号不一致。
这时候会发现,service-member服务有两个。
3.引入Maven依赖
-
<dependency><!--ribbon用于负载均衡-->
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-starter-ribbon</artifactId>
-
</dependency>
4.在启动类下,把restTemplate加入bean容器,并且上上注解LoadBalanced
-
@EnableEurekaClient
-
@SpringBootApplication
-
public class OderApp {
-
public static void main(String[] args) {
-
SpringApplication.run(OderApp.class, args);
-
}
-
/**
-
* 必须加上,不然启动不了
-
* @return
-
*/
-
@Bean //加入bean容器中
-
@LoadBalanced //支持负载均衡
-
RestTemplate restTemplate() {
-
return new RestTemplate();
-
}
-
}
5.演示效果
第一次访问9762
第二次访问
什么是接口网关
前面说了,我们通过httpclient、ajax访问服务,但是在访问不同接口会出现跨域和内网问题。这时候就需要接口网关。
路由网关(zuul)
zuul的主要作用是路由转发和过滤器,路由功能是微服务的一部分,比如/api/user/转发到user服务。
搭建SpringCloud网关
1.创建service-zuul工程
2.Maven依赖
-
<parent>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-parent</artifactId>
-
<version>1.5.2.RELEASE</version>
-
<relativePath /> <!-- lookup parent from repository -->
-
</parent>
-
<properties>
-
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
-
<java.version>1.8</java.version>
-
</properties>
-
<dependencies>
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-starter-eureka</artifactId>
-
</dependency>
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-starter-zuul</artifactId>
-
</dependency>
-
<dependency>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-web</artifactId>
-
</dependency>
-
<dependency>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-test</artifactId>
-
<scope>test</scope>
-
</dependency>
-
</dependencies>
-
<dependencyManagement>
-
<dependencies>
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-dependencies</artifactId>
-
<version>Dalston.RC1</version>
-
<type>pom</type>
-
<scope>import</scope>
-
</dependency>
-
</dependencies>
-
</dependencyManagement>
-
<build>
-
<plugins>
-
<plugin>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-maven-plugin</artifactId>
-
</plugin>
-
</plugins>
-
</build>
-
<repositories>
-
<repository>
-
<id>spring-milestones</id>
-
<name>Spring Milestones</name>
-
<url>https://repo.spring.io/milestone</url>
-
<snapshots>
-
<enabled>false</enabled>
-
</snapshots>
-
</repository>
-
</repositories>
3.application.yml配置
-
eureka:
-
client:
-
serviceUrl:
-
defaultZone: http://localhost:8888/eureka/
-
server:
-
port: 8769
-
spring:
-
application:
-
name: service-zuul
-
zuul:
-
routes:
-
api-a:
-
path: /api-member/**
-
service-id: service-member
-
api-b:
-
path: /api-order/**
-
service-id: service-order
4.启动类
-
@EnableZuulProxy
-
@EnableEurekaClient
-
@SpringBootApplication
-
public class AppZuul {
-
public static void main(String[] args) {
-
SpringApplication.run(AppZuul.class, args);
-
}
-
}
5.演示效果 通过Zuul网关转发到实际会员服务。
服务过滤
-
@Component
-
public class MyFilter extends ZuulFilter {
-
private static Logger log = LoggerFactory.getLogger(MyFilter.class);
-
@Override
-
public String filterType() {
-
return "pre";
-
}
-
@Override
-
public int filterOrder() {
-
return 0;
-
}
-
public boolean shouldFilter() {
-
return true;
-
}
-
public Object run() {
-
RequestContext ctx = RequestContext.getCurrentContext();
-
HttpServletRequest request = ctx.getRequest();
-
log.info(String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString()));
-
Object accessToken = request.getParameter("token");
-
if (accessToken != null) {
-
return null;
-
}
-
log.warn("token is empty");
-
ctx.setSendZuulResponse(false);
-
ctx.setResponseStatusCode(401);
-
try {
-
ctx.getResponse().getWriter().write("token is empty");
-
} catch (Exception e) {
-
}
-
return null;
-
}
-
}
分布式配置中心概述(SpringCloud Config)
在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。在Spring Cloud中,有分布式配置中心组件spring cloud config ,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中。在spring cloud config 组件中,分两个角色,一是config server,二是config client。
上面的话是否有些懵逼,说说应用场景,比如说数据库配置文件,在开发环境(dev),在测试环境(test),在正式环境中(pro)都是不一样的,如何切换,为不同服务统一管理,这就需要分布式配置中心。
config server:相当于git中的本地仓库,熟悉git的同学知道,git从远程仓库pull资源,在本地修改。
搭建分布式配置中心 service-config项目
1.创建git地址
https://github.com/mingchangkun/SpringCloud.git
2.config-client-dev.properties --dev环境
3.上传配置文件
-
name=小明
-
pwd=123456
上传git命令
-
git init
-
git add README.md
-
git commit -m "first commit"
-
git remote add origin https://github.com/mingchangkun/SpringCloud.git
-
git push -u origin master
4.创建config-server项目 相当于本地仓库
5.Maven依赖
-
<parent>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-parent</artifactId>
-
<version>1.5.2.RELEASE</version>
-
<relativePath /> <!-- lookup parent from repository -->
-
</parent>
-
<properties>
-
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
-
<java.version>1.8</java.version>
-
</properties>
-
<dependencies>
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-config-server</artifactId>
-
</dependency>
-
<dependency>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-test</artifactId>
-
<scope>test</scope>
-
</dependency>
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-starter-eureka</artifactId>
-
</dependency>
-
</dependencies>
-
<dependencyManagement>
-
<dependencies>
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-dependencies</artifactId>
-
<version>Camden.SR6</version>
-
<type>pom</type>
-
<scope>import</scope>
-
</dependency>
-
</dependencies>
-
</dependencyManagement>
-
<build>
-
<plugins>
-
<plugin>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-maven-plugin</artifactId>
-
</plugin>
-
</plugins>
-
</build>
-
<repositories>
-
<repository>
-
<id>spring-milestones</id>
-
<name>Spring Milestones</name>
-
<url>https://repo.spring.io/milestone</url>
-
<snapshots>
-
<enabled>false</enabled>
-
</snapshots>
-
</repository>
-
</repositories>
6.配置applcation.properties配置文件
-
spring.application.name=config-server
-
server.port=8889
-
spring.cloud.config.server.git.uri=https://github.com/mingchangkun/SpringCloud.git
-
spring.cloud.config.server.git.searchPaths=
-
spring.cloud.config.label=master
-
spring.cloud.config.server.git.username=
-
spring.cloud.config.server.git.password=
-
eureka.client.serviceUrl.defaultZone=http://localhost:8888/eureka/
- spring.cloud.config.server.git.uri:配置git仓库地址
- spring.cloud.config.server.git.searchPaths:配置仓库路径
- spring.cloud.config.label:配置仓库的分支
- spring.cloud.config.server.git.username:访问git仓库的用户名
- spring.cloud.config.server.git.password:访问git仓库的用户密码
如果Git仓库为公开仓库,可以不填写用户名和密码,如果是私有仓库需要填写,本例子是公开仓库,放心使用。
7.运行
-
@EnableConfigServer //分布式配置服务
-
@EnableEurekaClient //注册到Eureka服务中心
-
@SpringBootApplication
-
public class AppConfig {
-
public static void main(String[] args) {
-
SpringApplication.run(AppConfig.class, args);
-
}
-
}
8.演示 查看http://localhost:8889/foo/dev 查询配置中心 成功搭建config配置中心
并且服务已经注册到Eureka服务中心了
创建config-client项目
1.创建config-client项目
2.Maven依赖
-
<parent>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-parent</artifactId>
-
<version>1.5.2.RELEASE</version>
-
<relativePath /> <!-- lookup parent from repository -->
-
</parent>
-
<properties>
-
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
-
<java.version>1.8</java.version>
-
</properties>
-
<dependencies>
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-starter-config</artifactId>
-
</dependency>
-
<dependency>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-web</artifactId>
-
</dependency>
-
<dependency>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-test</artifactId>
-
<scope>test</scope>
-
</dependency>
-
</dependencies>
-
<dependencyManagement>
-
<dependencies>
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-dependencies</artifactId>
-
<version>Dalston.RC1</version>
-
<type>pom</type>
-
<scope>import</scope>
-
</dependency>
-
</dependencies>
-
</dependencyManagement>
-
<build>
-
<plugins>
-
<plugin>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-maven-plugin</artifactId>
-
</plugin>
-
</plugins>
-
</build>
-
<repositories>
-
<repository>
-
<id>spring-milestones</id>
-
<name>Spring Milestones</name>
-
<url>https://repo.spring.io/milestone</url>
-
<snapshots>
-
<enabled>false</enabled>
-
</snapshots>
-
</repository>
-
</repositories>
3.bootstrap.properties配置文件
-
spring.application.name=config-client
-
spring.cloud.config.label=master
-
spring.cloud.config.profile=
-
#spring.cloud.config.uri= http://localhost:8888/
-
eureka.client.serviceUrl.defaultZone=http://localhost:8888/eureka/
-
spring.cloud.config.discovery.enabled=true
-
spring.cloud.config.discovery.serviceId=config-server
-
server.port=8881
- spring.cloud.config.discovery.enabled 是从配置中心读取文件。
- spring.cloud.config.discovery.serviceId 配置中心的servieId,即服务名。
这时发现,在读取配置文件不再写ip地址,而是服务名,这时如果配置服务部署多份,通过负载均衡,从而高可用
4.使用分布式配置文件
-
@RestController
-
public class UserController {
-
@Value("${name}")
-
String name;
-
@Value("${pwd}")
-
String pwd;
-
@RequestMapping("/getUserName")
-
public String getUsername(){
-
return "姓名:"+name+",密码"+pwd;
-
}
-
}
5.启动
-
@SpringBootApplication
-
@EnableEurekaClient
-
public class AppClient {
-
public static void main(String[] args) {
-
SpringApplication.run(AppClient.class, args);
-
}
-
}
5.访问服务