idea项目创建
1.创建一个project,然后把src目录删掉
2.修改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>
<groupId>org.tang</groupId>
<artifactId>springcloud</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>springcloud-api</module>
<module>springcloud-provider-dept-8001</module>
<module>springcloud-consumer-dept80</module>
<module>springcloud-eureka-7001</module>
</modules>
<!--1. 打包方式 pom-->
<packaging>pom</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.16.18</lombok.version>
</properties>
<!-- 2. 父工程 管理-->
<dependencyManagement>
<!-- 2.1 供子工程依赖-->
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.2.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 2.1 springCloud的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--2.1 SpringBoot-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.4.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--2.2 数据库-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!-- 2.3 SpringBoot 启动器-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!-- 2.4 日志测试~-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
3.创建module模块
创建springcloud-api,主要是实体类,跟数据库
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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>org.tang</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-api</artifactId>
<!-- 当前的Module自己需要的依赖,如果父依赖中已经配置了版本,这里就不用写了 -->
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>
package com.tang.springcloud.pojo;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@NoArgsConstructor
@Accessors(chain = true) //链式写法
public class Dept implements Serializable {
// 实体类 orm-> 表
private Long deptno; //主键
private String dname;
//这个数据存在数据库的字段,微服务,一个服务对应一个数据库
private String db_source;
public Dept(Long deptno, String dname, String db_source) {
this.deptno = deptno;
this.dname = dname;
this.db_source = db_source;
}
/**
* 链式写法
* Dept dept = new Dept()
* dept.setDeptNo(11).setDname('ssss').setDb_source('001')
* */
}
4.创建provider,服务提供者
创建module模块,springcloud-provider-dept-8001
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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>org.tang</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-provider-dept-8001</artifactId>
<dependencies>
<!--导入Eureka Server依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
<version>1.4.6.RELEASE</version>
<!--去除jackson-dataformat-xml,否则会返回xml文件,而不是JSON-->
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 我们需要拿到实体类,所以要配置api module-->
<dependency>
<groupId>org.tang</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- mybatis整合Springboot -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!-- junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- jetty-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<!-- 热部署
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
-->
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>
server:
port: 8001
#mybaties 配置
#mybaties:
# type-aliases-package: com.tang.springcloud.pojo
# config-location: classpath:mybatis/mybatis-config.xml
# mapper-locations: classpath:mybatis/mapper/*.xml
#spring 配置
spring:
application:
name: springcloud-provider-dept
# datasource:
# type: com.alibaba.druid.pool.DruidDataSource
# driver-class-name: org.gjt.mm.mysql.Driver
# url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8
# username: root
# password: 123456
#Eureka配置
eureka:
instance:
instance-id: springcloud-provider-dept8001 #修改eureka上的默认描述信息
# hostname: provider8001 # Eureka服务端的实例名称
client:
service-url: #监控页面
# this.serviceUrl.put("defaultZone", "http://localhost:8761/eureka/");
# defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/
defaultZone: http://localhost:7001/eureka/
#info配置
info:
app.name: tangshen-springcloud
company.name: www.duxiaowei.com
package com.tang.springcloud.service;
import com.tang.springcloud.pojo.Dept;
import java.util.List;
public interface DeptService {
// public boolean addDept(Dept dept);
public Dept queryById(Long id);
// public List<Dept> queryAll();
}
package com.tang.springcloud.service;
//import com.tang.springcloud.dao.DeptDao;
import com.tang.springcloud.pojo.Dept;
import lombok.experimental.Accessors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@Accessors(chain = true) //链式写法
public class DeptServiceImpl implements DeptService{
// @Autowired
// private DeptDao deptDao;
// @Override
// public boolean addDept(Dept dept) {
// return deptDao.addDept(dept);
// }
@Override
public Dept queryById(Long id) {
// 造一个对象
Dept dept = new Dept();
System.out.println("DeptServiceImpl");
dept.setDeptno(11L).setDname("duxiaowei").setDb_source("db_source");
return dept;
}
// @Override
// public List<Dept> queryAll() {
// return deptDao.queryAll();
// }
}
package com.tang.springcloud.controller;
import com.tang.springcloud.pojo.Dept;
import com.tang.springcloud.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
//提供Restfu服务
@RestController
public class DeptController {
@Autowired
private DeptService deptService;
//获取一些配置的信息,得到具体的微服务
@Autowired
private DiscoveryClient client;
@GetMapping("/dept/get/{id}")
public Dept get(@PathVariable("id") Long id) {
System.out.println("controller");
return deptService.queryById(id);
}
//注册进来的微服务,获取一些消息
@GetMapping("/dept/discovery")
public Object discovery(){
//获取微服务列表的清单
List<String> services = client.getServices();
System.out.println("discovery==> services"+ services);
//得到一个具体的微服务信息,通过具体的微服务id,applicationName
List<ServiceInstance> instances = client.getInstances("SPRINGCLOUD-PROVIDER-DEPT");
for (ServiceInstance instance : instances) {
System.out.println("----------------------------------------");
System.out.println(
instance.getHost()+"\t"+
instance.getPort()+"\t"+
instance.getUri()+"\t"+
instance.getServiceId()+"\t"
);
}
return this.client;
}
}
package com.tang.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
//启动类
@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
@EnableEurekaClient //开启Eureka客户端注解,在服务启动后自动向注册中心注册服务
@EnableDiscoveryClient //服务发现
public class DeptProvider_8001 {
public static void main(String[] args) {
SpringApplication.run(DeptProvider_8001.class,args);
}
}
可以先关闭Eureka开关,启动,调用接口测试,接口服务是否可用
5.创建Eureka注册中心 ,springcloud-eureka-7001
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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>org.tang</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-eureka-7001</artifactId>
<dependencies>
<!--导入Eureka Server依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--热部署工具-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>
server:
port: 7001
#Eureka
eureka:
instance:
hostname: localhost # Eureka服务端的实例名称
client:
register-with-eureka: false #标识是否想注册中心注册自己
fetch-registry: false #fetch-registry如果为false表示自己为注册中心
service-url: #监控页面
# this.serviceUrl.put("defaultZone", "http://localhost:8761/eureka/");
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
# defaultZone: http://localhost:7002/eureka/,http://localhost:7003/eureka/
package com.tang.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer //服务端的启动类,可以接受别人注册进来~
public class EurekaServer_7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaServer_7001.class,args);
}
}
测试
注册中心:http://localhost:7001/
服务提供者:http://localhost:8001/dept/discovery
6. 消费者,
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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>org.tang</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-consumer-dept80</artifactId>
<dependencies>
<!--导入Eureka Server依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
<version>1.4.6.RELEASE</version>
<!--去除jackson-dataformat-xml,否则会返回xml文件,而不是JSON-->
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.tang</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>
server:
port: 80
#spring 配置,应用名
spring:
application:
name: springcloud-customer
#Eureka配置
eureka:
instance:
instance-id: springcloud-customer-dept80 #修改eureka上的默认描述信息
# hostname: provider8001 # Eureka服务端的实例名称
client:
service-url: #监控页面
# this.serviceUrl.put("defaultZone", "http://localhost:8761/eureka/");
# defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/
defaultZone: http://localhost:7001/eureka/
package com.tang.springcloud.controller;
import com.tang.springcloud.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class DeptConsumerController {
//理解:消费者,不应该有service层
//Restful,
// public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables)
//使用RestTemplate访问restful接口非常的简单粗暴且无脑
//(url,requestMap,ResponseBean.class) 这三个参数分别代表
//REST请求地址,请求参数,Http响应转换 被 转换成的对象类型
@Autowired
private RestTemplate restTemplate;//提供多种便捷访问远程http服务的方法,简单的Restful服务模板
// private static final String REST_URL_PREFIX = "http://localhost:8001";
private static final String REST_URL_PREFIX = "http://localhost:8001";
@GetMapping("/customer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id) {
System.out.println("consumer------");
System.out.println(REST_URL_PREFIX+"/dept/get/"+id);
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id,Dept.class);
}
}
package com.tang.springcloud.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ConfigBean {
//@Configuration = spring applicationContext.xml
// 配置bean
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
package com.tang.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient //开启Eureka客户端注解,在服务启动后自动向注册中心注册服务
public class DeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_80.class,args);
}
}
测试
Eureka注册中心
注册中心概述
注册中心:提供服务注册和发现功能,维护了一张服务列表,登记了有哪些服务提供者,然后服务消费者每次请求这张登记表来进行服务调用。
服务提供者:提供服务的模块,需要把自己注册到注册中心。
服务消费者:从注册中心获取服务列表,向服务提供者请求服务。
- 心跳
因为服务提供者可能故障,所以设有保活机制—-心跳检测。
心跳:提供者定期发送消息向Eureka刷新自己的状态
- 服务注册
服务提供者在启动时,会检测配置属性中的:eureka.client.register-with-erueka=true参数是否正确,事实上默认就是true。如果值确实为true,则会向EurekaServer发起一个Rest请求,并携带自己的元数据信息,Eureka Server会把这些信息保存到一个双层Map结构中。第一层Map的Key就是服务名称,第二层Map的key是服务的实例id。(第二层Map为了支持服务提供者多机集群)
- 高可用
修改Euraka配置文件,把EurekaServer自己也作为一个服务,向其他注册中心进行注册。
就是集群,水平扩展,在其他机器上部署注册中心,然后注册中心之间互相调用。出现单机故障时,存活的注册中心继续提供服务注册和发现功能。
- 服务续约
在注册服务完成以后,服务提供者会维持一个心跳(定时向EurekaServer发起请求),告诉EurekaServer:“我还活着”。这个我们称为服务的续约(renew);
- 失效剔除
有些时候,我们的服务提供方并不一定会正常下线,可能因为内存溢出、网络故障等原因导致服务无法正常工作。Eureka Server需要将这样的服务剔除出服务列表。因此它会开启一个定时任务,每隔60秒对所有失效的服务(超过90秒未响应)进行剔除。
可以通过eureka.server.eviction-interval-timer-in-ms参数对其进行修改,单位是毫秒,生成环境不要修改。
- 保护模式
这是触发了Eureka的自我保护机制。当一个服务未按时进行心跳续约时,Eureka会统计最近15分钟心跳失败的服务实例的比例是否超过了85%。在生产环境下,因为网络延迟等原因,心跳失败实例的比例很有可能超标,但是此时就把服务剔除列表并不妥当,因为服务可能没有宕机。Eureka就会把当前实例的注册信息保护起来,不予剔除。生产环境下这很有效,保证了大多数服务依然可用。
但是这给我们的开发带来了麻烦, 因此开发阶段我们都会关闭自我保护模式: