本篇威哥打算分享如何搭建Spring Cloud框架。
好了,跟随威哥一起开启你的第一行Spring Cloud代码吧。
1、首先打开你的IDEA。创建一个Maven项目:william-spring-project。
按照威哥下面截图来操作。
注意,上面Maven的配置请换成自己的Maven配置,下面是威哥的Maven配置。
OK,Maven项目搭建成功,如图:
2、创建服务注册中心
项目名称:register-server。威哥直接上图操作说明。
如果上面点击下一步没有反应,这个可以使用国内阿里代理来操作,国内代理地址:https://start.aliyun.com。
项目创建成功,这个之后需要来检查pom配置。pom.xml配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.william</groupId>
<artifactId>spring</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>register-server</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.2.6.RELEASE</spring-boot.version>
<spring-cloud.version>Hoxton.SR1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</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>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.2.6.RELEASE</version>
</plugin>
</plugins>
</build>
</project>
配置application或者yml。这里威哥说明下,yml配置文件以树形结构组成,其优先级高于application,会在application之前先假装yml,如果同时存application和yml,那么application将会因为后加载而覆盖yml配置。下面威哥把2种配置都提供出来。
application.properties配置如下:
server.port=9010
eureka.instance.hostname=127.0.0.1
#禁止自己当做服务注册
eureka.client.register-with-eureka=false
#屏蔽注册信息
eureka.client.fetch-registry=false
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/
application.yml配置如下:
server:
port: 9010
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
RegisterServerApplication启动项代码:
@SpringBootApplication
@EnableEurekaServer
public class RegisterServerApplication {
public static void main(String[] args) {
SpringApplication.run(RegisterServerApplication.class, args);
}
}
上面@EnableEurekaServer的意思是:申明此处为服务注册中心。
调试运行起来,之后在浏览器输入:http://localhost:9010/
出现上面效果图,证明Eureka注册中心发布成功。
3、创建服务生产者
项目名称:service-producer,创建步骤同时,只是勾选Eureka选项时区别下,如下:
检查pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.william</groupId>
<artifactId>spring</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>service-producer</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR3</spring-cloud.version>
</properties>
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</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>
配置application.properties:
eureka.client.service-url.defaultZone=http://localhost:9010/eureka/
server.port=9011
spring.application.name=service-producer
test=Hellow,I am WeiGe,Welocme to Java World
server.tomcat.uri-encoding=utf-8
spring.http.encoding.charset=utf-8
spring.http.encoding.enabled=true
spring.http.encoding.force=true
spring.cloud.loadbalancer.ribbon.enabled=false
启动项ServiceConsumerApplication:
@SpringBootApplication
@EnableDiscoveryClient
@RestController
public class ServiceProducerApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceProducerApplication.class, args);
}
}
新建TestController:
package com.william.producer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("service-producer-test")
public class TestController {
@Value("${test}")
String test;
@Value("${spring.application.name}")
String appionName;
@Value("${server.port}")
String port;
@RequestMapping(value = "/mytest")
public String mytest(@RequestParam String name) {
return String.format("Hello %s,%s,该信息从服务:%s,端口:%s吐出。", name, test, appionName, port);
}
}
ok,启动service-server和service-producer,可以看到生产者已经注册到了Eureka服务注册中心。
现在跟随威哥来测试一把服务是不是通的,打开浏览器或者postMan输入:
http://localhost:9011/service-producer-test/mytest?name=威哥
OK,上面测试证明服务OK。接下来威哥要新建Facade层,用来做Request和Response层使用,因为上面做的服务都是最简单的url传参,但是实际使用中我们都是使用json对象来传参的。
4、创建Facade项目:service-facade
具体步骤都可以同时,也可以创建j2ee的项目,都行,威哥是这样创建的:
注意:
之后新建request和response:
威哥贴一下pom.xml内容,可能有些同学需要,注意,需要安装下lombok插件。
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.william</groupId>
<artifactId>facade</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>service-facade</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR3</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-function-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</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>
GetCustomerRequest代码:
package com.william.facade.request;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import lombok.Data;
import javax.validation.constraints.NotNull;
@Data
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE)
public class GetCustomerRequest {
@NotNull(message = "pkid不能为空。")
private Integer pkid;
}
GetCustomerResponse代码:
package com.william.facade.reponse;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import lombok.Data;
@Data
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE)
public class GetCustomerResponse {
private Integer pkid;
private String customerName;
private String company;
private String sex;
}
ok,facade项目完毕,后续威哥会使用到。
5、创建消费者:service-consumer
创建步骤通服务生产者
得到如下项目结构:
pom.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.william</groupId>
<artifactId>consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>service-consumer</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR3</spring-cloud.version>
</properties>
<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-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</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>${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>
application.properties配置如下:
eureka.client.service-url.defaultZone=http://localhost:9010/eureka/
server.port=9012
spring.application.name=service-consumer
server.tomcat.uri-encoding=utf-8
spring.http.encoding.charset=utf-8
spring.http.encoding.enabled=true
spring.http.encoding.force=true
spring.cloud.loadbalancer.ribbon.enabled=false
启动项ServiceConsumerApplication 内容:
package com.william.consumer;
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.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableDiscoveryClient
@RestController
public class ServiceConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceConsumerApplication.class, args);
}
@Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
}
注意:上面重写了restTemplate,这个是为了演示基础的Ribbon消费RPC服务,但是威哥已经不使用它了,主要是为了完整的给同学们演示下。
调试起来service-consumer,再刷新下服务注册中心:会发现消费者也注入到了服务注册中心,这样是为了后面连接保持心跳,才能取到RPC调用所需的服务路由,Eureka是客户端负载均衡,会在消费者这一侧事先存储一份生产者的服务路由,这是需要保持心跳机制的,也是为后续威哥介绍Feign做的铺垫。
6、service-consumer开始消费服务
新建一个TestController:
package com.william.consumer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("service-consumer")
public class TestController {
@Autowired
RestTemplate restTemplate;
@RequestMapping("/sayHello")
public String sayHello(@RequestParam String info){
return restTemplate.getForObject(String.format("http://service-producer/service-producer-test/mytest?name=%s", info), String.class);
}
}
运行起来,在浏览器输入:http://localhost:9012/service-consumer/sayHello?info=吴三桂
ok,到此我们已经使用Ribbon成功消费了服务。基本上同学们已经算是搭建成功了SpringCloud框架。如果不想继续跟着威哥深造,可以就此打住退出了,记得帮威哥点赞哈。
7、开启Feign的愉快模式
新建service-remote项目,同facade,步骤威哥就不再截图了,需要删除启动项和resources资源包(用不上)。
此时威哥就用上了service-facade。
但是除了删除启动类,还需要额外加入web引用,可以在pom中灌进去,也可以按照威哥下面操作把web项添加进去:
最终得到的项目结构:
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.william</groupId>
<artifactId>remote</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>service-remote</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR3</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-function-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.william</groupId>
<artifactId>facade</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.william</groupId>
<artifactId>facade</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</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>
新建CustomerRemote接口:
package com.william.remote;
import com.william.facade.reponse.GetCustomerResponse;
import com.william.facade.request.GetCustomerRequest;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import javax.validation.Valid;
import java.util.List;
@FeignClient(name = "service-producer")
public interface CustomerRemote {
@PostMapping(value = "/service-producer/getCustomer")
List<GetCustomerResponse> getCustomer(@RequestBody(required = true) @Valid GetCustomerRequest request);
}
8、消费者通过Feign以RPC形式调用生产者的服务
现在再回头到消费者service-consumer,其启动项需求添加注解:@EnableFeignClients(basePackages = { "com.william.remote" })
新建CustomerController:
package com.william.consumer;
import com.william.facade.reponse.GetCustomerResponse;
import com.william.facade.request.GetCustomerRequest;
import com.william.remote.CustomerRemote;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
import java.util.List;
@RestController
@RequestMapping("service-consumer")
public class CustomerController {
@Autowired
private CustomerRemote customerRemote;
/**
* 获取客户信息
* @param request
* @return
* @author xuwei
* @since 2020-04-11
*/
@PostMapping(value = "/getCustomer")
public List<GetCustomerResponse> getCustomer(@RequestBody(required = true) @Valid GetCustomerRequest request) {
List<GetCustomerResponse> response = customerRemote.getCustomer(request);
return response;
}
}
ok,现在重新启动service-consumer,打开postman,本篇篇幅太长了,威哥就不介绍怎么引入swagger了。
到此本篇威哥分享完毕。大家记得帮威哥点赞啊。希望能够真正开启你的第一行Spring Cloud代码。
如果需要源码,请下载威哥上传的源码:https://download.csdn.net/download/xuwei_net/12324163。Maven依赖威哥没有上传哈,请自行更新依赖。