上一篇讲到如何利用zookeeper服务治理与发现和dubbo rpc通信框架进行小型分布式系统的搭建
SpringBoot+Dubbo+Zookeeper快速搭建分布式简单的生产消费模型
今天我们使用SpringCloud中的Eureka来进行简单的分布式服务搭建
我们需要先建一个mysql的表用来练习
数据库名为db01,表明dept以及其字段名和属性上图可见,
插入部分数据
ok我们有了基础的数据库
然后,我们构建简单的三个微服务,一个实体类api,一个provider(服务提供者),一个consumer(服务消费者).
启动我们的idea,新建一个纯maven父项目工程,我们的微服务工程可以被这个父项目工程统一管理,
删除多余没用的文件夹及文件.
ok我们开始配置父工程的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>com.bai</groupId>
<artifactId>springcloud</artifactId>
<version>1.0-SNAPSHOT</version>
<!--打包方式 pom-->
<packaging>pom</packaging>
<!-- properties-->
<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.10</lombok.version>
</properties>
<!-- 这只是管理 不能导的 必须子项目中使用-->
<dependencyManagement>
<dependencies>
<!-- springCloud的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 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>
<!-- 数据库的-->
<!-- 连接器-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
<!-- 数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!--springboot的启动器-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!-- lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</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>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
我们通过使用dependencyManagement标签对所需要的的依赖进行统一的管理,主要用到spring cloud ,spring boot,jdbc connector,duird,lombok和一些测试与热部署要用的pom
ok 配置好pom文件之后我们开始写其中的子项目实体类api,新建一个module,设置为纯maven项目即可,命名和项目结构如图
既然是微服务,那么这个服务仅仅为我们其他的服务提供实体类即可,
我们只需要编写数据库对应的pojo类即可
代码如下:
package com.bai.springcloud.pojo;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
//实体类 orm(对象关系映射 类表关系映射)
@Data
@NoArgsConstructor
@Accessors(chain = true) //链式写法
public class Dept implements Serializable {
private Long deptno;//主键
private String dname;
//这个数据存在哪个数据库的字段~微服务 一个服务对应一个数据库
//同一个信息可能存在不同的数据库
private String db_source;
public Dept(String dname) {
this.dname = dname;
}
}
ok 实体类api构建完毕
我们继续构建提供者provider微服务
继续新建一个纯maven项目
ok先配置我们的pom文件,导入需要用到的包
这里需要导入实体类api的包
<?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>com.bai</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-provider-dept-8001</artifactId>
<dependencies>
<!-- 我们需要拿到实体类,所以要配置api module-->
<dependency>
<groupId>com.bai</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</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.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!-- boot test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- jetty-->
<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>
<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>
<!-- 加入eureka依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!-- 添加监控信息-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
</project>
导入成功之后,这个项目是一个spring boot项目了,我们开始配置application.yml文件,也可以写properties文件
配置内容如下
server:
port: 8001
#mybatis配置
mybatis:
type-aliases-package: com.bai.springcloud.pojo
config-location: classpath:mybatis/mybatis-config.xml
mapper-locations: classpath:mybatis/mapper/*.xml
spring:
application:
name: springcloud-rovider-dept
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/db01?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
username: root
password: 1234
name: defaultDataSource
#spring的配置
ok 配置好端口号,数据库链接需要的信息以及mybatis需要的配置和实体类别名,mapper信息后,yml文件我们也配置好了
开始写业务代码
由于我们已经调用了api包的实体类,那么我们直接写dao(mapper),service和controller就可以了,
具体代码如下
dao:(记得写上Mapper和Repository注解 以便spring容器接管)
package com.bai.springcloud.dao;
import com.bai.springcloud.pojo.Dept;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import java.util.List;
@Mapper
@Repository
public interface DeptDao {
public boolean addDept(Dept dept);
public Dept queryDeptById(Long id);
public List<Dept> queryAll();
}
然后我们去resources的mybatis的mapper文件夹里写与dao接口对应的mapper.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.bai.springcloud.dao.DeptDao">
<insert id="addDept" parameterType="Dept">
insert into dept(dname, db_source)
values (#{dname},DATABASE());
</insert>
<select id="queryDeptById" resultType="Dept" parameterType="Long">
select *from dept where deptno = #{deptno};
</select>
<select id="queryAll" resultType="Dept">
select * from dept;
</select>
</mapper>
然后是service层:
package com.bai.springcloud.service;
import com.bai.springcloud.pojo.Dept;
import org.springframework.stereotype.Service;
import java.util.List;
public interface DeptService {
public boolean addDept(Dept dept);
public Dept queryDeptById(Long id);
public List<Dept> queryAll();
}
然后是service接口的Impl实现类: 记得标注service注解和织入我们的dao层
package com.bai.springcloud.service;
import com.bai.springcloud.dao.DeptDao;
import com.bai.springcloud.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class DeptServiceImpl implements DeptService {
@Autowired
DeptDao deptDao;
@Override
public boolean addDept(Dept dept) {
return deptDao.addDept(dept);
}
@Override
public Dept queryDeptById(Long id) {
return deptDao.queryDeptById(id);
}
@Override
public List<Dept> queryAll() {
return deptDao.queryAll();
}
}
然后是controller
package com.bai.springcloud.controller;
import com.bai.springcloud.pojo.Dept;
import com.bai.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.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController //提供restful服务
public class DeptController {
@Autowired
private DeptService deptService;
@Autowired //选springcloud的 获取一些配置的信息
private DiscoveryClient client;
@PostMapping("/dept/add")
public boolean addDept(Dept dept){
return deptService.addDept(dept);
}
@GetMapping("/dept/get/{id}")
public Dept get(@PathVariable("id")Long id){
return deptService.queryDeptById(id);
}
@GetMapping("/dept/list")
public List<Dept> addDept(){
return deptService.queryAll();
}
}
这里采用restful风格书写
ok 我们先进行局部测试,看这个provider服务能否跑通.
测试通过,接下来我们写服务消费者consumer的实现代码
同样新建一个纯maven项目,结构如下
依旧先配置pom
<?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>com.bai</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-consumer-dept-80</artifactId>
<!-- 实体类+web-->
<dependencies>
<dependency>
<groupId>com.bai</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>
这里仅仅需要导入实体类api和spring boot web依赖 以及热部署即可
由于是消费者 因此我们直接去编写controller即可,获取到服务提供者provider的服务即可,那么我们如何取到提供者提供的内容呢,这里需要用到RestTemplate类的方法来进行框架之间的通信,因此我们需要编写其config类,
如下:
package com.bai.springcloud.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ConfigBean {//ApplicationContext.xml---spring @Configuration
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
然后我们再编写controller即可,记得将RestTemplate织入到controller中,
package com.bai.springcloud.controller;
import com.bai.springcloud.pojo.Dept;
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 java.util.List;
@RestController
public class DeptConsumerController {
//理解:消费者会不会有service层 不应该有
//restTemplate.....很多方法供我们调用 注册到Spring中
@Autowired
private RestTemplate restTemplate;
//提供多种便捷访问远程http服务的方法 简单的restful服务模板
//三个参数 url,实体(或者map) 返回值的class对象
private static final String REST_URL_PREFIX = "http://localhost:8001";
@RequestMapping("consumer/dept/add")
public boolean add(Dept dept){
return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add",dept,boolean.class);
}
@RequestMapping("consumer/dept/get/{id}")
public Dept get(@PathVariable("id")Long id){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/" + id,Dept.class);
}
@RequestMapping("/consumer/dept/list")
public List<Dept> list(){
return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list",List.class);
}
}
注意restTemplate实例化对象的使用和其方法参数.
ok 我们再次进行测试,看通过消费者是否能够跑通到提供者的内容
需要将两个服务都启动
结果也成功跑通了
接下来我们加入eureka server服务,对服务提供者进行发现与注册
同样新建纯maven项目,项目结构如图:
配置pom
<?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>com.bai</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-eureka-7001</artifactId>
<!-- 导包-->
<dependencies>
<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>
</project>
配置eureka服务和热部署即可
编写application.yml来配置我们的eureka服务:
server:
port: 7001
#eureka配置
eureka:
instance:
hostname: localhost #eureka服务端的实例名字
client:
register-with-eureka: false #表示是否向eureka中心注册自己 服务器自己不用注册
fetch-registry: false #false 表示自己为注册中心
service-url: #监控页面
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
编写主启动类:
package com.bai.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
//启动之后 访问localhost:7001即可进入服务管理页面
@SpringBootApplication
@EnableEurekaServer //Eureka服务端的启动类 可以接受别人注册进来的服务
public class EurekaServer_7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaServer_7001.class,args);
}
}
开启EurekaServer服务
同时为provider的主启动类添加注解:
@EnableEurekaClient
当前Eureka项目为服务端,而提供者为客户端
为提供者provider的yml也加入配置信息,我们的服务需要注册到eureka中:
因此加入:
#eureka的配置 服务注册到哪里? 配一个地址就好了
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka/
ok运行我们的eureka服务,再运行provider服务,查看是否注册成功.
ok我们的eureka中可以看到提供者的内容了
我们还可以对provider 的 status 状态描述 进行配置
此时需要给provider的yml文件加入新配置:
#eureka的配置 服务注册到哪里? 配一个地址就好了
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka/
instance: #改eureka 服务的默认描述
instance-id: springcloud-provider-dept8001
增加instance-id 我们可以看到eureka页面中服务的status的改变
我们可以看到这里是指向服务详细信息的,这里没有配置的话点进去是没有信息的,因此我们也要配置.
在provider的yml中添加:
#info配置
info:
app.name: bai-springcloud
company: blog.bai.com
ok这个页面也可以访问了
那么我们想查看注册进来的服务的信息清单该怎么做呢,因为微服务项目,是小组成员做的,如何获取各自的项目端口,uri,服务名是一个需求,我们只需要在provider的controller中加入
@Autowired //选springcloud的 获取一些配置的信息
private DiscoveryClient client;
//注册进来的微服务 通过服务发现 获取一些消息
@GetMapping("/dept/discovery")
public Object Discovery(){
//获取微服务列表的清单
List<String> services = client.getServices();
System.out.println("discovery=>service" + services);
//得到一个具体的微服务信息 通过具体的服务id去取
List<ServiceInstance> instances = client.getInstances("SPRINGCLOUD-ROVIDER-DEPT");
for(ServiceInstance instance: instances){
System.out.println(
instance.getHost()+"\t"+
instance.getPort()+"\t"+
instance.getUri()+"\t"+
instance.getServiceId()+"\t"
);
}
return this.client;
}
需要自动织入DiscoveryClient来使用其中的一些方法,我们通过url查看
通过后台查看:
可以发现获得到了服务提供者的本机端口号,uri以及项目id.
ok eureka入门的一些操作介绍完毕.!!!