前言:以前的项目大多为单体项目,在编译时,这些项目将被打包成为一个个JAR包,并最终合并在一起形成一个WAR包。接下来,我们需要将该WAR包上传到Web容器中,解压该WAR包,并重新启动服务器。然后完成编译和部署
项目增大后会出现以下问题
①编译难,部署难,测试难
②技术选择难
③扩展难
一、springCloud是啥
Spring cloud是一个基于Spring Boot实现的服务治理工具包,用于微服务架构中管理和协调服务的。
Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署
五大神兽:
服务注册发现——Netflix Eureka : 注册所有微服务的通信地址
客服端负载均衡——Netflix Ribbon\Feign :服务之间的调用问题
断路器——Netflix Hystrix :解决微服务故障问题,微服务的隔离
服务网关——Netflix Zuul :微服务的统一入口
分布式配置——Spring Cloud Config :统一管理微服务的配置文件
微服务场景模拟-入门
1)创建普通maven项目,作为父模块
2)导包
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.SR1</spring-cloud.version>
<springboot.version>2.0.5.RELEASE</springboot.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${springboot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
3)创建服务提供者模块
<dependencies>
<!--公共代码依赖-->
<dependency>
<groupId>cn.itsource.springcloud</groupId>
<artifactId>User_interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--springboot支持-->
<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>
</dependency>
</dependencies>
application.yml
server:
port: 8001
spring:
application:
name: USER-PROVIDER #不要使用下划线
4)入口类
@SpringBootApplication
public class UserProviderApplication_8001 {
public static void main(String[] args) {
SpringApplication.run(UserProviderApplication_8001.class);
}
}
5)服务代码controller
@RestController
@RequestMapping("/provider")
public class UserController {
// @Autowired
// private IUserService userService;
@GetMapping("/user/{id}") //user/1
public User getUser(@PathVariable("id") Long id) {
// 正常应该调用service获取用户,现在模拟一下
return new User(id, "zs");
}
}
6)服务消费者
导包
<dependency>
<groupId>cn.itsource.springcloud</groupId>
<artifactId>User_interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--springboot支持-->
<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>
</dependency>
application.yml
server:
port: 9001
spring:
application:
name: USER-CONSUMER
入口类
package cn.itsource.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class UserConsumerAppliction_9001 {
public static void main(String[] args) {
SpringApplication.run(UserConsumerAppliction_9001.class);
}
}
调用接口
@Configuration // <beans></beans>
public class CfgBean {
@Bean //<bean class="org.springframework.web.client.RestTemplate"></bean>
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
controller
@RestController
@RequestMapping("/consumer")
public class UserController {
//多个方法调用只需改一处就ok
public static final String URL_PREFIX = "http://localhost:8001";
@Autowired
private RestTemplate restTemplate;
@RequestMapping("/user/{id}")
public User getUser(@PathVariable("id")Long id){
//调用远程服务 http请求
String url = URL_PREFIX+"/provider/user/"+id;
return restTemplate.getForObject(url,User.class );
}
}
Eureka注册中心
为什么?
因为分布式服务必然要面临的问题:
- 服务管理
- 如何自动注册和发现
- 如何实现状态监管
- 如何实现动态路由
- 服务如何实现负载均衡
- 服务如何解决容灾问题
- 服务如何实现统一配置
是什么
Eureka是netflix的一个子模块,也是核心模块之一,Eureka是一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移。服务注册与发现对于微服务架构来说是非常重要的,有了服务发现和注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务
Eureka注册中心搭建
新创建一个普通maven项目 eureka_server_7001
pom导包
<!--springboot支持-->
<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>
</dependency>
<!--Eureka服务端支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
application.yml
server:
port: 7001
eureka:
instance:
hostname: localhost
client:
registerWithEureka: false #是否要注册到eureka
fetchRegistry: false #表示是否从Eureka Server获取注册信息
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #单机配置
运行类
server:
port: 7001
eureka:
instance:
# hostname: localhost
hostname: eureka-7001.com #集群
client:
register-with-eureka: false
fetch-registry: false
service-url:
# defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #单机配置
defaultZone: http://eureka-7002.com:7002/eureka/ #集群配置
测试:启动并访问 localhost:7001
将服务提供者注册到Eureka
在服务提供者里导包
<!--eureka客户端支持 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
修改application.yml
server:
port: 8001
spring:
application:
name: PRODUCT-SERVICE #服务名
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
# defaultZone: http://eureka-7001.com:7001/eureka,http://eureka-7002.com:7002/eureka
instance:
prefer-ip-address: true
ip-address: 127.0.0.1
然后启用启动类
@SpringBootApplication
@EnableEurekaClient //表示是eureka的客户端
public class UserProviderApplication_8001 {
public static void main(String[] args) {
SpringApplication.run(UserProviderApplication_8001.class);
}
}
将服务消费者从Eureka调用服务
导包
<!-- Eureka客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
修改application.yml
server:
port: 9001
spring:
application:
name: ORDER-SERVICE #服务名
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
# defaultZone: http://eureka-7001.com:7001/eureka,http://eureka-7002.com:7002/eureka
instance:
prefer-ip-address: true
ip-address: 127.0.0.1
启动类加上 @EnableEurekaClient
package cn.itsource.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableEurekaClient
public class UserConsumerAppliction_9001 {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate(new OkHttp3ClientHttpRequestFactory());
}
public static void main(String[] args) {
SpringApplication.run(UserConsumerAppliction_9001.class);
}
}
整改服务调用
@Autowired
private DiscoveryClient discoveryClient;// Eureka客户端,可以获取到服务实例信息
// String baseUrl = "http://localhost:8081/user/";
// 根据服务名称,获取服务实例
List<ServiceInstance> instances = discoveryClient.getInstances("user-service");
// 因为只有一个UserService,因此我们直接get(0)获取
ServiceInstance instance = instances.get(0);
// 获取ip和端口信息
String baseUrl = "http://"+instance.getHost() + ":" + instance.getPort()+"/user/";
this.restTemplate.getForObject(baseUrl + id, User.class)
然后解决了url写死的问题
但是只有一个EurekaServer,挂了就不行了
Eureka注册中心集群
集群:多个服务器协调完成一种业务。
生产环境把Eureka部署多个服务器就ok了,但是现在是开发阶段同一台主机不同端口号来代替服务器
怎么做
先拷贝一份 eureka_server_7002
在system32下的hosts文件里添加端口号:
127.0.0.1 eureka-7001.com
127.0.0.1 eureka-7002.com
配置eureka_server_7002 application.yml
server:
port: 7002
eureka:
instance:
# hostname: localhost
hostname: eureka-7002.com #集群
client:
register-with-eureka: false
fetch-registry: false
service-url:
# defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #单机配置
defaultZone: http://eureka-7001.com:7001/eureka/ #集群配置
修改eureka_server_7001 application.yml
server:
port: 7001
eureka:
instance:
# hostname: localhost
hostname: eureka-7001.com #集群
client:
register-with-eureka: false
fetch-registry: false
service-url:
# defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #单机配置
defaultZone: http://eureka-7002.com:7002/eureka/ #集群配置
然后测试:eureka-7001.com:7001,eureka-7002.com:7002