一、构建SpringCloud项目
1. 首先创建一个maven工程,然后将src文件删除,只保留一个pom文件作为父pom文件。然后在pom文件中添加相对应的内容。
<groupId>com.cloud</groupId>
<artifactId>mycloud</artifactId>
<version>1.0-SNAPSHOT</version>
<modules> <!--表示有多少个子模块-->
<module>cloud-provider</module>
<module>cloud-consumer</module>
<module>cloud-api-commons</module>
<module>cloud-eureka-server</module>
<module>cloud-eureka-server-7002</module>
<module>cloud-provider-8082</module>
</modules>
<!--表示这是一个pom总工程-->
<packaging>pom</packaging>
<!--这里需要用dependencyManagement标签-->
<dependencyManagement>
<dependencies>
<!--spring boot 2.2.2-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.2.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--spring cloud Hoxton.SR1 引用H版的springcloud-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependencyManagement>
tips:maven的dependencyManagement和dependencies的区别
dependencyManagement会出现在父pom文件中,其子模块就不不用申明版本号和groupID;dependencyManagement并不会导入jar然而,dependencies会导入jar包。
2. 然后在当前工程添加模块总体工程目录结构如下:
3. 构建共用的代码和实体类模块
这个模块的pom文件是为当前模块服务的,不需要配置yml文件等,如果其他模块用到其实体类等直接通过pom文件进行导入即可
4. 构建服务消费者
现在pom文件中导入相关jar包
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
<!--热部署依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--导入自己的实体类-->
<dependency>
<groupId>com.cloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- eureka的客户端jar包 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
完成以后编写application.yml文件。
server:
port: 8080 # 定义端口号
spring:
application:
name: cloud-order-service # 定义服务名称
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 定义当前操作的数据源
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/****?useUnicode=true&&useSSL=false&&characterEncoding=UTF-8&&serverTimezone=GMT%2B8
username: ****
password: ****
eureka:
client:
register-with-eureka: true # 是否向注册中心注册
fetch-registry: true # 表示自己不是注册中心,需要去检索服务
service-url:
# defaultZone: http://localhost:7001/eureka/ 单机版
defaultZone: http://eureka7001.com:7001/eureka, http://eureka7002.com:7002/eureka # 集群的写法
然后编写Controller在编写主启动类:
Controller
@RestController
@Slf4j // 打印日志用
public class OrderController {
// 这里不能写成http://localhost:8081,这样就写死了,而是写成微服务的名称,如果需要负载均衡还需要编写一个配置类。
public static final String url = "http://CLOUD-SERVICE"; //
// 使用带有rest风格的请求
@Resource
private RestTemplate restTemplate;
@GetMapping(value = "consumer/payment/getPayment/{id}")
public CommentResult<Payment> getPayment(@PathVariable("id") Integer id){
// 进行get请求,第一个参数是url,第二个是返回对象的类型
return restTemplate.getForObject(url+"/payment/getPayment/"+id, CommentResult.class);
// 进行post请求 第一个参数是地址,第二个是参数,第三个是返回对象,服务提供者获取信息时需要在参数接收时加上@RequestBody注解进行参数的获取
restTemplate.postForObject(url, id, CommentResult.class);
}
}
配置类:
@Configuration
public class applicationContextConfig {
@Bean
@LoadBalanced // 负载均衡注解
public RestTemplate getRestTemplate(){
return new RestTemplate(); // rest风格
}
}
主启动类:
@SpringBootApplication
@EnableEurekaClient //表示这个是eureka的客户端
public class OrderMain {
public static void main(String[] args) {
SpringApplication.run(OrderMain.class, args);
}
}
工程目录结构:
5. 构建服务提供者
首先需要在pom文件中导入jar包
<dependencies>
<!-- 导入eureka的服务端jar包 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
编写yml文件
server:
port: 8082
spring:
application:
name: cloud-service
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 定义当前操作的数据源
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/lesson?useUnicode=true&&useSSL=false&&characterEncoding=UTF-8&&serverTimezone=GMT%2B8
username: root
password: zyz521
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
# defaultZone: http://localhost:7001/eureka/ 单机版
# 集群设置
defaultZone: http://eureka7001.com:7001/eureka, http://eureka7002.com:7002/eureka
instance:
instance-id: payment8082
prefer-ip-address: true # 显示ip地址
# 关闭eureka的自我保护机制
lease-renewal-interval-in-seconds: 1 # 客户端向服务端你发送心跳的时间间隔默认是30秒
lease-expiration-duration-in-seconds: 2 # 服务端收到最后一次心跳等待的最长时间 默认是90秒
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.cloud.springcloud.entities # 所有entity所在别名类的包
编写业务类和主启动类
@RestController
@Slf4j
public class PaymentController {
@Resource
private PaymentService paymentService;
@Value("${server.port}") // 从配置文件读取端口号
private String serverPort;
@PostMapping(value = "payment/create")
public CommentResult create(@RequestBody Payment payment){
int result = paymentService.create(payment);
return new CommentResult(200, "success"+serverPort, result);
}
@GetMapping(value = "payment/getPayment/{id}")
public CommentResult getPayment(@PathVariable("id") Integer id){
Payment payment = paymentService.getPayment(id);
return new CommentResult(200, "success"+serverPort, payment);
}
}
在controller里面调用的是service接口,在impl包下面才是接口的实现
接口:
public interface PaymentService {
public Payment getPayment(@Param("id") Integer id);
}
实现类:
@Service // 需要实现接口
public class PaymentService implements com.cloud.springcloud.service.PaymentService {
@Resource
private PaymentDao paymentDao;
public Payment getPayment(@Param("id") Integer id){
return paymentDao.getPayment(id);
}
}
主启动类:
@SpringBootApplication
@EnableEurekaClient // 表示当前是eureka的客户端
public class PaymentMain8082 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8082.class, args);
}
}
工程目录结构:
6. 构建注册中心
首先需要编写pom文件
<dependencies>
<!-- 导入eureka的服务端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
</dependencies>
然后编写yml文件
server:
port: 7002
eureka:
instance:
hostname: eureka7002.com # 服务端实例名称
client:
register-with-eureka: false # 是否向注册中心注册自己
fetch-registry: false # false表示自己就是注册中心,并不需要 去检索服务
service-url:
defaultZone: http://eureka7001.com:7001/eureka/ # 查询服务和注册服务都需要这个地址
server:
# 关闭自我保护
enable-self-preservation: false # 关闭自我保护
eviction-interval-timer-in-ms: 2000 # 设置心跳时间
编写主启动类:
@SpringBootApplication
@EnableEurekaServer // 表示这是eureka的服务端
public class EurekaMain7002 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7002.class,args);
}
}
工程目录:
7. eureka注册中心集群设置
主要遵循一个原则:相互注册相互守望
在第一个注册中心的yml文件配置
eureka:
instance:
hostname: eureka7002.com
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka/ # 另外其他的注册中心地址
在第二个注册中心的yml文件配置
eureka:
instance:
hostname: eureka7001.com
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://eureka7002.com:7002/eureka/ # 另外其他的注册中心地址
8. eureka的自我保护
会尝试保护其微服务的信息,不再删除微服务注册表中的数据,也就是不会注销任何微服务,某时刻微服务不可用,eureka不会对其进行清理依旧会保存信息 是cap里面的ap分支。
如何禁止自我保护:
首先到服务中心进行eureka.server.enable-self-preservation = false,并设置心跳时间eviction-interval-timer-in-ms: 2000。
然后在客户端设置发送心跳的时间间隔 lease-renewal-interval-in-seconds: 1和服务端收到最后一次心跳等待的最长时间 lease-expiration-duration-in-seconds: 2 。
9. 服务发现
这个东西并不是在eureka中出现的,而是可以在多种注册中心进行使用
首先需要在主启动类上添加@EnableDiscoveryClient 注解
@RestController
@Slf4j
public class PaymentController {
// 服务发现
@Resource
private DiscoveryClient discoveryClient;
@GetMapping(value = "payment/discovery")
public Object discovery(){
// 得到服务列表
List<String> services = discoveryClient.getServices();
for(String ele: services){
System.out.println(ele);
}
// 第二种通过id获取服务列表
List<ServiceInstance> instanceList = discoveryClient.getInstances("cloud-service");
for (ServiceInstance instance : instanceList) {
System.out.println(instance.getInstanceId()); // 获取每个服务的详细信息
}
return this.discoveryClient;
}
}
二、eureka现在已经停止维护,更多的倾向于zookeeper、consul和nacous等注册中心。