按照下图创建工程:
首先先创建一个工作集,方便项目管理,在工作集下面创建分布式集群项目。这里有个工程名命名规范,参照工程名图的命名规范,这样方便管理。
创建父工程:
- 创建一个maven空项目的父工程,注意这里的父工程是pom类型的,图1所示,在按照图2步骤创建。图3是创建父工程的操作步骤,在父工程里主要定义版本信息,供它的子模块使用,父工程如果定义了一些依赖的版本信息,那么它的子模块只需要添加依赖就行了,不需要写版本信息,父工程里没有的依赖或者没有定义的依赖版本信息,子模块又需要用的话,可以在子模块里自己定义版本信息和添加依赖,
<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>com.lyj.springcloud</groupId>
<artifactId>microservicecloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<!-- 新建父工程microservicecloud,切记是packageing是pom模式 主要是定义pom文件,将后续的各个子模块公用的jar包统一提出来,
类似一个抽象父类 -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!--指定每次编译的时候都是以java8版本进行编译 ====start -->
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<!--指定每次编译的时候都是以java8版本进行编译 ====end -->
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.16.18</lombok.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.9.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.0.4</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.31</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
<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>
</dependencies>
</dependencyManagement>
<build>
<!-- 这里的 配置是使在Eureka的web界面能够访问服务的info界面(服务的详细信息)==start -->
<!-- finalName指父工程的名字 -->
<finalName>microservicecloud</finalName>
<!-- resources:资源,允许你访问的资源
directory:允许你访问这个路径下的资源
filtering:访问过滤开启-->
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<!-- plugins:引入插件的意思,
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
上面的插件是负责解析和解读的-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<!-- configuration:解析配置的意思,
<delimiter>$</delimiter>:意思就是以$开头和以$结尾的
在<directory>src/main/resources</directory>路径下面
的信息,我就能读取,即要显示的信息-->
<configuration>
<delimiters>
<delimiter>$</delimiter>
</delimiters>
</configuration>
</plugin>
</plugins>
<!-- 这里的 配置是使在Eureka的web界面能够访问服务的info界面(服务的详细信息)==end -->
</build>
<!-- 创建microservice-api服务,自动在父工程pom文件里引进module配置 -->
<modules>
<module>microservicecloud-api</module>
<module>microservicecloud-provider-dept-8001</module>
<module>microservicecloud-consumer-dept-80</module>
<module>microservicecloud-eureka-7001</module>
<module>microservicecloud-eureka-7002</module>
<module>microservicecloud-eureka-7003</module>
</modules>
</project>
创建公共子模块(Module):
除了父工程是pom类型的工程,后面的公共子模块和服务提供者工程和服务消费者工程都是jar包类型。并且创建都是在父工程下创建module模块,创建完成后检查父工程中的pom文件是否添加了创建的module,如果自动添加了,则创建正确。
<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>
<!-- 本Module开发步骤
1、新建microservicecloud-api创建完成后查看pom文件变化
2、修改pom
3、新建Entity且配合lombok使用
4、mvn clean&install(打成jar包)后给其他模块引用,达到通用的目的。
也即需要用到部门实体的话,不用每个工程都定义一份,直接引用本模块即可 -->
<parent>
<!-- 子类里面显示声明才能有明确的继承表现,
无意外就是父类的默认版本否则自己定义-->
<groupId>com.lyj.springcloud</groupId>
<artifactId>microservicecloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<!-- 当前Module,就是我自己叫什么名字 -->
<artifactId>microservicecloud-api</artifactId>
<!-- 当前Module需要用的jar包,按自己需求添加,
入股父类已经包含了,可以不用 写版本号-->
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
这里添加了一个lombok依赖主要是用来简化和方便写我们的Javabean,添加这个依赖,可以不用写getter和setter方法、构造方法、toString()等。直接在相应的Javabean上面添加相应的注解即可。
图4是公共子模块的架构图:
在这里创建了一个公共的Javabean,供后面服务提供者和服务消费者使用。如下:
package com.lyj.springcloud.entities;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@SuppressWarnings("serial")//如果有类上或者方法上或者参数上有警告。添加此注解可以选择压制
//@AllArgsConstructor//添加传参构造函数的注解,依赖于lombok(俗称小辣椒)的依赖
@NoArgsConstructor//添加构造空构造函数的注解
@Data//添加使每个参数都生成getter和setter方法
@Accessors(chain=true)//添加链式风格访问的注解
public class Dept implements Serializable//Dept(Entity) ORM mysql->Dept(table) 类关系映射
{ //必须序列化
private Long deptno;//主键
private String dname;//部门名称
/**
* 来自哪个数据库,因为微服务架构可以一个服务对应一个数据库,
* 同一个信息被存在不同的数据库
*/
private String db_source;
// 检测是否能够自定义构造函数
// public Dept(String dname) {
// super();
// this.dname = dname;
// }
//
// //检测链式风格访问是否起作用
// public static void main(String[] args) {
// Dept dept=new Dept();
这里下面是检测
// dept.setDeptno(11l).setDname("RD").setDb_source("DB01");
// }
}
创建服务注册模块(cloud-server):
架构图5:
pom.xml配置:
<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>com.lyj.springcloud</groupId>
<artifactId>microservicecloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>microservicecloud</groupId>
<artifactId>microservicecloud-eureka-7001</artifactId>
<dependencies>
<!-- eureka-server服务端配置 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<!-- 修改后立即生效,热部署 ===start-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!--修改后立即生效,热部署===end-->
</dependencies>
</project>
创建application主程序:
记得在主程序上添加@EnableEurekaServer注解,开启服务,用来接收服务的注册。
package com.lyj.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer // Eureka服务器端启动类,接收其他微服务注册进来
public class EurekaServer7001_App {
public static void main(String[] args) {
SpringApplication.run(EurekaServer7001_App.class, args);
}
}
创建application.yml文件:
单机版的Eureka配置
server:
port: 7001
eureka:
# server:
# enable-self-preservation: false #禁用自我保护机制
instance:
hostname: localhost #eureka服务端的实例名称
client:
register-with-eureka: false #false 表示不向注册中心注册自己
#false表示自己就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
fetch-registry: false
service-url:
#设置与Eureka Server交互的地址查询服务和注册服务都需要这个地址
defaultZone: http://${eureka.instance.hostname}:${server.port}/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>
<parent>
<groupId>com.lyj.springcloud</groupId>
<artifactId>microservicecloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>microservicecloud-provider-dept-8001</artifactId>
<dependencies>
<!-- 引入自定义的api通用包,可以使用Dept部门的Entity -->
<dependency>
<groupId>com.lyj.springcloud</groupId>
<artifactId>microservicecloud-api</artifactId>
<!-- 下面指定的版本是活的,相当于,api通用包随意怎么变,这里都会自动更新,不影响 -->
<version>${project.version}</version>
</dependency>
<!-- 将微服务注册provider到Eureka注册中心中 ==start -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!-- 将微服务注册provider到Eureka注册中心中 ==end -->
<!-- 引入监控信息完善的依赖==start -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 引入监控信息完善的依赖==end -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</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>
</dependency>
<!-- 引入热部署,修改后立即生效===start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- 引入热部署,修改后立即自动发布和构建生效===end -->
</dependencies>
</project>
配置application.yml 文件:
server:
#指定服务器端口号8001
port: 8001
mybatis:
#mybatis配置文件所在路径
config-location: classpath:mybatis/mybatis.cfg.xml
#所有Entity别名类所在包
type-aliases-package: com.lyj.springcloud.entities
#mapper映射文件所在路径
mapper-locations:
- classpath:mybatis/mapper/**/*.xml
spring:
application:
# 当前应用(服务)起的名字
name: microservicecloud-dept
datasource:
#当前数据源操作类型
type: com.alibaba.druid.pool.DruidDataSource
#mysql驱动包
driver-class-name: com.mysql.jdbc.Driver
#数据库名称
url: jdbc:mysql://localhost:3306/cloudDB01
username: mysql
password: 15827318595
dbcp2:
min-idle: 5 #数据库连接池的最小维持连接数
initial-size: 5 #初始化连接数5个
max-total: 5 #设置最大连接数
max-wait-millis: 200 #s等待连接获取的最大超时时间
#配置Eureka
eureka:
#客户端注册进Eureka服务列表内
client:
service-url:
defaultZone: http://localhost:7001/eureka #(单机版服务器)
服务提供者详细架构图如下:
- 创建DeptDao访问数据库的接口:
package com.lyj.springcloud.dao;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import com.lyj.springcloud.entities.Dept;
@Mapper // 添加mybatis注解(mapper文件)
public interface DeptDao {
public boolean addDept(Dept dept);
public Dept findById(Long id);
public List < Dept > findAll();
}
- 创建DeptService接口:
package com.lyj.springcloud.service;
import java.util.List;
import com.lyj.springcloud.entities.Dept;
public interface DeptService {
/**
* 这里是对数据库访问的函数,比较靠近底层,为了比较符合rest的风格, 这里的函数名都是以靠近底层的命名方式命名
*
* @param dept
* @return
*/
public boolean add(Dept dept);
public Dept get(Long id);
public List < Dept > list();
}
- 创建接口实现类DeptServiceImpl:
package com.lyj.springcloud.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.lyj.springcloud.dao.DeptDao;
import com.lyj.springcloud.entities.Dept;
import com.lyj.springcloud.service.DeptService;
@Service("deptService")
public class DeptServiceImpl implements DeptService {
@Autowired
private DeptDao deptDao;
@Override
public boolean add(Dept dept) {
return deptDao.addDept(dept);
}
@Override
public Dept get(Long id) {
return deptDao.findById(id);
}
@Override
public List < Dept > list() {
return deptDao.findAll();
}
}
- 创建控制器:
package com.lyj.springcloud.controller;
import java.util.List;
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.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.lyj.springcloud.entities.Dept;
import com.lyj.springcloud.service.DeptService;
@RestController
public class DeptController {
@Autowired
private DeptService service;
/**
* 这里是引入服务发现的DiscoveryClient 注意这里的DiscoveryClient是引用这个 org.springframework.cloud.client.discovery.DiscoveryClient;
* 还需要在application的主程序中添加@EnableDiscoveryClient注解,开启服务发现功能
*/
@Autowired
private DiscoveryClient client;
@RequestMapping(value = "/dept/add", method = RequestMethod.POST)
public boolean add(@RequestBody Dept dept) {
return service.add(dept);
}
@RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
public Dept get(@PathVariable("id") Long id) {
return service.get(id);
}
@RequestMapping(value = "/dept/list", method = RequestMethod.GET)
public List < Dept > list() {
return service.list();
}
@RequestMapping(value = "/dept/discovery", method = RequestMethod.GET)
public Object discovery() {
List < String > list = client.getServices();
System.out.println("************" + list);
List < ServiceInstance > srvList = client.getInstances("MICROSERVICECLOUD-DEPT");
for (ServiceInstance eInstance : srvList) {
System.out.println(eInstance.getServiceId() + "\t" + eInstance.getHost() + "\t" + eInstance.getPort() + "\t"
+ eInstance.getUri());
}
return this.client;
}
}
- 创建application主程序 这里面配置了服务发现(服务发现用用的不多,主要是服务注册)
package com.lyj.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@EnableDiscoveryClient // 开启服务发现功能,控制器里的服务发现方法能正常运行。
@EnableEurekaClient // 本服务启动后会自动将服务注册进Eureka服务中心中
@SpringBootApplication
public class DeptProvider8001_App {
/**
* 使用服务发现功能步骤: 1、先要启动EurekaServer 2、再启动DeptProvider8001_App主启动类,需要 稍等一会 3、访问http://localhost:8001/dept/discovery
*
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
SpringApplication.run(DeptProvider8001_App.class, args);
}
}
下图是数据访问的路径,mapper.xml文件路径:
配置DeptMapper.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lyj.springcloud.dao.DeptDao">
<select id="findById" resultType="Dept" parameterType="Long">
select deptno dname,db_source from dept where deptno=#{deptno};
</select>
<select id="findAll" resultType="Dept">
select deptno,dname,db_source from dept;
</select>
<insert id="addDept" parameterType="Dept">
<!-- database()mysql自带的查询数据源的名字的()数据库的名字 -->
INSERT INTO dept(dname,db_source) VALUES(#{dname},DATABASE());
</insert>
</mapper>
配置mybatis.cfg.xml,这里可有可无,主要配置一些访问数据库的一些属性缓存之类的。如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="cacheEnabled" value="true"/><!-- 二级缓存开启 -->
</settings>
</configuration>
服务消费者配置:
服务消费者的开发流程图:
架构图:
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>
<parent>
<groupId>com.lyj.springcloud</groupId>
<artifactId>microservicecloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>microservicecloud-consumer-dept-80</artifactId>
<description>部门微服务消费者</description>
<dependencies>
<!-- 引入自己定义的api -->
<dependency>
<groupId>com.lyj.springcloud</groupId>
<artifactId>microservicecloud-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入热部署,修改后立即生效===start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- 引入热部署,修改后立即自动发布和构建生效===end -->
</dependencies>
</project>
配置application.yml文件
server:
port: 80 #访问时不用加端口号,因为浏览器的默认端口就是80,所以访问:localhosst/xxxxx
创建application主程序:
package com.lyj.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DeptConsumer80_App {
public static void main(String[] args) {
// TODO Auto-generated method stub
SpringApplication.run(DeptConsumer80_App.class, args);
}
}
创建Config.java 文件:
package com.lyj.springcloud.cfgbeans;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ConfigBean {
@Bean
public RestTemplate geRestTemplate() {
return new RestTemplate();
}
}
// boot--spring applicationContext.xml
//--@Configuration配置 ConfigBean=applicationContext.xml
//public UserService getUserService() {
// return new UserServiceImpl();
//}
/**
* applicationContext.xml==ConfigBean(@Configuration) <bean id="userService" class="com.lyj.tmall.UserServiceImpl">
* 这里的id相当于上面的方法类型UserService,class就相当于return的返回值,
*/
创建控制器:
package com.lyj.springcloud.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
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;
import com.lyj.springcloud.entities.Dept;
@RestController
public class DeptController_consumer {
/**
* RestTemplate提供了多种便捷访问远程Http服务的方法, 是一种简单便捷的访问restful服务模板类, 是spring提供的用于访问Rest服务的客户端模板工具集 用法:
* 使用restTemplate访问restful接口非常的简单粗暴无脑。 (url,requestMap,ResponseBean.class)这三个参数分别代表 REST请求地址、请求参数、HTTP响应转换被转换成的对象类型。
*
*/
@Autowired
private RestTemplate restTemplate;
private static final String TEST_URL_PREFIX = "http://localhost:8001";
@RequestMapping(value = "/consumer/dept/add")
public boolean add(Dept dept) {
return restTemplate.postForObject(TEST_URL_PREFIX + "/dept/add", dept, boolean.class);
// return restTemplate.getForObject(TEST_URL_PREFIX + "/dept/add", boolean.class, dept);
}
@RequestMapping(value = "/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id) {
return restTemplate.getForObject(TEST_URL_PREFIX + "/dept/get/" + id, Dept.class);
}
@SuppressWarnings("unchecked")
@RequestMapping(value = "/consumer/dept/list")
public List < Dept > list(Dept dept) {
return restTemplate.getForObject(TEST_URL_PREFIX + "/dept/list", List.class);
}
// 测试@EnableDiscoveryClient,消费者可以调用服务发现,消费者的application主程序不用添加@EnableDiscoveryClient
@RequestMapping(value = "/consumer/dept/discovery")
public Object discovery() {
return restTemplate.getForObject(TEST_URL_PREFIX + "/dept/discovery", Object.class);
}
}
数据库执行脚本:
-- drop database if exists cloudDB01;
CREATE DATABASE cloudDB01 CHARACTER SET UTF-8;
USE cloudDb01;
CREATE TABLE dept
(
deptno BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
dname VARCHAR(60),
db_source VARCHAR(60)
);
-- DATABASE()查询获取当前数据源(数据库)的名字
INSERT INTO dept(dname,db_source) VALUES('开发部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES('人事部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES('市场部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES('运维部',DATABASE());
SELECT * FROM dept;
INSERT INTO dept(dname,db_source) VALUES(123,DATABASE());
测试:
一上操作都是一个Eureka-server服务器的运行。
下面讲一下集群分布式开发:
集群开发步骤:
Eureka集群开发流程图:
集群配置,也就是服务消费者不动,只用增加服务器子模块的配置的数量即可。在父工程下创建服务器工程子模块
如下:
架构图:
配置7002工程和7003工程的pom文件,与7001pom文件一样,直接copy过来。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>
<parent>
<groupId>com.lyj.springcloud</groupId>
<artifactId>microservicecloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>microservicecloud-eureka-7002</artifactId>
<dependencies>
<!-- eureka-server服务端配置 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<!-- 修改后立即生效,热部署 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>
修改7002工程和7003工程的application主程序配置:
主程序配置一样,只不过类名不一样而已
package com.lyj.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer // Eureka服务器端启动类,接收其他微服务注册进来
public class EurekaServer7002_App {
public static void main(String[] args) {
SpringApplication.run(EurekaServer7002_App.class, args);
}
}
修改7001工程的application.yml配置文件,改为集群配置:
#单机版的Eureka配置
#server:
# port: 7001
#
#eureka:
## server:
## enable-self-preservation: false #禁用自我保护机制
# instance:
# hostname: localhost #eureka服务端的实例名称
# client:
# register-with-eureka: false #false 表示不向注册中心注册自己
# #false表示自己就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
# fetch-registry: false
# service-url:
# #设置与Eureka Server交互的地址查询服务和注册服务都需要这个地址
# defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
#
#集群Eureka配置,即把相同的服务部署到不同的服务器上运行,避免由于一台服务器异常而终止程序,
#集群配置可以在一台服务器发生异常的情况下,还能保持程序的正常运行
server:
port: 7001
eureka:
# server:
# enable-self-preservation: false #禁用自我保护机制
instance:
hostname: eureka7001.com #eureka服务端的实例名称
client:
register-with-eureka: false #false 表示不向注册中心注册自己
#false表示自己就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
fetch-registry: false
service-url:
# defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
defaultZone: http://eureka7002.com:7002,http://eureka7003.com:7003
#设置与Eureka Server交互的地址查询服务和注册服务都需要这个地址
# defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #(单机)
# defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
7002application.yml文件配置:
#集群Eureka配置,即把相同的服务部署到不同的服务器上运行,避免由于一台服务器异常而终止程序,
#集群配置可以在一台服务器发生异常的情况下,还能保持程序的正常运行
server:
port: 7002
eureka:
# server:
# enable-self-preservation: false #禁用自我保护机制
instance:
hostname: eureka7002.com #eureka服务端的实例名称
client:
register-with-eureka: false #false 表示不向注册中心注册自己
#false表示自己就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
fetch-registry: false
service-url:
#设置与Eureka Server交互的地址查询服务和注册服务都需要这个地址
# defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #(单机)
# defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7003.com:7003/eureka/
defaultZone: http://eureka7001.com:7001,http://eureka7003.com:7003
7003application.yml文件配置:
#集群Eureka配置,即把相同的服务部署到不同的服务器上运行,避免由于一台服务器异常而终止程序,
#集群配置可以在一台服务器发生异常的情况下,还能保持程序的正常运行
server:
port: 7003
eureka:
# server:
# enable-self-preservation: false #禁用自我保护机制
instance:
hostname: eureka7003.com #eureka服务端的实例名称
client:
register-with-eureka: false #false 表示不向注册中心注册自己
#false表示自己就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
fetch-registry: false
service-url:
#设置与Eureka Server交互的地址查询服务和注册服务都需要这个地址
# defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #(单机)
# defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
defaultZone: http://eureka7001.com:7001,http://eureka7002.com:7002
最重要的一点==修改映射文件:==打开C盘,找到这个路径下的hosts文件:C:\Windows\System32\drivers\etc
编辑hosts文件添加映射配置:
host文件中的Eureka
修改8001工程的application.yml文件里的defaultZone服务注册路径,具体配置如下:
server:
#指定服务器端口号8001
port: 8001
mybatis:
#mybatis配置文件所在路径
config-location: classpath:mybatis/mybatis.cfg.xml
#所有Entity别名类所在包
type-aliases-package: com.lyj.springcloud.entities
#mapper映射文件所在路径
mapper-locations:
- classpath:mybatis/mapper/**/*.xml
spring:
application:
# 当前应用(服务)起的名字
name: microservicecloud-dept
datasource:
#当前数据源操作类型
type: com.alibaba.druid.pool.DruidDataSource
#mysql驱动包
driver-class-name: com.mysql.jdbc.Driver
#数据库名称
url: jdbc:mysql://localhost:3306/cloudDB01
username: mysql
password: 15827318595
dbcp2:
min-idle: 5 #数据库连接池的最小维持连接数
initial-size: 5 #初始化连接数5个
max-total: 5 #设置最大连接数
max-wait-millis: 200 #s等待连接获取的最大超时时间
#配置Eureka
eureka:
#客户端注册进Eureka服务列表内
client:
service-url:
# defaultZone: http://localhost:7001/eureka #(单机版服务器)
# 集群配置(多台服务器共同使用)
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
#自定义实例的statusIP地址名字(主机名字:服务名称修改,不采用默认的名字)
instance:
instance-id: microservicecloud-dept8001
prefer-ip-address: true #访问路径可以显示IP地址
#配置Eurekaweb界面访问各个服务的的详细信息的info界面
info:
app.name: lyj-microservicecloud
company.name: www.lyj.com
build.artifactId: $project.artifactId$
build.version: $project.version$
最后依次启动服务器7001、7002、7003工程,和服务提供者工程。
测试:
依次访问:http://eureka7001.com:7001/
http://eureka7002.com:7002/
http://eureka7003.com:7003/
并且可以在这个三个界面里按照下图:可以点击1查看该服务的我们自己自定义的信息。
点击2或者3可以跳转到7002或者7003服务器,并且都可以正常操作。
面试常考题:
1.Eureka是什么?
Eureka是Netflix的一个子模块,也是核心模块之一,Eureka是一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移。服务注册于发现对于微服务架构来说是非常重要,有了服务发现与注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件,功能类似dubbo的注册中心,比如zookeeper。
2.传统的ACID什么?&CAP是什么
ACID:原子性(Atomicity)、一致性(Consistency)、独立性(lsolation)、持久性(Durability)
原子性:事务里的所有操作要么做,要么都不做,事务成功的条件是事务里所有操作都成功,只要有一个操作失败、整个事务失败。
一致性:数据库要一直处于一致状态,事务运行不会改变数据库原本的一致性约束
独立性:并发的事务之间不会互相影响,如果一个事务要访问的数据正在被另外一个事务修改,只要另外一个事务未提交,它所访问的数据就不受未提交事务的影响。
持久性:一旦事务提交后,它所做的修改将会永久的保存在数据库上,即使出现宕机也不会丢失。
CAP:一致性(Consistency)、可用性(Availability)、分区容错性(Partition Tolerance)
经典CAP图
CAP理论图:
在现在集群分布式的开发过程中,CAP三个条件最多只能同时较好的满足两个。
CAP理论的核心:一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求,因此,根据CAP原理将NOSQL数据库分成了满足CA原则、满足CP原则、满足AP原则三大类:
CA-单点集群,满足一致性、可用性的系统,通常在可扩展上不太强大
CP-满足一致性,分区容错性的系统,通常性能不是很高。
AP-满足可用性、分区容错性的系统,通常可能对一致性要求低一些。
CAP的3进2:
CAP理论就是说再分布式存储系统中,最多只能实现上面的两点。而由于当前的网络硬件肯定会出现延迟丢包等问题,所以分区容错性是我们必须需要实现的。
所以我们只能在一致性和可用性之间进行权衡,没有NOSQL系统能同时保证这三点。
CA传统的Oracle数据库
AP大多数网站架构的选择
CPRedis、MongoDB
注意:分布式架构的时候必须做出取舍
3.Netflix在设计Eureka时遵守的就是AP原则,啥是AP原则?
面试必问:
Eureka与zookeeper的区别?
答:Eureka遵守AP,zookeeper遵守CP
4. 作为服务注册中心,Eureka比zookeeper好在哪里?