以consul为微服务治理中心的微服务架构演示

方法论

前端组件化(可视化工具)

后端微服务化(分布式统一管控)

迭代自动化(CI/CD)

过程流水线化(DevOps)

定义接口入/出参后,通过KV模拟数据即可实现前后端联调,再深入开发相关微服务

本工程完整演示了以consul为微服务治理中心的标准微服务架构各个基本模块功能,通过该项目能够完整了解微服务注册、发现、健康监测、负载均衡、全链路监控、配置中心、权限控制等。

consul集群部署说明

修改配置文件,存放目录为consul.d,后缀为.json,可以有多个配置文件,后面的属性覆盖前面的。

1.公共基础配置文件/etc/consul.d/base-config.json

{

"ports": {

"http": 8500,

"dns": 8600,

"serf_lan": 8301,

"serf_wan": 8302,

"server": 8300

}

}

2.server节点的ACL配置文件acl.json

{

"datacenter": "dc1",

"acl_datacenter": "dc1",

"acl_master_token": "6407e6d8-1696-4b98-826d-0ad9a5c93449",

"acl_default_policy": "deny",

"server": true,

"log_level": "DEBUG",

"bootstrap_expect": 3,

"client_addr": "0.0.0.0"

}

3.client节点的ACL配置文件acl.json

{

"datacenter": "dc1",

"acl_datacenter": "dc1",

"acl_master_token": "6407e6d8-1696-4b98-826d-0ad9a5c93449",

"acl_token": "dd2c1eb3-7698-efb1-d213-f84d40fb5970",

"acl_default_policy": "deny",

"server": false,

"log_level": "DEBUG",

"client_addr": "0.0.0.0"

}

备注:

先启动server

浏览器打开UI,用acl_master_token设置ACL

创建一个新的ACL

将token配置到client的ACL文件的acl_token

逐步启动client

这个acl_token就是java bootstrap.yml中的consul配置

以docker方式启动consul

1.启动主服务server1

docker run -d --net host -p 8600:8600 -p 8500:8500 -p 8600:53/udp --name consul-server -v /etc/consul.d:/etc/consul.d consul:latest agent -bind=172.16.15.233 -config-dir=/etc/consul.d -node=server1 -ui

2.启动主服务server2

docker run -d --net host -p 8600:8600 -p 8500:8500 -p 8600:53/udp --name consul-server -v /etc/consul.d:/etc/consul.d consul:latest agent -bind=172.16.15.237 -config-dir=/etc/consul.d -node=server2 -retry-join=172.16.15.233

3.启动主服务server3

docker run -d --net host -p 8600:8600 -p 8500:8500 -p 8600:53/udp --name consul-server -v /etc/consul.d:/etc/consul.d consul:latest agent -bind=172.16.15.232 -config-dir=/etc/consul.d -node=server3 -retry-join=172.16.15.233

4.启动客户端client1

docker run -d --net host -p 8600:8600 -p 8500:8500 -p 8600:53/udp --name consul-client -v /etc/consul.d:/etc/consul.d consul:latest agent -bind=172.16.15.230 -config-dir=/etc/consul.d -node=client1 -retry-join=172.16.15.233

5.启动客户端client2

docker run -d --net host -p 8600:8600 -p 8500:8500 -p 8600:53/udp --name consul-client -v /etc/consul.d:/etc/consul.d consul:latest agent -bind=172.16.15.231 -config-dir=/etc/consul.d -node=client2 -retry-join=172.16.15.233

微服务模块

Springcloud 接入consul

基本依赖包

参考父工程的pom文件

把Spring consul的配置存放到bootstrap.yml文件里,而不是application.yml里边

spring:

cloud:

consul:

host: 172.28.50.28

port: 8500

discovery:

register: true

prefer-ip-address: true

instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${server.port}

acl-token: dd2c1eb3-7698-efb1-d213-f84d40fb5970

config:

enabled: true

format: yaml

watch:

enabled: true

prefix: config

data-key: data

网关服务,在spring注入的时候,要把需要引入的组件注入到主应用里边

//注册到consul的注入项

@EnableDiscoveryClient

//引入zuul进行网关路由配置的注入项

@EnableZuulProxy

@SpringBootApplication

业务集成服务,该服务是实现复杂业务逻辑的主体服务,是直接对接网关的微服务,是发现和调用其他微服务的主体服务

//在主应用注入微服务发现注入项

@EnableFeignClients

//建立一系列的接口类,通过接口类实现对其他微服务的调用

利用consul KV静态、动态管理配置,consul也是一个配置中心,通过KV管理配置属性

在consul KV中配置key的前缀为config(和consul.config.prefix属性值一致),下级目录为微服务名称,用逗号隔开为不同环境,以consul.config.data-key属性结尾,例如:config/accumulation-api-gateway,dev/data作为微服务accumulation-api-gateway的开发环境配置文件

如果是静态配置属性,静态配置只在微服务重启的时候才会从consul KV获取一次,例如:RabbitMQ的配置

如果要动态获取配置属性,则必须编写配置属性bean,动态配置会在consul KV更新后自动同步到微服务的对应bean上,例如:Redis的配置

api网关微服务api-gateway

路由配置、链路监控配置存储到consul的key/value中,路由指向业务逻辑层

#健康监控配置

management:

health:

redis:

enabled: false

consul:

enabled: true

#feign配置

zuul:

routes:

four-operations:

path: /api/**

serviceId: accumulation-business-layer

ribbon:

ReadTimeout: 120000

ConnectTimeout: 300000

#链路跟踪sleuth & zipkin配置

spring:

zipkin:

base-url: http://172.28.43.90:9411

sleuth:

sampler:

percentage: 1.0

业务逻辑层微服务business-layer

该微服务实现全部业务输出接口,对输入数据进行必要的合法性检测,解决跨域调用问题等

在controler层对需要检测的对象注入@Valid

@CrossOrigin

@RequestMapping(value = "/login",method = RequestMethod.POST)

@ApiOperation(value = "注册用户",notes = "注册一个用户到系统中")

@ResponseBody

public String login(@RequestBody @Valid RegisterVO user) throws IOException {

log.info("参数={}",user);

//该用户是否已经注册

String accessToken=iSso.login(user.getUsername(),user.getPassword());

log.info("accessToken={}",accessToken);

JSONObject result=new JSONObject();

result.put("code",1000);

result.put("email",user.getUsername());

result.put("accessToken",accessToken);

return result.toJSONString();

}

需要检测的对象注解正则式、提示信息等

public class RegisterVO {

@NotBlank(message = "用户名不能为空")

@Pattern(regexp = "^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*\\.[a-zA-Z0-9]{2,6}$",message = "必须为邮箱地址")

private String username;

@NotBlank(message = "密码不能为空")

@Pattern(regexp = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,16}$",message = "密码必须为数字、字母混合")

@Length(min = 8,max = 16,message = "密码长度必须为8-16个字符")

private String password;

}

调用文件上传微服务,在接口中要指定consumes为MediaType.MULTIPART_FORM_DATA_VALUE,参数注解为@RequestPart,否则调用出错

@FeignClient(name = "accumulation-distribution-file-layer")

@RequestMapping("/file")

public interface IDistributionFile {

@PostMapping(value = "/upload",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)

String save(@RequestPart(value = "fileName") MultipartFile file);

@RequestMapping(value = "/download/{fileName}", method = RequestMethod.GET, produces = MediaType.IMAGE_JPEG_VALUE)

byte[] get(@PathVariable("fileName") String fileName);

}

缓存微服务层cache-layer

通过jedis实现对redis集群的使用

在主类Application添加配置注解,解决autowire注入失败问题

//解决autowire注入失败问题

@EnableConfigurationProperties({RedisConfig.class})

redis配置从consul key/value动态获取,通过RedisConfig实例化redis连接池单例bean

#redis配置

redis:

host: 172.28.19.200

port: 7389

password:

timeout: 100

maxActive: 200

maxIdle: 200

minIdle: 5

maxWaitMillis: 10240

expireSeconds: 36000

commandTimeout: 10240

clusterNodes:

数据库持久层database-layer

该模块通过mybatis、mongodb演示了mysql关系型数据库及mongodb文档型数据库的使用方法

数据库连接配置

#数据库连接

spring:

datasource:

driver-class-name: com.mysql.jdbc.Driver

url: jdbc:mysql://172.28.5.92:3306/ToonBeacon?useUnicode=true&characterEncoding=utf8

username: syswin

password: syswin

maxActive: 2335

maxIdel: 120

maxWait: 100

#mongodb配置

data:

mongodb:

uri: mongodb://172.28.43.18:27017/crazyicelee

通过注解实现mysql数据库的VO映射,直接将sql注入到相关接口类中

@Mapper

public interface StudentDao {

@Results({

@Result(property = "name", column = "name"),

@Result(property = "age", column = "age"),

@Result(property = "sex", column = "sex"),

@Result(property = "email",column = "email")

})

@Select("SELECT * FROM student WHERE age > #{age}")

List searchAge(int age);

@Insert("INSERT INTO student(name, age,sex,email) VALUES (#{name}, #{age},#{sex},#{email})")

void addStudent(Student user);

@Update("UPDATE student SET name=#{name},sex=#{sex},age=#{age} WHERE email=#{email}")

void updateStudent(Student student);

@Delete("DELETE FROM student WHERE email=#{email}")

void deleteStudent(String email);

}

mongdb直接扩展MongoRepository作为接口实现数据库的访问

@Service

public interface UserRepository extends MongoRepository {

}

利用MongoDB 的GridFS分布式存储文件

4.1 创建GridFS的GridFSBucket bean

@Configuration

public class MongoConf {

@Autowired

private MongoDbFactory mongoDbFactory;

@Bean

public GridFSBucket getGridFSBuckets() {

MongoDatabase db = mongoDbFactory.getDb();

return GridFSBuckets.create(db);

}

}

4.2 实现文件上传、下载、删除API

@RestController

@RequestMapping("/file")

public class GridFSController {

private static Logger LOGGER = LoggerFactory.getLogger(GridFSController.class);

@Autowired

private GridFsTemplate gridFsTemplate;

@Autowired

private GridFSBucket gridFSBucket;

@PostMapping(value = "/upload")

public String save(@RequestParam(value = "fileName") MultipartFile file) {

LOGGER.info("Saving file..");

DBObject metaData = new BasicDBObject();

metaData.put("createdDate", new Date());

String fileName = UUID.randomUUID().toString();

try {

InputStream inputStream = file.getInputStream();

gridFsTemplate.store(inputStream, fileName, file.getContentType(), metaData);

} catch (IOException e) {

LOGGER.error("IOException: " + e);

throw new RuntimeException("System Exception while handling request");

}

LOGGER.info("File return: " + fileName);

return fileName;

}

@RequestMapping(value = "/download", method = RequestMethod.GET, produces = MediaType.IMAGE_JPEG_VALUE)

public byte[] get(@RequestParam(value = "fileName") String fileName) throws IOException {

LOGGER.info("Getting file.." + fileName);

GridFSFile result = gridFsTemplate.findOne(new Query().addCriteria(Criteria.where("filename").is(fileName)));

if (result == null) {

LOGGER.info("File not found" + fileName);

throw new RuntimeException("No file with name: " + fileName);

}

LOGGER.info("File found " + fileName);

//打开流下载对象

GridFSDownloadStream downloadStream = gridFSBucket.openDownloadStream(result.getObjectId());

//获取流对象

GridFsResource gridFsResource=new GridFsResource(result,downloadStream);

return IOUtils.toByteArray(gridFsResource.getInputStream());

}

@RequestMapping(value = "/delete", method = RequestMethod.DELETE)

public void delete(@RequestParam(value = "fileName") String fileName) {

LOGGER.info("Deleting file.." + fileName);

gridFsTemplate.delete(new Query().addCriteria(Criteria.where("filename").is(fileName)));

LOGGER.info("File deleted " + fileName);

}

}

消息队列接入层message-layer

本模块实现了接入rabbitmq的消息发送、接收,通过注解方式实现

#RabbitMq配置

spring:

rabbitmq:

host: 172.28.19.123

port: 5672

username: guest

password: guest

virtual-host: /

publisher-confirms: true

单点登录微服务层sso-layer

本模块以JWT演示了用户登录token的实现,可以将token存储到redis进行全站认证

基于OAuth2框架实现SSO

用mysql作为用户体系数据存储系统,mybatis作为数据库连接器,以SQL注解到DAO接口的方式实现简单的数据库访问。

1.1 在启动主类添加Mapper扫码注解,指定数据库映射类所在包,并且要注解@EnableWebSecurity,标明该服务提供OAuth2认证

@SpringBootApplication

@EnableAuthorizationServer

@EnableWebSecurity

@MapperScan(basePackages = "com.crazyice.lee.accumulation.sso.dao")

public class Application {

public static void main(String[] args) {

SpringApplication.run(Application.class, args);

}

}

1.2 SQL注解到接口实现数据库访问

这里特别说明SQL的IN操作实现方法,该接口必须添加@Mapper、@Repository注解,否则可能导致@Autowired失效或者创建Bean失败

@Mapper

@Repository

public interface SysPermissionServiceDao {

@Results({

@Result(property = "id", column = "id"),

@Result(property = "pid", column = "pid"),

@Result(property = "type", column = "type"),

@Result(property = "name",column = "name"),

@Result(property = "code",column = "code"),

@Result(property = "uri",column = "uri"),

@Result(property = "seq",column = "seq"),

@Result(property = "createUser",column = "create_user"),

@Result(property = "createTime",column = "create_time"),

@Result(property = "updateUser",column = "update_user"),

@Result(property = "updateTime",column = "update_time")

})

@Select({"

"SELECT * FROM sys_permission WHERE id IN "+

""+

"#{id}"+

""+

""

})

List findByIds(@Param("ids") List ids);

}

1.3 实现WebSecurityConfigurerAdapter适配器

@Configuration

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired

private DemoUserDetailsService demoUserDetailsService;

@Override

protected void configure(AuthenticationManagerBuilder auth) throws Exception {

auth.userDetailsService(demoUserDetailsService).passwordEncoder(passwordEncoder());

}

@Override

public void configure(WebSecurity web) throws Exception {

web.ignoring().antMatchers("/assets/**", "/css/**", "/images/**");

}

@Override

protected void configure(HttpSecurity http) throws Exception {

http.formLogin()

.loginPage("/login")

.and()

.authorizeRequests()

.antMatchers("/login").permitAll()

.anyRequest()

.authenticated()

.and().csrf().disable().cors();

}

@Bean

public PasswordEncoder passwordEncoder() {

return new SCryptPasswordEncoder();

}

}

1.4 实现UserDetailsService接口

@Service

public class DemoUserDetailsService implements UserDetailsService {

private static final Logger LOGGER = LoggerFactory.getLogger(DemoUserDetailsService.class);

private static final PasswordEncoder passwordEncoder=new SCryptPasswordEncoder();

@Autowired

private SysUserServiceDao sysUserServiceDao;

@Autowired

private PermissionService permissionService;

@Override

public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

//根据用户名从数据库获取用户信息

SysUser sysUser = sysUserServiceDao.getByUsername(username);

if (null == sysUser) {

LOGGER.warn("用户:{},不存在", username);

throw new UsernameNotFoundException(username);

}

//根据用户id获取用户权限

List permissionList = permissionService.findByUserId(sysUser.getId());

List authorityList = new ArrayList<>();

permissionList.stream().forEach(item->authorityList.add(new SimpleGrantedAuthority(item.getCode())));

//生成用户信息进行口令验证

User user = new User(sysUser.getUsername(), passwordEncoder.encode(sysUser.getPassword()), authorityList);

LOGGER.info("登录用户: {}", JSON.toJSONString(user));

return user;

}

}

实现OAuth2认证服务

自定义springboot注解演示模块myself-annotation

本模块以aop的方式实现了自定义注解的演示

websocket服务演示模块

本模块以websocket演示了websocket协议的服务端及客户端,实现了服务端的连接监听、消息监听、消息发送、不在线用户推送通知等,客户端实现了新用户加入、退出、和指定人聊天、群发等。

其他bean注入websocket方法

websocket的ServerEndpoint不能直接使用@Autowired将其他bean注入进来,而应该使用以下步骤

1.1 在主程序Application中使用静态方法调用传递参数,代码如下:

public class Application {

public static void main(String[] args) {

SpringApplication springApplication = new SpringApplication(Application.class);

ConfigurableApplicationContext configurableApplicationContext = springApplication.run(args);

//解决WebSocket不能注入的问题

WebSocketServer.setApplicationContext(configurableApplicationContext);

}

@Bean

public ServerEndpointExporter serverEndpointExporter(){

return new ServerEndpointExporter();

}

}

1.2 在websocket程序中定义需要注入的bean,代码如下:

//此处是解决无法注入的关键

private static ApplicationContext applicationContext;

//注入的service

private static ISendNotice iSendNotice;

//注入动态配置

private static ThirdParam thirdParam;

//注入本地缓存service

private static CacheServer cacheServer;

1.3 在websocket程序中定义set方法接纳参数,代码如下:

//外部bean注入进来

public static void setApplicationContext(ApplicationContext applicationContext) {

WebSocketServer.applicationContext = applicationContext;

WebSocketServer.iSendNotice=applicationContext.getBean(ISendNotice.class);

WebSocketServer.thirdParam=applicationContext.getBean(ThirdParam.class);

WebSocketServer.cacheServer=applicationContext.getBean(CacheServer.class);

}

利用ehcache将用户信息持久化缓存到本地

2.1 配置ehcache.xml,将eternal="true"

2.2 配置缓存策略服务CacheServer并注入进websocket中使用,cache key为字符串的时候要用单引号'括住

超级账本fabric链代码演示模块

该模块实现了运行在超级账本区块链上的链码编写,接入,相关接口对接等功能演示

快速数据字典查询服务

该模块以极简的方式实现了通用数据自典查询服务,利用consul KV的自动同步特性为分布式数据字典维护和查询提供了极简的解决方案。

将数据字典以KV的方式配置到consul平台

给数据字典配置动态bean,该bean动态从consul KV获取数据字典的MAP数据,存储到内存中,所以在提供给微服务查询时速度很快,解决了通常处理方案的读取数据库、加载缓存等中间过程,既保证了数据一致性,又保证了分布式服务的高可靠及内存访问的高效率。

@ConfigurationProperties(prefix = "dictionary")

@Data

public class DictionaryConfig {

private Map sex;

private Map province;

private Map city;

}

备注:每添加一个字典,只需要在该代码里边增加一个Map属性即可

通用的restFul API,该服务通过反射机制实现了一致的数据字典查询,适用所有基于MAP数据格式的数据字典,而且可以根据Key的前缀进行级联过滤。

@RestController

public class Controller {

private static Logger log = LoggerFactory.getLogger(Controller.class);

@Autowired

private DictionaryConfig dictionaryConfig;

//首字母转大写

public static String toUpperCaseFirstOne(String s){

if(Character.isUpperCase(s.charAt(0)))

return s;

else

return (new StringBuilder()).append(Character.toUpperCase(s.charAt(0))).append(s.substring(1)).toString();

}

@RequestMapping(value = "/getDictionary/{name}",method = RequestMethod.GET)

@ApiOperation(value = "字典",notes = "获取指定字典的KV列表")

@ApiImplicitParams({

@ApiImplicitParam(paramType = "query",name="filter",value = "删选key",dataType = "String")

})

public Map getDictionary(@PathVariable("name") String name, @RequestParam(value = "filter",name = "filter",required = false) String filter){

try {

Map totalMap=(Map) dictionaryConfig.getClass().getMethod("get" + toUpperCaseFirstOne(name)).invoke(dictionaryConfig);

if(filter==null) {

return totalMap;

}

else{

return totalMap.entrySet().stream().filter((e)->{

if(e.getKey().startsWith(filter))

return true;

else

return false;

}).collect(Collectors.toMap((e)->e.getKey(),(e)->e.getValue()));

}

} catch (IllegalAccessException e) {

log.error(e.getLocalizedMessage());

} catch (InvocationTargetException e) {

log.error(e.getLocalizedMessage());

} catch (NoSuchMethodException e) {

log.error(e.getLocalizedMessage());

}

return null;

}

}

个性化驾驶舱

该微服务以KV的方式提供个性化驾驶舱数据并配合前端联调,通过这种模式能够加速接口定义及联调效率。

驾驶舱按照用户个性化标识动态提供需要显示的模块数据,前端根据模块数据及类型以相关样式显示这些模块

通过配置consul的key/value来调整数据配合前端用户交互,确定接口数据结构后就可以深入开发相关模块的后端逻辑

每个模块的数据为统一的list对象,再深入的数据结构可以根据模块的实际情况自由定义,该数据映射为bean Model

##################

# 以下配置到consul #

##################

#健康监控配置

management:

health:

redis:

enabled: false

consul:

enabled: true

#个性化模块列表

personal:

cockpits:

- userId: 13701231472

models:

- 1

- 3

- 4

- 5

- userId: 13691491904

models:

- 1

- 2

- 3

- 4

- 5

- userId: 18513125518

models:

- 3

- 4

- 5

#个性化模块内容

models:

- id: 1

type: visit

name: 会议管理

data:

- name: 调查内容一

- name: 调查内容二

- id: 2

type: list

name: 调查信息

data:

- name: 调查内容一

- name: 调查内容二

- id: 3

type: content

name: 内容展示

data:

- name: 丰富的可视化类型 ECharts 提供了常规的折线图、柱状图、散点图、饼图、K线图,用于统计的盒形图,用于地理数据可视化的地图、热力图、线图,用于关系数据可视化的关系图、treemap、旭日图,多维数据可视化的平行坐标,还有用于 BI 的漏斗图,仪表盘,并且支持图与图之间的混搭。

- id: 4

type: app

name: 应用

data:

- name: 会议

visit: 122

img: http://scloud.toon.mobi/f/oCu-gQmNjNhDXnXOy8qPI8gPXQOM9kCn6mSLoRdYI+IfG.png

- name: 日程

visit: 122

img: http://scloud.toon.mobi/f/Mzu1uXTPFTo1mZaqY195QCdMGFhJRm47VPaPGVrB8d8fG.png

- name: 问卷调查

visit: 122

img: http://scloud.toon.mobi/f/VPTW828DPVYWOQEC6rgx-uThn2PRffr9OoRoR+Yk0WgfG.png

- id: 5

type: chart-loudou

name: 漏斗图

data:

- name: 访问

value: 20

- name: 资讯

value: 40

- name: 订单

value: 60

- name: 点击

value: 80

- name: 展示

value: 100

- id: 6

type: chart-zhexian

name: 一周信息统计

data:

- name: 访问

value: 12

- name: 资讯

value: 19

- name: 订单

value: 12

- name: 点击

value: 15

- name: 展示

value: 18

本工程的完整源代码

该工程代码经过验证均可正常运行。

码云git下载地址

consul java connect_accumulation相关推荐

  1. consul java 注册中心_Spring Cloud微服务架构实战之Consul注册中心02:consul入门案例...

    获取springcloud实战项目详细视频教程,请留言联系. 1.创建项目 我们创建聚合项目来讲解 Consul,首先创建一个 pom 父工程. 2.添加依赖 pom.xml 4.0.0 com.ex ...

  2. Zuul上传文件,中文文件名乱码解决办法

    问题描述 在项目中又一个上传文件的oss服务,直接调用服务的上传文件成功,如果经过网关zuul服务,上传中文名字的文件,文件名会出现乱码,最终导致上传失败,如果上传英文名字的文件,没有任何问题.怀疑网 ...

  3. [转载] --- 数据库基本知识

    里面的很多点,我之前都总结过,但是感觉这篇把这些都连起来了,总结的挺好,转载保存一下 [从入门到入土]令人脱发的数据库底层设计 前言 说到数据库这个词,我只能用爱恨交加这个词来形容它.两年前在自己还单 ...

  4. mongodb 索引详解

    使用springboot连接mongodb的时候,涉及到索引的使用 举例: @Document(collection="book") //注释的是复合索引 //@CompoundI ...

  5. java B2B2C springmvc mybatis电子商务平台源码-Consul服务发现原理...

    Consul 是什么 Consul 是一个支持多数据中心分布式高可用的服务发现和配置共享的服务软件,由 HashiCorp 公司用 Go 语言开发, 基于 Mozilla Public License ...

  6. java版电子商务spring cloud分布式微服务b2b2c社交电商 (十四)服务注册(consul)

    Springcloud b2b2c电子商务社交平台源码请加企鹅求求:一零三八七七四六二六.这篇文章主要介绍 spring cloud consul 组件,它是一个提供服务发现和配置的工具.consul ...

  7. java B2B2C源码电子商务平台-基于Consul的分布式锁实现

    分布式锁实现 需要JAVA Spring Cloud大型企业分布式微服务云构建的B2B2C电子商务平台源码:壹零叁八柒柒肆六二六 基于Consul的分布式锁主要利用Key/Value存储API中的ac ...

  8. consul-02.consul服务注册实现(java)

    一,续 在上一篇文章中简单介绍了下consul和集群环境搭建,点我查看上一篇文章. 本篇中将介绍怎么将服务注册至consul集群中,并形成一个公共jar包,在springmvc或者springboot ...

  9. java负载均衡框架_SpringCloud与Consul集成实现负载均衡功能

    负载均衡(Load Balance,简称LB)是一种服务器或网络设备的集群技术.负载均衡将特定的业务(网络服务.网络流量等)分担给多个服务器或网络设备,从而提高了业务处理能力,保证了业务的高可用性.负 ...

最新文章

  1. 2018谷歌学术指数发布——看看综合、生物、生信、微生物领域高引文章和杂志
  2. 小猿圈讲解Java可以做什么?
  3. Endnote如何一键更改参考文献?
  4. Ubuntu 16.04 安装网易云音乐
  5. Linux 线程(1):线程概述
  6. enum 有什么好处_高新技术企业认定四个核心评分标准是什么?软著能加分吗?...
  7. C语言-十进制转换为二进制函数
  8. 2021-08-25剑指 Offer 13. 机器人的运动范围
  9. 计算机程序考试试题及答案,计算机程序员考试试题及答案.doc
  10. STC15单片机实战项目 - 原理图设计
  11. 《西游记》的读后感4000字
  12. Service starting has been prevented by iaware or trustsbase sInfo ServiceInfo 解决方法
  13. Format_String_Attack_Lab
  14. Centos7.2部署HOR2.2(基于K8S集群的容器应用整合)
  15. Cox 比例风险模型中HR和置信区间
  16. Oracle 19 创建数据库、表空间
  17. 【diannaoxitong】查看路由器ADSL帐号密码方法
  18. python需要购买版权吗_关于版权事宜的一些说明
  19. C# XmlDocument处理XML元素节点
  20. 怎样将本地图片转换成网络链接图片

热门文章

  1. [公告]博客园管理团队新增成员wayfarer
  2. c51中断优先级c语言,基于proteus的51单片机开发实例(14)中断嵌套和中断优先级...
  3. IT商界著名公司来历和简介
  4. mysql子查询:标量子查询,行子查询,列子查询
  5. 歌曲背後真實的故事 (看完这个故事我流泪了~~~)
  6. 1688商品详情SKU
  7. 2021-05-21--0515周考
  8. 这才是实习生写的代码,你学废了吗
  9. 为什么网上工商银行安装了U盾不能上网站了?
  10. 如何开通聚合商家收款码?