在学习SpringCloud遇到过许多坑,这里记录一下。
首先,新建一个maven pom工程,命名为spring-cloud-demo-parent,该工程作为父工程
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 http://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.1.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.huangbl</groupId>
<artifactId>spring-cloud-demo-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>spring-cloud-demo-parent</name>
<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.boot</groupId>
<artifactId>spring-boot-starter</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>${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>
一、创建服务注册中心
在spring-cloud-demo-parent中新建一个模块cloud-demo-registry-center,其pom.xml的内容为
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.huangbl</groupId>
<artifactId>spring-cloud-demo-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>cloud-demo-registry-center</artifactId>
<packaging>war</packaging>
<name>cloud-demo-registry-center Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
<build>
<finalName>cloud-demo-registry-center</finalName>
<plugins>
<!--<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.huangbl.cloud.registry.center.Application</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal><!--可以把依赖的包都打包到生成的Jar包中-->
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
新建包名com.huangbl.cloud.registry.center,并在该包下建立Application和ServletInitializer.java两个类,其内容分别为:
Application.java
package com.huangbl.cloud.registry.center;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* @className Application
* @description TODO
* @author huangbl
* @date 2019/02/14 17:01
* @return
*/
@EnableEurekaServer
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
其中,@EnableEurekaServer注解标识这是一个服务注册中心
ServletInitializer.java
package com.huangbl.cloud.registry.center;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
public class ServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}
在src/main/resources下新建application.properties
server.port=8081
server.servlet.context-path=/cloud-demo-registry-center
spring.application.name=eureka-cloud-demo-registry-center
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/
其中
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
表示这是一个eureka server,否则程序会尝试注册成eureka client。
此时,运行Application.java,地址栏输入“http://127.0.0.1:8081/cloud-demo-registry-center/”可进入eureka server界面
二、创建服务提供者
在spring-cloud-demo-parent内建立一个maven模块cloud-demo-provider,其pom.xml内容为
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.huangbl</groupId>
<artifactId>spring-cloud-demo-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>cloud-demo-provider</artifactId>
<packaging>war</packaging>
<name>cloud-demo-provider Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
<build>
<finalName>cloud-demo-provider</finalName>
<plugins>
<!--<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.huangbl.cloud.provider.Application</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal><!--可以把依赖的包都打包到生成的Jar包中-->
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
新建包com.huangbl.cloud.provider,在该包下建立Application.java和ServletInitializer.java两个文件,文件内容和cloud-demo-registry-center中的大致相同,唯一不同的是Application.java中将@EnableEurekaServer换成@EnableEurekaClient
在src/main/resources下新建application.properties,文件内容为
server.port=8082
server.servlet.context-path=/cloud-demo-provider
spring.application.name=eureka-cloud-demo-provider
eureka.client.service-url.defaultZone=http://127.0.0.1:8081/cloud-demo-registry-center/eureka
其中spring.application.name是向服务注册中心注册时的Application名称,后面服务消费者访问服务提供者相关接口时也需要用到,而eureka.client.service-url.defaultZone是连接服务注册中心的地址,这里有个坑需要注意一下,如果服务注册中心(cloud-demo-registry-center)设置了server.servlet.context-path,假设此时该值为cloud-demo-registry-center,则cloud-demo-provider中eureka.client.service-url.defaultZone的值需要在eureka前加上cloud-demo-registry-center,即“http://127.0.0.1:8081/cloud-demo-registry-center/eureka”,否则为“http://127.0.0.1:8081/eureka”。
在com.huangbl.cloud.provider下新建controller包,并创建UserController.java
package com.huangbl.cloud.provider.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping("/find")
public String find(String nickName) {
String result = "Hello " + nickName + ",this is cloud-demo-provider";
return result;
}
}
三、创建服务消费者
同样的道理,在spring-cloud-demo-parent中建立子模块cloud-demo-consumer,其pom.xml内容为
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.huangbl</groupId>
<artifactId>spring-cloud-demo-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>cloud-demo-consumer</artifactId>
<packaging>war</packaging>
<name>cloud-demo-consumer Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</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-netflix-ribbon</artifactId>
</dependency>
</dependencies>
<build>
<finalName>cloud-demo-consumer</finalName>
<plugins>
<!--<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.huangbl.cloud.consumer.Application</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal><!--可以把依赖的包都打包到生成的Jar包中-->
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
新建com.huangbl.cloud.consumer包,在该包下建立Application.java和ServletInitializer.java文件
Application.java
package com.huangbl.cloud.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.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
/**
* @className Application
* @description TODO
* @author huangbl
* @date 2018/11/26 17:01
* @return
*/
@EnableEurekaClient
@EnableDiscoveryClient
@SpringBootApplication
public class Application {
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
由于本文中服务与服务之间的调用采用ribbon+restTemplate(ribbon是一个负载均衡客户端,如果服务提供者有多个,则会自动选择其中一个)的方式,所以需要服务启动的时候注入RestTemplate。
ServletInitializer.java内容与前面的一样
在src/main/resources下新建application.properties
server.port=8083
server.servlet.context-path=/cloud-demo-consumer
spring.application.name=eureka-cloud-demo-consumer
eureka.client.service-url.defaultZone=http://127.0.0.1:8081/cloud-demo-registry-center/eureka
在com.huangbl.cloud.consumer下新建controller包,创建TestController.java
package com.huangbl.cloud.consumer.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("/test")
public class TestController {
@Autowired
private RestTemplate restTemplate;
@RequestMapping("/index")
public String index() {
String result = restTemplate.getForObject("http://EUREKA-CLOUD-DEMO-PROVIDER/cloud-demo-provider/user/find?nickName=sheep", String.class);
return result;
}
}
上面的代码就完成了调用服务生产者的接口,其中的“EUREKA-CLOUD-DEMO-PROVIDER”就是服务提供者中配置的spring.application.name(这里有个坑,访问的名称需要以http://127.0.0.1:8081/cloud-demo-registry-center/界面上显示的为准,界面显示的为全大写,而我设置的是小写),“http://EUREKA-CLOUD-DEMO-PROVIDER”会在请求时替换成实际的服务提供者的ip和端口,不能直接写成ip+端口的方式,这样无法请求而且也达不到负载均衡的效果。