搭建第一个springcloud--生产者消费者和Eureka
SpringCloud是一系列框架的有序集合。它利用SpringBoot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用SpringBoot的开发风格做到一键启动和部署。SpringCloud并没有重复制造*,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过SpringBoot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。
创建两个maven项目,一个provider,一个consumer。
两者的路径为(只展示其一consumer项目结构):
先建立两个springboot项目,一个端口为默认的8080,一个手动设置为8081(在Application.yml中设置)。
其中pom文件内容为:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>consumer</groupId>
<artifactId>consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>consumer</name>
<description>consumer</description>
<!-- 只复制下面的内容即可 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
而springboot的入口在Application.java,用于启动项目。内容为:
package consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
以上为两个项目一样的内容,接下来是每个项目的不同的文件内容。
首先是providerdemo.java里面的内容:
@RestController
public class providerdemo {
@RequestMapping("provider/demo")
public String demo() {
return "provider success!";
}
}
再来是consumerdemo.java里面的内容:
@RestController
public class consumerdemo {
/*
* 当我们从服务消费端去调用服务提供者的服务的时候,使用了一个很好用的对象,叫做RestTemplate,
* 当时我们只使用了RestTemplate中最简单的一个功能getForEntity发起了一个get请求去调用服务端的数据
*/
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Autowired
private RestTemplate restTemplate;
@RequestMapping("consumer/demo")
public String consumerdemo() {
return this.restTemplate.getForObject("http://localhost:8080/provider/demo",String.class);
}
}
RestTemplates在SpringCloud中,消费者通过这个类访问生产者,@bean注解是为了实例化这个类,实例化之后通过@AutoWired注解引入,将其交给Spring进行管理。
分别启动两个类,分别访问localhost:8080/provider/demo和http://localhost:8081/consumer/demo应该都能得到provider success!这个结果,说明consumer成功调用了provider中的方法。
问题:
这样的编码方式是将接口(http://localhost:8080/provider/demo)硬编码在代码中,但是项目发布之后,ip地址必然是变动的。而且,硬编码的方式肯定是无法实现负载均衡的,就是说如果同时启动多个provider服务,这种硬编码方式是无法根据负载均衡策略去调用服务的。
解决方法:
在Dubbo中使用的ZooKeeper作为服务注册与发现的容器,在Springcloud中使用的是Eureka作为服务注册与发现的容器。
接下来添加一个Eureka项目,新建一个项目,pom文件为:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>Eureka</groupId>
<artifactId>Eureka</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Eureka</name>
<description>Eureka</description>
<!-- 只复制下面的内容即可 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>
<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.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
<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>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
然后在Springboot的启动类上添加@EnableEurekaServer或者@EnableDiscoveryClient,这两个注解的注解的区别主要是:
@EnableEurekaServer是基于 spring-cloud-netflix依赖,只能为eureka作用,是专门给Eureka用的
@EnableDiscoveryClient是基于 spring-cloud-commons依赖,并且在classpath中实现,是给比如zookeeper、consul使用的,
@SpringBootApplication
@EnableEurekaServer
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
注意一点:SpringApplication.run(Application.class,args);里面的类名.class要与类名保持一致,是自启动。
接下来修改yml文件
server:
port: 8083
eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://localhost:8082/eureka/
register-with-eureka: false这个的默认值为true,设置为true不会对使用不会有很大的影响,但是在启动的时候会保下面的错误:
was unable to refresh its cache! status = Cannot execute request on any known server
是因为启动的时候自己注册了自己而引起的冲突
defaultZone配置eureka的地址。
如果运行会出现以下错误问题:
java.lang.NoSuchMethodError: org.springframework.boot.builder.SpringApplicationBuilder.<init>([Ljava/lang/Object;)V
是由于spring boot版本兼容性导致的,在pom.xml中修改配置文件,修改前:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/>
</parent>
修改后:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/>
</parent>
再次启动项目,成功。 (这里我只想说一句mmp,改了好几个版本,每改一次版本要等半个小时maven下载,启动起来又给我报了好多错,最后发现我随便写的端口8082竟然重复了,最后把端口改成8083就可以成功启动了)
启动成功输入 http://localhost:8083/(根据自己的端口)就可以看见eureka界面。
接着我们要把provider和consumer都放在注册中心中,那么我们需要更改一些pom文件
两者pom文件相同,只列其一:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>springcloud</groupId>
<artifactId>springcloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springcloud</name>
<description>springcloud</description>
<!-- 只复制下面的内容即可 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
更改了parent的版本号,增加了这个spring-cloud-starter-netflix-eureka-client。
在这里强调一下dependencyManagement和dependency的关系
1.在Maven中dependencyManagement的作用其实相当于一个对所依赖jar包进行版本管理的管理器。
2.pom.xml文件中,jar的版本判断的两种途径
(1):如果dependencies里的dependency自己没有声明version元素,那么maven就
会倒dependencyManagement里面去找有没有对该artifactId和groupId进行过版本声明,如果有,就继承它,如果
没有就会报错,告诉你必须为dependency声明一个version
(2):如果dependencies中的dependency声明了version,那么无论dependencyManagement中有无对该jar的version声明,都以dependency里的version为准。
问题:如果版本不一致会出现的这样的错误。
JavaWeb:java.lang.NoClassDefFoundError: org/springframework/core/OrderComparator$OrderSourceProvider
要保持springboot和springcloud的版本一致。
回到正题,继续走,接着更改provider和consumer的启动项,在项目的启动类上添加@EnableEurekaClient
注解
更改provider和consumer的yml文件
server:
port: 8080
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8083/eureka/
spring:
application:
name: provider-demo
在yml文件中添加上eureka注册中心的地址defaultZone: http://localhost:8083/eureka/
如果自己不给它设置name,application的名称为UNKNOWN。
consumer的yml文件同理。
最后先启动eureka,再启动provider、consumer,在注册中心就可以看见:
这样,第一个springcloud就搭建完了,一个经典的生产者消费者加上eureka的注册中心,这部分有什么疑问可以留言,我也是刚开始学习,能帮忙就尽量帮忙。