分享

SpringCloud微服务完整实例

 观审美2 2019-06-19

转自:https://blog.csdn.net/ittechnologyhome/article/details/73824784,侵删

一微服务架构概述

1.1 微服务特性以及优点

  • 每个服务可以独立运行在自己的进程里
  • 一系列独立运行的微服务(goods,order,pay,user,search…)共同构建了整个系统
  • 每个服务为独立的业务开发,一个微服务只关注某个特定的功能,例如用户管理,商品管理微服务
  • 微服务之间通过一些轻量级的通信机制进行通讯,例如通过Restful API进行调用
  • 技术栈不受限:可以使用不同的开发语言和数据存储技术
  • 全自动的部署机制
  • 按需伸缩:根据需求和应用场景,实现细粒度的水平扩展

1.2 微服务带来的挑战

  • 运维要求较高
  • 分布式的复杂性
  • 接口调整成本较高

1.3 微服务设计原则

  • 单一职责原则
  • 服务自治原则
  • 轻量级通讯机制
  • 微服务粒度

1.4 微服务开发框架

  • SpringCloud:众多组件构造完善的分布式系统
  • Dubbo/Dubbox:关注服务治理
  • Dropwizard:关注单个微服务开发

二 SpringCloud概述与开发环境

2.1 SpringCloud概述

SpringCloud是基于SpringBoot之上的用来快速构建微服务系统的工具集,拥有功能完善的轻量级微服务组件,例如服务治理(Eureka),声明式REST调用(Feign),客户端负载均衡(Ribbon),服务容错(Hystrix),服务网关(Zuul)以及服务配置(Spring Cloud Config),服务跟踪(Sleuth)等等。

官网链接:http://projects./spring-cloud/ 
目前主流的版本为SpringBoot1.4.5.RELEAE和SpringCloudCamden.SR7, 
Maven pom配置如下:

  1. <parent>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-parent</artifactId>
  4. <version>1.4.5.RELEASE</version>
  5. </parent>
  6. <dependencyManagement>
  7. <dependencies>
  8. <dependency>
  9. <groupId>org.springframework.cloud</groupId>
  10. <artifactId>spring-cloud-dependencies</artifactId>
  11. <version>Camden.SR7</version>
  12. <type>pom</type>
  13. <scope>import</scope>
  14. </dependency>
  15. </dependencies>
  16. </dependencyManagement>
  17. <dependencies>
  18. <dependency>
  19. <groupId></groupId>
  20. <artifactId>spring-cloud-starter-config</artifactId>
  21. </dependency>
  22. <dependency>
  23. <groupId></groupId>
  24. <artifactId>spring-cloud-starter-eureka</artifactId>
  25. </dependency>
  26. </dependencies>

2.2 开发环境

MacOS10.12+JDK8u131+IntelliJ IDEA2017.1.4

Tomcat8.5+Maven3.3.9+Git2.12+Firefox54

Spring4.3.9.RELEASE+SpringBoot1.4.5.RELEASE+SpringCloud Camden.SR7

三 工程机器模块说明

3.1 工程说明

工程首先自定义了Maven父工程,其中定义如下的公共组件:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven./POM/4.0.0"
  3. xmlns:xsi="http://www./2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven./POM/4.0.0 http://maven./xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0</modelVersion>
  6. <!-- 自定义工程的maven坐标-->
  7. <groupId>com.ekeyfund.springcloud</groupId>
  8. <artifactId>springcloud-parent</artifactId>
  9. <version>2.0.0-SNAPSHOT</version>
  10. <packaging>pom</packaging>
  11. <!-- 基于SpringBoot 1.4.5.RELEASE-->
  12. <parent>
  13. <groupId>org.springframework.boot</groupId>
  14. <artifactId>spring-boot-starter-parent</artifactId>
  15. <version>1.4.5.RELEASE</version>
  16. <relativePath/>
  17. </parent>
  18. <!-- 定义引用类库版本 -->
  19. <properties>
  20. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  21. <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  22. <java.version>1.8</java.version>
  23. <spring-cloud.version>Camden.SR7</spring-cloud.version>
  24. <springcloud-parent.version>2.0.0-SNAPSHOT</springcloud-parent.version>
  25. <druid.version>1.0.31</druid.version>
  26. <jackson.version>2.8.8</jackson.version>
  27. <commons-lang3.version>3.5</commons-lang3.version>
  28. <ehcache.version>3.1.4</ehcache.version>
  29. <hibernate.version>5.0.12.Final</hibernate.version>
  30. <servlet-api.version>3.1.0</servlet-api.version>
  31. <commons-collection4.version>4.1</commons-collection4.version>
  32. <springframework.oxm.version>4.3.9.RELEASE</springframework.oxm.version>
  33. </properties>
  34. <!-- 引入SpringCloud微服务常用组件-->
  35. <modules>
  36. <module>springcloud-eureka-server</module>
  37. <module>springcloud-eureka-server-ha</module>
  38. <module>springcloud-provider-user-service</module>
  39. <module>springcloud-consumer-h5-ribbon-hystrix</module>
  40. <module>springcloud-consumer-h5-feign</module>
  41. <module>springcloud-api-gateway</module>
  42. <module>springcloud-consumer-h5</module>
  43. <module>springcloud-config-server</module>
  44. </modules>
  45. <dependencies>
  46. <!-- 服务发现组件-->
  47. <dependency>
  48. <groupId>org.springframework.cloud</groupId>
  49. <artifactId>spring-cloud-starter-eureka-server</artifactId>
  50. </dependency>
  51. <!-- 应用监控-->
  52. <dependency>
  53. <groupId>org.springframework.boot</groupId>
  54. <artifactId>spring-boot-starter-actuator</artifactId>
  55. </dependency>
  56. <!-- 应用测试-->
  57. <dependency>
  58. <groupId>org.springframework.boot</groupId>
  59. <artifactId>spring-boot-starter-test</artifactId>
  60. <scope>test</scope>
  61. </dependency>
  62. <dependency>
  63. <groupId>mysql</groupId>
  64. <artifactId>mysql-connector-java</artifactId>
  65. <scope>runtime</scope>
  66. </dependency>
  67. <dependency>
  68. <groupId>com.alibaba</groupId>
  69. <artifactId>druid</artifactId>
  70. <version>${druid.version}</version>
  71. </dependency>
  72. <dependency>
  73. <groupId>javax.servlet</groupId>
  74. <artifactId>javax.servlet-api</artifactId>
  75. <version>${servlet-api.version}</version>
  76. </dependency>
  77. <dependency>
  78. <groupId>com.fasterxml.jackson.core</groupId>
  79. <artifactId>jackson-annotations</artifactId>
  80. <version>${jackson.version}</version>
  81. </dependency>
  82. <dependency>
  83. <groupId>org.apache.commons</groupId>
  84. <artifactId>commons-lang3</artifactId>
  85. <version>${commons-lang3.version}</version>
  86. </dependency>
  87. <dependency>
  88. <groupId>org.apache.commons</groupId>
  89. <artifactId>commons-collections4</artifactId>
  90. <version>${commons-collection4.version}</version>
  91. </dependency>
  92. <dependency>
  93. <groupId>org.hibernate</groupId>
  94. <artifactId>hibernate-ehcache</artifactId>
  95. <version>${hibernate.version}</version>
  96. </dependency>
  97. <dependency>
  98. <groupId>org.ehcache</groupId>
  99. <artifactId>ehcache</artifactId>
  100. <version>${ehcache.version}</version>
  101. </dependency>
  102. <dependency>
  103. <groupId>org.springframework</groupId>
  104. <artifactId>spring-oxm</artifactId>
  105. <version>${springframework.oxm.version}</version>
  106. </dependency>
  107. </dependencies>
  108. <dependencyManagement>
  109. <dependencies>
  110. <dependency>
  111. <groupId>org.springframework.cloud</groupId>
  112. <artifactId>spring-cloud-dependencies</artifactId>
  113. <version>${spring-cloud.version}</version>
  114. <type>pom</type>
  115. <scope>import</scope>
  116. </dependency>
  117. </dependencies>
  118. </dependencyManagement>
  119. </project>

3.2 模块说明

模块则借助IntelliJ IDEA结合Spring Initializer自动生成工程结构,主要模块和说明如下:

模块名称 模块说明 访问地址
springcloud-eureka-server 分布式服务注册中心(单点) http://127.0.0.1:9999
springcloud-eureka-server-ha 分布式服务注册中心(高可用版本) http://127.0.0.1:9998 http://127.0.0.1:9997
springcloud-provider-user-service 用户服务提供者 http://127.0.0.1:9996/list http://127.0.0.1:9995/list
springcloud-consumer-h5 用户服务调用者,采用原始的RestTemplate调用 http://127.0.0.1:9991/user/get/4
springcloud-consumer-h5-ribbon-hystrix 用户服务调用者,采用ribbon做客户端负载均衡 http://127.0.0.1:9994/springcloud-provider-user-service
springcloud-consumer-h5-feign feign声明式服务调用者 http://127.0.0.1:9993/list
springcloud-gateway 网关服务 http://127.0.0.1:9992/api-a/list
springcloud-config-server 配置中心 待定

四 使用SpringBoot实现服务提供者

所属maven模块:springcloud-provider-user-service 
基于SpringBoot的Web和JPA模块实现Restful API的常用方法

4.1 entity

主要包含User,Role,Department三个实体

Role.java

  1. package com.ekeyfund.springcloud.entity;
  2. import javax.persistence.*;
  3. import java.io.Serializable;
  4. /**
  5. * Role Entity
  6. *
  7. * @author Liuguanglei liuguanglei@ekeyfund.com
  8. * @create 2017-06-下午2:36
  9. */
  10. @Entity
  11. @Table(name = "springboot_role")
  12. public class Role implements Serializable{
  13. @Id
  14. @GeneratedValue(strategy = GenerationType.IDENTITY)
  15. @Column(name = "role_id")
  16. private Long id;
  17. @Column(name = "role_name")
  18. private String name;
  19. public Long getId() {
  20. return id;
  21. }
  22. public void setId(Long id) {
  23. this.id = id;
  24. }
  25. public String getName() {
  26. return name;
  27. }
  28. public void setName(String name) {
  29. this.name = name;
  30. }
  31. @Override
  32. public String toString() {
  33. return new org.apache.commons.lang3.builder.ToStringBuilder(this)
  34. .append("id", id)
  35. .append("name", name)
  36. .toString();
  37. }
  38. }

Department.java

  1. package com.ekeyfund.springcloud.entity;
  2. import org.apache.commons.lang3.builder.ToStringBuilder;
  3. import org.hibernate.annotations.CacheConcurrencyStrategy;
  4. import javax.persistence.*;
  5. import java.io.Serializable;
  6. /**
  7. * Department Entity
  8. *
  9. * @author Liuguanglei liuguanglei@ekeyfund.com
  10. * @create 2017-06-下午2:31
  11. */
  12. @Entity
  13. @Table(name = "springboot_department")
  14. @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
  15. public class Department implements Serializable {
  16. @Id
  17. @GeneratedValue(strategy = GenerationType.IDENTITY)
  18. @Column(name = "department_id")
  19. private Long id;
  20. @Column(name = "department_name")
  21. private String name;
  22. public Long getId() {
  23. return id;
  24. }
  25. public void setId(Long id) {
  26. this.id = id;
  27. }
  28. public String getName() {
  29. return name;
  30. }
  31. public void setName(String name) {
  32. this.name = name;
  33. }
  34. @Override
  35. public String toString() {
  36. return new ToStringBuilder(this)
  37. .append("id", id)
  38. .append("name", name)
  39. .toString();
  40. }
  41. }

User.java

  1. package com.ekeyfund.springcloud.entity;
  2. import com.fasterxml.jackson.annotation.JsonBackReference;
  3. import org.apache.commons.lang3.builder.ToStringBuilder;
  4. import org.springframework.format.annotation.DateTimeFormat;
  5. import javax.persistence.*;
  6. import java.io.Serializable;
  7. import java.util.Date;
  8. import java.util.List;
  9. /**
  10. * User Entity
  11. *
  12. * @author Liuguanglei liuguanglei@ekeyfund.com
  13. * @create 2017-06-下午2:32
  14. */
  15. @Entity
  16. @Table(name = "springboot_user")
  17. public class User implements Serializable{
  18. @Id
  19. @Column(name = "user_id")
  20. @GeneratedValue(strategy = GenerationType.IDENTITY)
  21. private Long id;
  22. @Column(name = "user_name")
  23. private String name;
  24. @Column(name = "user_password")
  25. private String password;
  26. @Column(name = "user_create_date")
  27. @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  28. private Date createDate;
  29. @ManyToOne
  30. @JoinColumn(name = "department_id")
  31. @JsonBackReference
  32. private Department department;
  33. @ManyToMany(cascade = {},fetch = FetchType.EAGER)
  34. @JoinTable(name = "springboot_user_role",joinColumns = {@JoinColumn(name="user_id")},
  35. inverseJoinColumns = {@JoinColumn(name = "role_id")}
  36. )
  37. private List<Role> roleList;
  38. public Long getId() {
  39. return id;
  40. }
  41. public void setId(Long id) {
  42. this.id = id;
  43. }
  44. public String getName() {
  45. return name;
  46. }
  47. public void setName(String name) {
  48. this.name = name;
  49. }
  50. public String getPassword() {
  51. return password;
  52. }
  53. public void setPassword(String password) {
  54. this.password = password;
  55. }
  56. public Date getCreateDate() {
  57. return createDate;
  58. }
  59. public void setCreateDate(Date createDate) {
  60. this.createDate = createDate;
  61. }
  62. public Department getDepartment() {
  63. return department;
  64. }
  65. public void setDepartment(Department department) {
  66. this.department = department;
  67. }
  68. public List<Role> getRoleList() {
  69. return roleList;
  70. }
  71. public void setRoleList(List<Role> roleList) {
  72. this.roleList = roleList;
  73. }
  74. @Override
  75. public String toString() {
  76. return new ToStringBuilder(this)
  77. .append("id", id)
  78. .append("name", name)
  79. .append("password", password)
  80. .append("createDate", createDate)
  81. .append("department", department)
  82. .append("roleList", roleList)
  83. .toString();
  84. }
  85. }

4.2 数据访问Repository

主要包含UserRepository和DepartmentRepository

DepartmentRepository.java

  1. package com.ekeyfund.springcloud.repository;
  2. import com.ekeyfund.springcloud.entity.Department;
  3. import org.springframework.data.jpa.repository.JpaRepository;
  4. import org.springframework.stereotype.Repository;
  5. /**
  6. * Created by tony on 2017/6/19.
  7. */
  8. @Repository
  9. public interface DepartmentRepository extends JpaRepository<Department,Long> {
  10. }

UserRepoistory.java

  1. package com.ekeyfund.springcloud.repository;
  2. import com.ekeyfund.springcloud.entity.User;
  3. import org.springframework.data.jpa.repository.JpaRepository;
  4. import org.springframework.stereotype.Repository;
  5. import java.util.Collection;
  6. import java.util.Date;
  7. import java.util.List;
  8. /**
  9. * User Repository
  10. *
  11. * @author Liuguanglei liuguanglei@ekeyfund.com
  12. * @create 2017-06-下午2:54
  13. */
  14. @Repository
  15. public interface UserRepository extends JpaRepository<User,Long>{
  16. /**
  17. * and
  18. * @param id
  19. * @param name
  20. * @return
  21. */
  22. User findByIdAndName(Long id, String name);
  23. User findByNameAndPassword(String name, String password);
  24. /**
  25. * or
  26. * @param id
  27. * @param name
  28. * @return
  29. */
  30. User findByIdOrName(Long id, String name);
  31. /**
  32. * between
  33. * @param start
  34. * @param end
  35. * @return
  36. */
  37. List<User> findByCreateDateBetween(Date start, Date end);
  38. /**
  39. * lessThan
  40. * @param start
  41. * @return
  42. */
  43. List<User> getByCreateDateLessThan(Date start);
  44. /**
  45. * Greater Than
  46. * @param start
  47. * @return
  48. */
  49. List<User> findByCreateDateGreaterThan(Date start);
  50. /**
  51. * is null
  52. * @return
  53. */
  54. List<User> findByNameIsNull();
  55. /**
  56. * in
  57. * @param nameList
  58. * @return
  59. */
  60. List<User> findByNameIn(Collection<String> nameList);
  61. }

4.3 业务逻辑Service

主要包含UserService,DepartmentService及其实现

UserService.java

  1. package com.ekeyfund.springcloud.service;
  2. import com.ekeyfund.springcloud.entity.User;
  3. import java.util.List;
  4. /**
  5. * Created by tony on 2017/6/19.
  6. */
  7. public interface UserService {
  8. /**
  9. * 登录
  10. * @param name
  11. * @param password
  12. * @return
  13. */
  14. public User login(String name, String password);
  15. /**
  16. * 注册
  17. * @param user
  18. * @return
  19. */
  20. public User register(User user);
  21. /**
  22. * 注销
  23. * @param user
  24. * @return
  25. */
  26. void writeOff(User user);
  27. /**
  28. * 当前用户是否已经存在
  29. * @param user
  30. * @return
  31. */
  32. boolean isExists(User user);
  33. List<User> getAllUser();
  34. User getUserById(Long id);
  35. }

UserServiceImpl.java

  1. package com.ekeyfund.springcloud.service.impl;
  2. import com.ekeyfund.springcloud.entity.User;
  3. import com.ekeyfund.springcloud.repository.UserRepository;
  4. import com.ekeyfund.springcloud.service.UserService;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.stereotype.Service;
  7. import javax.transaction.Transactional;
  8. import java.util.List;
  9. /**
  10. * User Service Impl
  11. *
  12. * @author Liuguanglei liuguanglei@ekeyfund.com
  13. * @create 2017-06-下午3:34
  14. */
  15. @Service
  16. @Transactional
  17. public class UserServiceImpl implements UserService {
  18. @Autowired
  19. private UserRepository userRepository;
  20. @Override
  21. public User login(String name, String password) {
  22. return userRepository.findByNameAndPassword(name,password);
  23. }
  24. @Override
  25. public User register(User user) {
  26. return userRepository.save(user);
  27. }
  28. @Override
  29. public void writeOff(User user) {
  30. userRepository.delete(user);
  31. }
  32. @Override
  33. public boolean isExists(User user) {
  34. return userRepository.findOne(user.getId())!=null?true:false;
  35. }
  36. @Override
  37. public List<User> getAllUser() {
  38. return userRepository.findAll();
  39. }
  40. @Override
  41. public User getUserById(Long id) {
  42. return userRepository.findOne(id);
  43. }
  44. }

DepartmentService.java

  1. package com.ekeyfund.springcloud.service;
  2. import com.ekeyfund.springcloud.entity.Department;
  3. /**
  4. * Created by tony on 2017/6/19.
  5. */
  6. public interface DepartmentService {
  7. Department saveDepartment(Department department);
  8. Department getDepartmentById(Long id);
  9. }

DepartmentServiceImpl.java

  1. package com.ekeyfund.springcloud.service.impl;
  2. import com.ekeyfund.springcloud.entity.Department;
  3. import com.ekeyfund.springcloud.repository.DepartmentRepository;
  4. import com.ekeyfund.springcloud.service.DepartmentService;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.stereotype.Service;
  7. import javax.transaction.Transactional;
  8. /**
  9. * Department Impl
  10. *
  11. * @author Liuguanglei liuguanglei@ekeyfund.com
  12. * @create 2017-06-下午3:12
  13. */
  14. @Transactional
  15. @Service
  16. public class DepartmentImpl implements DepartmentService {
  17. @Autowired
  18. private DepartmentRepository departmentRepository;
  19. @Override
  20. public Department saveDepartment(Department department) {
  21. return departmentRepository.save(department);
  22. }
  23. @Override
  24. public Department getDepartmentById(Long id) {
  25. return departmentRepository.findOne(id);
  26. }
  27. }

4.4 Controller层

主要包含提供User完整的Restful API 的UserController

UserController.java

  1. package com.ekeyfund.springcloud.controller;
  2. import com.ekeyfund.springcloud.entity.User;
  3. import com.ekeyfund.springcloud.service.UserService;
  4. import org.slf4j.LoggerFactory;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.cloud.client.ServiceInstance;
  7. import org.springframework.cloud.client.discovery.DiscoveryClient;
  8. import org.springframework.web.bind.annotation.*;
  9. import java.util.Date;
  10. import java.util.List;
  11. /**
  12. * UserController
  13. * Restful API
  14. * @author Liuguanglei liuguanglei@ekeyfund.com
  15. * @create 2017-06-下午11:24
  16. */
  17. @RestController
  18. public class UserController {
  19. private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(UserController.class);
  20. @Autowired
  21. private DiscoveryClient discoveryClient;
  22. @Autowired
  23. private UserService userService;
  24. @GetMapping(value = "/list")
  25. public List<User> list(){
  26. ServiceInstance instance=discoveryClient.getLocalServiceInstance();
  27. LOGGER.info("call user/list service host is "+instance.getHost()+"service_id is "+instance.getServiceId());
  28. return userService.getAllUser();
  29. }
  30. @GetMapping(value = "/login")
  31. public User login( @RequestParam String name,@RequestParam String password){
  32. User user=userService.login(name,password);
  33. return user;
  34. }
  35. @PostMapping("/register")
  36. public String register(@ModelAttribute User user){
  37. User result =userService.register(user);
  38. return result!=null?"success":"fail";
  39. }
  40. @GetMapping("/get/{id}")
  41. public User get(@PathVariable Long id){
  42. return userService.getUserById(id);
  43. }
  44. @PutMapping("/update/{id}")
  45. public String update(@PathVariable Long id,@ModelAttribute User user){
  46. User updatedUser =userService.getUserById(id);
  47. updatedUser.setName(user.getName());
  48. updatedUser.setPassword(user.getPassword());
  49. updatedUser.setCreateDate(new Date());
  50. User result= userService.register(updatedUser);
  51. return result!=null?"success":"fail";
  52. }
  53. @DeleteMapping("/delete/{id}")
  54. public String delete(@PathVariable Long id){
  55. User user =new User();
  56. user.setId(id);
  57. userService.writeOff(user);
  58. return "success";
  59. }
  60. }

4.5 Configuration

主要包含数据源Druid和JPA的配置

DruidConfiguation.java

  1. package com.ekeyfund.springcloud.configuration;
  2. import com.alibaba.druid.support.http.StatViewServlet;
  3. import com.alibaba.druid.support.http.WebStatFilter;
  4. import org.springframework.boot.web.servlet.FilterRegistrationBean;
  5. import org.springframework.boot.web.servlet.ServletRegistrationBean;
  6. import org.springframework.context.annotation.Bean;
  7. /**
  8. * Druid Configuration
  9. *
  10. * @author Liuguanglei liuguanglei@ekeyfund.com
  11. * @create 2017-06-下午5:48
  12. */
  13. public class DruidConfiguration {
  14. @Bean
  15. public ServletRegistrationBean statViewServle(){
  16. ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(),"/druid/*");
  17. //白名单:
  18. servletRegistrationBean.addInitParameter("allow","192.168.1.218,127.0.0.1");
  19. //IP黑名单 (存在共同时,deny优先于allow) : 如果满足deny的即提示:Sorry, you are not permitted to view this page.
  20. servletRegistrationBean.addInitParameter("deny","192.168.1.100");
  21. //登录查看信息的账号密码.
  22. servletRegistrationBean.addInitParameter("loginUsername","druid");
  23. servletRegistrationBean.addInitParameter("loginPassword","12345678");
  24. //是否能够重置数据.
  25. servletRegistrationBean.addInitParameter("resetEnable","false");
  26. return servletRegistrationBean;
  27. }
  28. @Bean
  29. public FilterRegistrationBean statFilter(){
  30. FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
  31. //添加过滤规则.
  32. filterRegistrationBean.addUrlPatterns("/*");
  33. //添加不需要忽略的格式信息.
  34. filterRegistrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
  35. return filterRegistrationBean;
  36. }
  37. }

JPAPersistenceConfiguration

  1. package com.ekeyfund.springcloud.configuration;
  2. import com.alibaba.druid.pool.DruidDataSource;
  3. import org.slf4j.LoggerFactory;
  4. import org.springframework.beans.factory.annotation.Value;
  5. import org.springframework.boot.autoconfigure.domain.EntityScan;
  6. import org.springframework.context.annotation.Bean;
  7. import org.springframework.context.annotation.Configuration;
  8. import org.springframework.core.Ordered;
  9. import org.springframework.core.annotation.Order;
  10. import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
  11. import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
  12. import org.springframework.orm.jpa.JpaTransactionManager;
  13. import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
  14. import org.springframework.orm.jpa.vendor.HibernateJpaDialect;
  15. import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
  16. import org.springframework.transaction.PlatformTransactionManager;
  17. import org.springframework.transaction.annotation.EnableTransactionManagement;
  18. import javax.persistence.EntityManagerFactory;
  19. import javax.sql.DataSource;
  20. import java.sql.SQLException;
  21. import java.util.Properties;
  22. /**
  23. * JPA Persistence Configuration
  24. *
  25. * @author Liuguanglei liuguanglei@ekeyfund.com
  26. * @create 2017-06-上午11:26
  27. */
  28. @Order(Ordered.HIGHEST_PRECEDENCE)
  29. @Configuration
  30. @EnableTransactionManagement(proxyTargetClass = true) //启用JPA的事务管理
  31. @EnableJpaRepositories(basePackages = "com.ekeyfund.springcloud.repository" )//启用JPA资源库并指定资源库接口位置
  32. @EntityScan(basePackages = "com.ekeyfund.springcloud.entity")//指定实体的位置
  33. public class JPAPersistenceConfiguration {
  34. private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(JPAPersistenceConfiguration.class);
  35. /*******************数据库和连接池配置信息,读取application.properties文件的属性值****************************/
  36. @Value("${spring.datasource.driver-class-name}")
  37. private String driverClass;
  38. @Value("${spring.datasource.username}")
  39. private String userName;
  40. @Value("${spring.datasource.password}")
  41. private String password;
  42. @Value("${spring.datasource.url}")
  43. private String url;
  44. @Value("${spring.datasource.initialSize}")
  45. private int initialSize;
  46. @Value("${spring.datasource.minIdle}")
  47. private int minIdle;
  48. @Value("${spring.datasource.maxActive}")
  49. private int maxActive;
  50. @Value("${spring.datasource.maxWait}")
  51. private long maxWait;
  52. @Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
  53. private long timeBetweenEvictionRunsMillis;
  54. @Value("${spring.datasource.minEvictableIdleTimeMillis}")
  55. private long minEvictableIdleTimeMillis;
  56. @Value("${spring.datasource.filters}")
  57. private String filters;
  58. @Value("${spring.datasource.connectionProperties}")
  59. private String connectionProperties;
  60. @Bean(name = "druidDataSource",initMethod = "init",destroyMethod = "close")
  61. public DataSource dataSource(){
  62. DruidDataSource druidDataSource =new DruidDataSource();
  63. druidDataSource.setDriverClassName(driverClass);
  64. druidDataSource.setUsername(userName);
  65. druidDataSource.setPassword(password);
  66. druidDataSource.setUrl(url);
  67. druidDataSource.setInitialSize(initialSize);
  68. druidDataSource.setMinIdle(minIdle);
  69. druidDataSource.setMaxActive(maxActive);
  70. druidDataSource.setMaxWait(maxWait);
  71. druidDataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
  72. druidDataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
  73. druidDataSource.setConnectionProperties(connectionProperties);
  74. try {
  75. druidDataSource.setFilters(filters);
  76. } catch (SQLException e) {
  77. LOGGER.error("build datasoure exception ",e.getMessage());
  78. }
  79. return druidDataSource;
  80. }
  81. @Bean(name = "entityManagerFactory")
  82. public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource druidDataSource){
  83. LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean =new LocalContainerEntityManagerFactoryBean();
  84. localContainerEntityManagerFactoryBean.setDataSource(druidDataSource);
  85. localContainerEntityManagerFactoryBean.setPackagesToScan("com.ekeyfund.springcloud.entity");
  86. localContainerEntityManagerFactoryBean.setJpaProperties(buildHibernateProperties());
  87. localContainerEntityManagerFactoryBean.setJpaDialect(new HibernateJpaDialect());
  88. localContainerEntityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter(){
  89. {
  90. setDatabase(org.springframework.orm.jpa.vendor.Database.MYSQL);
  91. setDatabasePlatform("org.hibernate.dialect.MySQL5Dialect");
  92. }
  93. });
  94. return localContainerEntityManagerFactoryBean;
  95. }
  96. @Bean
  97. public PlatformTransactionManager transactionManager(DataSource druidDataSource, EntityManagerFactory entityManagerFactory){
  98. JpaTransactionManager jpaTransactionManager=new JpaTransactionManager();
  99. jpaTransactionManager.setDataSource(druidDataSource);
  100. jpaTransactionManager.setEntityManagerFactory(entityManagerFactory);
  101. return jpaTransactionManager;
  102. }
  103. @Bean
  104. PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor(){
  105. return new PersistenceExceptionTranslationPostProcessor();
  106. }
  107. protected Properties buildHibernateProperties(){
  108. Properties hibernateProperties =new Properties();
  109. hibernateProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
  110. hibernateProperties.setProperty("hibernate.hbm2ddl.auto","update");
  111. hibernateProperties.setProperty("hibernate.show_sql", "false");
  112. hibernateProperties.setProperty("hibernate.use_sql_comments", "false");
  113. hibernateProperties.setProperty("hibernate.format_sql", "true");
  114. hibernateProperties.setProperty("hibernate.generate_statistics", "false");
  115. hibernateProperties.setProperty("javax.persistence.validation.mode", "none");
  116. //Audit History flags
  117. hibernateProperties.setProperty("org.hibernate.envers.store_data_at_delete", "true");
  118. hibernateProperties.setProperty("org.hibernate.envers.global_with_modified_flag", "true");
  119. hibernateProperties.setProperty("hibernate.cache.use_second_level_cache", "true");
  120. hibernateProperties.setProperty("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.EhCacheRegionFactory");
  121. hibernateProperties.setProperty("hibernate.cache.use_query_cache", "true");
  122. return hibernateProperties;
  123. }
  124. }

4.6 应用配置

主要包含springboot的application.properties,logback的logback-spring.xml以及缓存框架的ehcache.xml

application.propeties

  1. ##DataSource Config
  2. ##\u6570\u636e\u5e93\u8fde\u63a5\u6c60\u4fe1\u606f\u914d\u7f6e
  3. spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
  4. spring.datasource.driver-class-name=com.mysql.jdbc.Driver
  5. spring.datasource.url=jdbc:mysql://127.0.0.1:3306/springboot?characterEncoding=utf-8
  6. spring.datasource.username=root
  7. spring.datasource.password=guanglei
  8. # \u4e0b\u9762\u4e3a\u8fde\u63a5\u6c60\u7684\u8865\u5145\u8bbe\u7f6e\uff0c\u5e94\u7528\u5230\u4e0a\u9762\u6240\u6709\u6570\u636e\u6e90\u4e2d
  9. # \u521d\u59cb\u5316\u5927\u5c0f\uff0c\u6700\u5c0f\uff0c\u6700\u5927
  10. spring.datasource.initialSize=5
  11. spring.datasource.minIdle=5
  12. spring.datasource.maxActive=20
  13. # \u914d\u7f6e\u83b7\u53d6\u8fde\u63a5\u7b49\u5f85\u8d85\u65f6\u7684\u65f6\u95f4
  14. spring.datasource.maxWait=60000
  15. # \u914d\u7f6e\u95f4\u9694\u591a\u4e45\u624d\u8fdb\u884c\u4e00\u6b21\u68c0\u6d4b\uff0c\u68c0\u6d4b\u9700\u8981\u5173\u95ed\u7684\u7a7a\u95f2\u8fde\u63a5\uff0c\u5355\u4f4d\u662f\u6beb\u79d2
  16. spring.datasource.timeBetweenEvictionRunsMillis=60000
  17. # \u914d\u7f6e\u4e00\u4e2a\u8fde\u63a5\u5728\u6c60\u4e2d\u6700\u5c0f\u751f\u5b58\u7684\u65f6\u95f4\uff0c\u5355\u4f4d\u662f\u6beb\u79d2
  18. spring.datasource.minEvictableIdleTimeMillis=300000
  19. spring.datasource.validationQuery=SELECT 1 FROM DUAL
  20. spring.datasource.testWhileIdle=true
  21. spring.datasource.testOnBorrow=false
  22. spring.datasource.testOnReturn=false
  23. # \u6253\u5f00PSCache\uff0c\u5e76\u4e14\u6307\u5b9a\u6bcf\u4e2a\u8fde\u63a5\u4e0aPSCache\u7684\u5927\u5c0f
  24. spring.datasource.poolPreparedStatements=true
  25. spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
  26. # \u914d\u7f6e\u76d1\u63a7\u7edf\u8ba1\u62e6\u622a\u7684filters\uff0c\u53bb\u6389\u540e\u76d1\u63a7\u754c\u9762sql\u65e0\u6cd5\u7edf\u8ba1\uff0c'wall'\u7528\u4e8e\u9632\u706b\u5899
  27. spring.datasource.filters=stat,wall,log4j
  28. # \u901a\u8fc7connectProperties\u5c5e\u6027\u6765\u6253\u5f00mergeSql\u529f\u80fd\uff1b\u6162SQL\u8bb0\u5f55
  29. spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
  30. # \u5408\u5e76\u591a\u4e2aDruidDataSource\u7684\u76d1\u63a7\u6570\u636e
  31. #spring.datasource.useGlobalDataSourceStat=true
  32. # druid \u8bbf\u95ee\u5730\u5740 http://host:port/druid/index.html
  33. ##Log Config
  34. logging.config=classpath:logback-spring.xml
  35. ## SpringData JPA Config
  36. spring.jpa.database=mysql
  37. spring.jpa.show-sql=true
  38. spring.jpa.hibernate.ddl-auto=update
  39. spring.jpa.generate-ddl=true
  40. server.port=9996

ehcache.xml

  1. <ehcache>
  2. <!-- Sets the path to the directory where cache .data files are created.
  3. If the path is a Java System Property it is replaced by
  4. its value in the running VM.
  5. The following properties are translated:
  6. user.home - User's home directory
  7. user.dir - User's current working directory
  8. java.io.tmpdir - Default temp file path -->
  9. <!--
  10. 指定一个目录:当 EHCache 把数据写到硬盘上时, 将把数据写到这个目录下.
  11. -->
  12. <diskStore path="tempDirectory"/>
  13. <!--Default Cache configuration. These will applied to caches programmatically created through
  14. the CacheManager.
  15. The following attributes are required for defaultCache:
  16. maxInMemory - Sets the maximum number of objects that will be created in memory
  17. eternal - Sets whether elements are eternal. If eternal, timeouts are ignored and the element
  18. is never expired.
  19. timeToIdleSeconds - Sets the time to idle for an element before it expires. Is only used
  20. if the element is not eternal. Idle time is now - last accessed time
  21. timeToLiveSeconds - Sets the time to live for an element before it expires. Is only used
  22. if the element is not eternal. TTL is now - creation time
  23. overflowToDisk - Sets whether elements can overflow to disk when the in-memory cache
  24. has reached the maxInMemory limit.
  25. -->
  26. <!--
  27. 设置缓存的默认数据过期策略
  28. -->
  29. <defaultCache
  30. maxElementsInMemory="10000"
  31. eternal="false"
  32. timeToIdleSeconds="120"
  33. timeToLiveSeconds="120"
  34. overflowToDisk="true"
  35. />
  36. <!--
  37. 设定具体的命名缓存的数据过期策略。每个命名缓存代表一个缓存区域
  38. 缓存区域(region):一个具有名称的缓存块,可以给每一个缓存块设置不同的缓存策略。
  39. 如果没有设置任何的缓存区域,则所有被缓存的对象,都将使用默认的缓存策略。即:<defaultCache.../>
  40. Hibernate 在不同的缓存区域保存不同的类/集合。
  41. 对于类而言,区域的名称是类名。如:com.ekeyfund.springboot.jpa.entity.User
  42. 对于集合而言,区域的名称是类名加属性名。如com.ekeyfund.springboot.jpa.entity.User.roleList
  43. -->
  44. <!--
  45. name: 设置缓存的名字,它的取值为类的全限定名或类的集合的名字
  46. maxElementsInMemory: 设置基于内存的缓存中可存放的对象最大数目
  47. eternal: 设置对象是否为永久的, true表示永不过期,
  48. 此时将忽略timeToIdleSeconds 和 timeToLiveSeconds属性; 默认值是false
  49. timeToIdleSeconds:设置对象空闲最长时间,以秒为单位, 超过这个时间,对象过期。
  50. 当对象过期时,EHCache会把它从缓存中清除。如果此值为0,表示对象可以无限期地处于空闲状态。
  51. timeToLiveSeconds:设置对象生存最长时间,超过这个时间,对象过期。
  52. 如果此值为0,表示对象可以无限期地存在于缓存中. 该属性值必须大于或等于 timeToIdleSeconds 属性值
  53. overflowToDisk:设置基于内存的缓存中的对象数目达到上限后,是否把溢出的对象写到基于硬盘的缓存中
  54. -->
  55. <cache name="com.ekeyfund.springcloud.entity.Department"
  56. maxElementsInMemory="1"
  57. eternal="false"
  58. timeToIdleSeconds="300"
  59. timeToLiveSeconds="600"
  60. overflowToDisk="true"
  61. />
  62. <cache name="com.ekeyfund.springcloud.entity.User"
  63. maxElementsInMemory="1000"
  64. eternal="true"
  65. timeToIdleSeconds="0"
  66. timeToLiveSeconds="0"
  67. overflowToDisk="false"
  68. />
  69. <cache name="com.ekeyfund.springcloud.entity.Role"
  70. maxElementsInMemory="1000"
  71. eternal="true"
  72. timeToIdleSeconds="0"
  73. timeToLiveSeconds="0"
  74. overflowToDisk="false"
  75. />
  76. </ehcache>

logback.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <configuration>
  3. <!--<include resource="org/springframework/boot/logging/logback/base.xml"/>-->
  4. <!-- 项目的appid -->
  5. <property name="APP_ID" value="SpringCloud-Provider-User-Service"/>
  6. <property name="LOG_PATH" value="logs"></property>
  7. <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
  8. <encoder>
  9. <pattern>%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>
  10. </encoder>
  11. </appender>
  12. <appender name="FILE_LOG"
  13. class="ch.qos.logback.core.rolling.RollingFileAppender">
  14. <filter class="ch.qos.logback.classic.filter.LevelFilter">
  15. <level>DEBUG</level>
  16. </filter>
  17. <file>${LOG_PATH}/${APP_ID}/access.log</file>
  18. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  19. <fileNamePattern>${LOG_PATH}/${APP_ID}/access.log.%d{yyyy-MM-dd}.zip
  20. </fileNamePattern>
  21. <maxHistory>10</maxHistory>
  22. </rollingPolicy>
  23. <encoder>
  24. <pattern>%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
  25. </encoder>
  26. </appender>
  27. <appender name="FILE_DEBUG"
  28. class="ch.qos.logback.core.rolling.RollingFileAppender">
  29. <filter class="ch.qos.logback.classic.filter.LevelFilter">
  30. <level>DEBUG</level>
  31. <onMatch>ACCEPT</onMatch>
  32. <onMismatch>DENY</onMismatch>
  33. </filter>
  34. <file>${LOG_PATH}/${APP_ID}/access_debug.log</file>
  35. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  36. <fileNamePattern>${LOG_PATH}/${APP_ID}/access_debug.log.%d{yyyy-MM-dd}.zip
  37. </fileNamePattern>
  38. <maxHistory>10</maxHistory>
  39. </rollingPolicy>
  40. <encoder>
  41. <pattern>%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
  42. </encoder>
  43. </appender>
  44. <appender name="FILE_INFO"
  45. class="ch.qos.logback.core.rolling.RollingFileAppender">
  46. <filter class="ch.qos.logback.classic.filter.LevelFilter">
  47. <level>INFO</level>
  48. <onMatch>ACCEPT</onMatch>
  49. <onMismatch>DENY</onMismatch>
  50. </filter>
  51. <file>${LOG_PATH}/${APP_ID}/access_info.log</file>
  52. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  53. <fileNamePattern>${LOG_PATH}/${APP_ID}/access_info.log.%d{yyyy-MM-dd}.zip
  54. </fileNamePattern>
  55. <maxHistory>10</maxHistory>
  56. </rollingPolicy>
  57. <encoder>
  58. <pattern>%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
  59. </encoder>
  60. </appender>
  61. <appender name="FILE_WARN"
  62. class="ch.qos.logback.core.rolling.RollingFileAppender">
  63. <filter class="ch.qos.logback.classic.filter.LevelFilter">
  64. <level>WARN</level>
  65. <onMatch>ACCEPT</onMatch>
  66. <onMismatch>DENY</onMismatch>
  67. </filter>
  68. <file>${LOG_PATH}/${APP_ID}/access_warn.log</file>
  69. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  70. <fileNamePattern>${LOG_PATH}/${APP_ID}/access_warn.log.%d{yyyy-MM-dd}.zip
  71. </fileNamePattern>
  72. <maxHistory>10</maxHistory>
  73. </rollingPolicy>
  74. <encoder>
  75. <pattern>%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
  76. </encoder>
  77. </appender>
  78. <appender name="FILE_ERROR"
  79. class="ch.qos.logback.core.rolling.RollingFileAppender">
  80. <filter class="ch.qos.logback.classic.filter.LevelFilter">
  81. <level>ERROR</level>
  82. <onMatch>ACCEPT</onMatch>
  83. <onMismatch>DENY</onMismatch>
  84. </filter>
  85. <file>${LOG_PATH}/${APP_ID}/access_error.log</file>
  86. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  87. <fileNamePattern>${LOG_PATH}/${APP_ID}/access_error.log.%d{yyyy-MM-dd}.zip
  88. </fileNamePattern>
  89. <maxHistory>10</maxHistory>
  90. </rollingPolicy>
  91. <encoder>
  92. <pattern>%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
  93. </encoder>
  94. </appender>
  95. <appender name="ASYNC_LOG" class="ch.qos.logback.classic.AsyncAppender">
  96. <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
  97. <discardingThreshold>0</discardingThreshold>
  98. <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
  99. <queueSize>512</queueSize>
  100. <appender-ref ref="FILE_LOG"/>
  101. </appender>
  102. <appender name="ASYNC_LOG" class="ch.qos.logback.classic.AsyncAppender">
  103. <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
  104. <discardingThreshold>0</discardingThreshold>
  105. <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
  106. <queueSize>512</queueSize>
  107. <appender-ref ref="FILE_LOG"/>
  108. </appender>
  109. <appender name="ASYNC_LOG_DEBUG" class="ch.qos.logback.classic.AsyncAppender">
  110. <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
  111. <discardingThreshold>0</discardingThreshold>
  112. <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
  113. <queueSize>512</queueSize>
  114. <appender-ref ref="FILE_DEBUG"/>
  115. </appender>
  116. <appender name="ASYNC_LOG_INFO" class="ch.qos.logback.classic.AsyncAppender">
  117. <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
  118. <discardingThreshold>0</discardingThreshold>
  119. <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
  120. <queueSize>512</queueSize>
  121. <appender-ref ref="FILE_INFO"/>
  122. </appender>
  123. <appender name="ASYNC_LOG_WARN" class="ch.qos.logback.classic.AsyncAppender">
  124. <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
  125. <discardingThreshold>0</discardingThreshold>
  126. <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
  127. <queueSize>512</queueSize>
  128. <appender-ref ref="FILE_WARN"/>
  129. </appender>
  130. <appender name="ASYNC_LOG_ERROR" class="ch.qos.logback.classic.AsyncAppender">
  131. <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
  132. <discardingThreshold>0</discardingThreshold>
  133. <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
  134. <queueSize>512</queueSize>
  135. <appender-ref ref="FILE_ERROR"/>
  136. </appender>
  137. <root level="INFO">
  138. <!-- appender referenced after it is defined -->
  139. <appender-ref ref="STDOUT"/>
  140. <appender-ref ref="ASYNC_LOG"/>
  141. <appender-ref ref="ASYNC_LOG_DEBUG"/>
  142. <appender-ref ref="ASYNC_LOG_INFO"/>
  143. <appender-ref ref="ASYNC_LOG_WARN"/>
  144. <appender-ref ref="ASYNC_LOG_ERROR"/>
  145. </root>
  146. <logger name="org.springframework" level="INFO"/>
  147. </configuration>

4.7 pom.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven./POM/4.0.0" xmlns:xsi="http://www./2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven./POM/4.0.0 http://maven./xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <artifactId>springcloud-provider-user-service</artifactId>
  6. <packaging>jar</packaging>
  7. <name>springcloud-user-service</name>
  8. <description>SpringCloud User Service Application</description>
  9. <parent>
  10. <groupId>com.ekeyfund.springcloud</groupId>
  11. <artifactId>springcloud-parent</artifactId>
  12. <version>2.0.0-SNAPSHOT</version>
  13. <relativePath>../pom.xml</relativePath>
  14. </parent>
  15. <properties>
  16. <start-class>com.ekeyfund.springcloud.SpringcloudUserServiceMasterApplication</start-class>
  17. </properties>
  18. <dependencies>
  19. <dependency>
  20. <groupId>org.springframework.boot</groupId>
  21. <artifactId>spring-boot-starter-data-jpa</artifactId>
  22. </dependency>
  23. <dependency>
  24. <groupId>org.springframework.boot</groupId>
  25. <artifactId>spring-boot-starter-web</artifactId>
  26. </dependency>
  27. </dependencies>
  28. <build>
  29. <plugins>
  30. <plugin>
  31. <groupId>org.springframework.boot</groupId>
  32. <artifactId>spring-boot-maven-plugin</artifactId>
  33. <configuration>
  34. <mainClass>${start-class}</mainClass>
  35. <layout>ZIP</layout>
  36. </configuration>
  37. <executions>
  38. <execution>
  39. <goals>
  40. <goal>repackage</goal>
  41. </goals>
  42. </execution>
  43. </executions>
  44. </plugin>
  45. </plugins>
  46. </build>
  47. </project>

4.8 启动类

  1. package com.ekeyfund.springcloud;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
  5. //@EnableDiscoveryClient//激活Eureka中的DiscoveryClient实现(自动化配置,创建DiscoveryClient接口针对Eureka客户端的EurekaDiscoveryClient实例)
  6. @SpringBootApplication
  7. public class SpringcloudUserServiceMasterApplication {
  8. public static void main(String[] args) {
  9. SpringApplication.run(SpringcloudUserServiceMasterApplication.class, args);
  10. }
  11. }

4.9 测试用例

  1. package com.ekeyfund.springcloud;
  2. import com.ekeyfund.springcloud.entity.Department;
  3. import com.ekeyfund.springcloud.entity.User;
  4. import com.ekeyfund.springcloud.service.DepartmentService;
  5. import com.ekeyfund.springcloud.service.UserService;
  6. import org.junit.Test;
  7. import org.junit.runner.RunWith;
  8. import org.slf4j.LoggerFactory;
  9. import org.springframework.beans.factory.annotation.Autowired;
  10. import org.springframework.boot.test.context.SpringBootTest;
  11. import org.springframework.context.annotation.ComponentScan;
  12. import org.springframework.test.context.junit4.SpringRunner;
  13. import java.util.Date;
  14. @RunWith(SpringRunner.class)
  15. @SpringBootTest
  16. @ComponentScan("com.ekeyfund.springcloud")
  17. public class SpringcloudUserServiceApplicationTests {
  18. private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(SpringcloudUserServiceApplicationTests.class);
  19. @Test
  20. public void contextLoads() {
  21. }
  22. @Autowired
  23. private DepartmentService departmentService;
  24. @Autowired
  25. private UserService userService;
  26. @Test
  27. public void testDepartmentService(){
  28. Department department=new Department();
  29. department.setName("dev");
  30. Department result =departmentService.saveDepartment(department);
  31. LOGGER.info("add result "+result);
  32. Long id =1L;
  33. result =departmentService.getDepartmentById(id);
  34. LOGGER.info("get department "+result);
  35. }
  36. @Test
  37. public void testUserRegister()throws Exception{
  38. User user =new User();
  39. user.setName("tony");
  40. user.setPassword("666666");
  41. user.setCreateDate(new Date());
  42. Department department=departmentService.getDepartmentById(1L);
  43. user.setDepartment(department);
  44. User result =userService.register(user);
  45. LOGGER.info("register result "+result);
  46. }
  47. @Test
  48. public void testWriteOff()throws Exception{
  49. User user =new User();
  50. user.setName("tony");
  51. user.setPassword("666666");
  52. userService.writeOff(user);
  53. }
  54. @Test
  55. public void testUserLogin()throws Exception{
  56. User user =new User();
  57. user.setName("tony");
  58. user.setPassword("666666");
  59. User result =userService.login(user.getName(),user.getPassword());
  60. LOGGER.info("login "+result);
  61. }
  62. @Test
  63. public void testUserIsExist()throws Exception{
  64. User user =new User();
  65. user.setId(4L);
  66. boolean result =userService.isExists(user);
  67. LOGGER.info("isExist "+result);
  68. }
  69. }

五 使用SpringBoot实现服务消费者

所属maven模块:springcloud-consumer-h5

5.1 entity

主要包含User,Department,Role 
Role.java

  1. package com.ekeyfund.springcloud.entity;
  2. /**
  3. * Role Entity
  4. *
  5. * @author Liuguanglei liuguanglei@ekeyfund.com
  6. * @create 2017-06-下午2:36
  7. */
  8. public class Role {
  9. private Long id;
  10. private String name;
  11. public Long getId() {
  12. return id;
  13. }
  14. public void setId(Long id) {
  15. this.id = id;
  16. }
  17. public String getName() {
  18. return name;
  19. }
  20. public void setName(String name) {
  21. this.name = name;
  22. }
  23. @Override
  24. public String toString() {
  25. return new org.apache.commons.lang3.builder.ToStringBuilder(this)
  26. .append("id", id)
  27. .append("name", name)
  28. .toString();
  29. }
  30. }

Department.java

  1. package com.ekeyfund.springcloud.entity;
  2. import org.apache.commons.lang3.builder.ToStringBuilder;
  3. /**
  4. * Department Entity
  5. *
  6. * @author Liuguanglei liuguanglei@ekeyfund.com
  7. * @create 2017-06-下午2:31
  8. */
  9. public class Department {
  10. private Long id;
  11. private String name;
  12. public Long getId() {
  13. return id;
  14. }
  15. public void setId(Long id) {
  16. this.id = id;
  17. }
  18. public String getName() {
  19. return name;
  20. }
  21. public void setName(String name) {
  22. this.name = name;
  23. }
  24. @Override
  25. public String toString() {
  26. return new ToStringBuilder(this)
  27. .append("id", id)
  28. .append("name", name)
  29. .toString();
  30. }
  31. }

User.java

  1. package com.ekeyfund.springcloud.entity;
  2. import com.fasterxml.jackson.annotation.JsonBackReference;
  3. import org.apache.commons.lang3.builder.ToStringBuilder;
  4. import org.springframework.format.annotation.DateTimeFormat;
  5. import java.util.Date;
  6. import java.util.List;
  7. /**
  8. * User Entity
  9. *
  10. * @author Liuguanglei liuguanglei@ekeyfund.com
  11. * @create 2017-06-下午2:32
  12. */
  13. public class User {
  14. private Long id;
  15. private String name;
  16. private String password;
  17. @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  18. private Date createDate;
  19. @JsonBackReference
  20. private Department department;
  21. private List<Role> roleList;
  22. public Long getId() {
  23. return id;
  24. }
  25. public void setId(Long id) {
  26. this.id = id;
  27. }
  28. public String getName() {
  29. return name;
  30. }
  31. public void setName(String name) {
  32. this.name = name;
  33. }
  34. public String getPassword() {
  35. return password;
  36. }
  37. public void setPassword(String password) {
  38. this.password = password;
  39. }
  40. public Date getCreateDate() {
  41. return createDate;
  42. }
  43. public void setCreateDate(Date createDate) {
  44. this.createDate = createDate;
  45. }
  46. public Department getDepartment() {
  47. return department;
  48. }
  49. public void setDepartment(Department department) {
  50. this.department = department;
  51. }
  52. public List<Role> getRoleList() {
  53. return roleList;
  54. }
  55. public void setRoleList(List<Role> roleList) {
  56. this.roleList = roleList;
  57. }
  58. @Override
  59. public String toString() {
  60. return new ToStringBuilder(this)
  61. .append("id", id)
  62. .append("name", name)
  63. .append("password", password)
  64. .append("createDate", createDate)
  65. .append("department", department)
  66. .append("roleList", roleList)
  67. .toString();
  68. }
  69. }

5.2 Configuraiton

主要包含Spring MVC相关配置

MVCConfiguration.java

  1. package com.ekeyfund.springcloud.configuration;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.http.MediaType;
  5. import org.springframework.http.converter.HttpMessageConverter;
  6. import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
  7. import org.springframework.web.client.RestTemplate;
  8. import org.springframework.web.servlet.config.annotation.EnableWebMvc;
  9. import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
  10. import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
  11. import java.util.ArrayList;
  12. import java.util.List;
  13. @Configuration
  14. @EnableWebMvc
  15. public class MVCConfiguration extends WebMvcConfigurerAdapter{
  16. /**
  17. *
  18. * @return
  19. */
  20. @Bean
  21. public RequestMappingHandlerAdapter requestMappingHandlerAdapter(){
  22. RequestMappingHandlerAdapter requestMappingHandlerAdapter=new RequestMappingHandlerAdapter();
  23. List<HttpMessageConverter<?>> messageConverters =new ArrayList<>();
  24. messageConverters.add(mappingJackson2HttpMessageConverter());
  25. requestMappingHandlerAdapter.setMessageConverters(messageConverters);
  26. return requestMappingHandlerAdapter;
  27. }
  28. //@Bean
  29. public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(){
  30. MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter =new MappingJackson2HttpMessageConverter();
  31. List<MediaType> supportedMediaTypes =new ArrayList<>();
  32. supportedMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
  33. mappingJackson2HttpMessageConverter.setSupportedMediaTypes(supportedMediaTypes);
  34. return mappingJackson2HttpMessageConverter;
  35. }
  36. @Bean
  37. public RestTemplate restTemplate(){
  38. RestTemplate restTemplate =new RestTemplate();
  39. return restTemplate;
  40. }
  41. }

5.3 Controller

主要包含UserController

UserController.java

  1. package com.ekeyfund.springcloud.controller;
  2. import com.ekeyfund.springcloud.entity.User;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.web.bind.annotation.GetMapping;
  5. import org.springframework.web.bind.annotation.PathVariable;
  6. import org.springframework.web.bind.annotation.RestController;
  7. import org.springframework.web.client.RestTemplate;
  8. /**
  9. * UserController
  10. *
  11. * @author tony 18601767221@163.com
  12. * @create 2017-06-27-下午11:42
  13. * @see
  14. * @since JDK1.8u133
  15. */
  16. @RestController
  17. public class UserController {
  18. @Autowired
  19. private RestTemplate restTemplate;
  20. @GetMapping("user/get/{id}")
  21. public User get(@PathVariable Long id){
  22. return this.restTemplate.getForObject("http://127.0.0.1:9996/get/{1}",User.class,id);
  23. }
  24. }

5.4 应用配置

主要包含springboot的application.properties

application.properties

  1. server.port=9991
  2. server.tomcat.uri-encoding=UTF-8

5.5 启动类

  1. package com.ekeyfund.springcloud;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. @SpringBootApplication
  5. public class SpringcloudConsumerH5Application {
  6. public static void main(String[] args) {
  7. SpringApplication.run(SpringcloudConsumerH5Application.class, args);
  8. }
  9. }

5.6 测试服务调用

9991端口的服务消费者会调用9996端口的服务提供者接口。 
通常在实际的开发中会遇到类似的情景:例如PC/H5/Android/IOS会去调用User模块的登录服务。

RestTemplate Call

弊端:因为程序调用的IP和端口采用了硬编码,而IP和端口可能变更,因此难以维护。 
而当服务提供者宕机后服务会不可用,后面会在系统中引入服务注册、发现组件,该组件主要是维护了一个服务注册表,服务提供者和消费者将服务注册到该注册表中,而服务注册和发现组件会通过发送心跳来判断服务是否可用。

六 使用Eureka实现服务发现组件

所属maven模块:springcloud-eureka-server

1 pom.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven./POM/4.0.0" xmlns:xsi="http://www./2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven./POM/4.0.0 http://maven./xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <groupId>com.ekeyfund.springcloud</groupId>
  6. <artifactId>springcloud-eureka-server</artifactId>
  7. <packaging>jar</packaging>
  8. <name>springcloud-eureka-server</name>
  9. <description>SpringCloud Eureka Server </description>
  10. <parent>
  11. <groupId>com.ekeyfund.springcloud</groupId>
  12. <artifactId>springcloud-parent</artifactId>
  13. <version>2.0.0-SNAPSHOT</version>
  14. <relativePath>../pom.xml</relativePath>
  15. </parent>
  16. <properties>
  17. <start-class>com.ekeyfund.springcloud.SpringcloudEurekaServerApplication</start-class>
  18. </properties>
  19. </project>

2 编写启动类,在启动类上添加@EnableEurekaServer注解,声明这是一个Eureka Server

  1. package com.ekeyfund.springcloud;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
  5. /**
  6. * 单点eureka server
  7. */
  8. @EnableEurekaServer //启用Eureka Server
  9. @SpringBootApplication
  10. public class SpringcloudEurekaServerApplication {
  11. public static void main(String[] args) {
  12. SpringApplication.run(SpringcloudEurekaServerApplication.class, args);
  13. }
  14. }

3 在应用配置文件application.properties添加如下内容:

  1. spring.application.name=springcloud-cureka-server
  2. server.port=9999
  3. eureka.instance.hostname=127.0.0.1
  4. #定义注册中心的地址
  5. eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/
  6. #不向注册中心注册自己
  7. eureka.client.register-with-eureka=false
  8. #注册中心的职责就是去维护服务实例,不需要去检索服务
  9. eureka.client.fetch-registry=false
  10. eureka.instance.prefer-ip-address=true

4 测试访问Eureka Server

运行SpringcloudEurekaServerApplication,在浏览器输入 http://127.0.0.1:9999即可以访问Eureka Server

Eureka Server

七 服务注册

所属maven模块 springcloud-provider-user-service

1 pom.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven./POM/4.0.0" xmlns:xsi="http://www./2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven./POM/4.0.0 http://maven./xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <artifactId>springcloud-provider-user-service</artifactId>
  6. <packaging>jar</packaging>
  7. <name>springcloud-user-service</name>
  8. <description>SpringCloud User Service Application</description>
  9. <parent>
  10. <groupId>com.ekeyfund.springcloud</groupId>
  11. <artifactId>springcloud-parent</artifactId>
  12. <version>2.0.0-SNAPSHOT</version>
  13. <relativePath>../pom.xml</relativePath>
  14. </parent>
  15. <properties>
  16. <start-class>com.ekeyfund.springcloud.SpringcloudUserServiceMasterApplication</start-class>
  17. </properties>
  18. <dependencies>
  19. <dependency>
  20. <groupId>org.springframework.boot</groupId>
  21. <artifactId>spring-boot-starter-data-jpa</artifactId>
  22. </dependency>
  23. <dependency>
  24. <groupId>org.springframework.boot</groupId>
  25. <artifactId>spring-boot-starter-web</artifactId>
  26. </dependency>
  27. <!-- eureka client-->
  28. <dependency>
  29. <groupId>org.springframework.cloud</groupId>
  30. <artifactId>spring-cloud-starter-eureka</artifactId>
  31. </dependency>
  32. </dependencies>
  33. <build>
  34. <plugins>
  35. <plugin>
  36. <groupId>org.springframework.boot</groupId>
  37. <artifactId>spring-boot-maven-plugin</artifactId>
  38. <configuration>
  39. <mainClass>${start-class}</mainClass>
  40. <layout>ZIP</layout>
  41. </configuration>
  42. <executions>
  43. <execution>
  44. <goals>
  45. <goal>repackage</goal>
  46. </goals>
  47. </execution>
  48. </executions>
  49. </plugin>
  50. </plugins>
  51. </build>
  52. </project>

2 在application.properties文件中添加以下配置:

  1. #####Eureka Client Config#######
  2. #设置服务名称
  3. spring.application.name=springcloud-provider-user-service
  4. #eureka 单实例配置
  5. #eureka.client.service-url.defaultZone=http://127.0.0.1:9999/eureka
  6. eureka.instance.prefer-ip-address=true

其中spring.application.name是指定注册到Eureka Server上的应用名称 
eureka.instance.prefer-ip-address表示将自己的IP注册到Eureka Server

3 编写启动类,在启动类上添加@EnableDiscoveryClient注解,声明这是一个Eureka Client

  1. package com.ekeyfund.springcloud;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
  5. @EnableDiscoveryClient//激活Eureka中的DiscoveryClient实现(自动化配置,创建DiscoveryClient接口针对Eureka客户端的EurekaDiscoveryClient实例)
  6. @SpringBootApplication
  7. public class SpringcloudUserServiceApplication {
  8. public static void main(String[] args) {
  9. SpringApplication.run(SpringcloudUserServiceMasterApplication.class, args);
  10. }
  11. }

4 测试服务注册 
首先运行SpringcloudEurekaServerApplication,启动Eureka Server,然后启动SpringcloudUserServiceApplication,启动Eureka Client。 
访问Eureka Server,效果如下图: 
Eureka Server Register

八 Eureka Server 高可用实现

在生产环境中,如果Eureka Server所在的机器发生宕机,那么服务发现组件将会变得不可用,因此需要实现高可用。Eureka Server可以通过运行多个实例并相互注册的方式实现高可用部署,实例之间会彼此增量同步信息,从而保持所有节点的数据一致。

所属maven模块springcloud-eureka-server-ha

该模块使用了springboot的多环境配置特性来激活两个Eureka Server,因此准备了application.properties,application-master.properties和application-slave.properties三个配置文件

application.properties

  1. spring.profiles.active=master
  2. ##使用ip地址的形式定义注册中心的地址
  3. eureka.instance.prefer-ip-address=true
  4. #禁用自我保护模式
  5. #eureka.server.enable-self-preservation=false
  6. ###eureka server 启用安全验证
  7. #security.user.name=tony
  8. #security.user.password=666666
  9. #security.basic.enabled=true
  10. ##服务续约任务的调用间隔时间默认为30s
  11. #eureka.instance.lease-renewal-interval-in-seconds=3
  12. ###定义服务失效的时间默认是90s
  13. #eureka.instance.lease-expiration-duration-in-seconds=540

application-master.properties

  1. spring.application.name=springcloud-eureka-server-ha
  2. server.port=9998
  3. eureka.instance.hostname=127.0.0.1
  4. eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:9997/eureka/

application-slave.properties

  1. spring.application.name=springcloud-eureka-server-ha
  2. server.port=9997
  3. eureka.instance.hostname=127.0.0.1
  4. eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:9998/eureka/

同时准备两个启动类用来启动两个Eureka Server

SpringcloudEurekaMasterServerApplication.java

  1. package com.ekeyfund.springcloud;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
  5. @EnableEurekaServer
  6. @SpringBootApplication
  7. public class SpringcloudEurekaMasterServerApplication {
  8. public static void main(String[] args) {
  9. SpringApplication.run(SpringcloudEurekaMasterServerApplication.class, args);
  10. }
  11. }

SpringcloudEurekaSlaveServiceApplication.java

  1. package com.ekeyfund.springcloud;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
  5. @EnableEurekaServer
  6. @SpringBootApplication
  7. public class SpringcloudEurekaSlaveServiceApplication {
  8. public static void main(String[] args) {
  9. SpringApplication.run(SpringcloudEurekaSlaveServiceApplication.class, args);
  10. }
  11. }

分别运行SpringcloudEurekaMasterServerApplication和SpringcloudEurekaSlaveServiceApplication后会发现两个注册中心已经完成相互注册

9998端口的Eureka Server 
9998端口的Eureka Server

9997端口的Eureka Server 
9997端口的Eureka Server

所属maven模块 springcloud-provider-user-service

服务提供者的服务注册只需要改变application.properties的注册地址即可

  1. #####Eureka Client Config#######
  2. #设置服务名称
  3. spring.application.name=springcloud-provider-user-service
  4. #指定服务注册中心的地址 ###高可用改造后可以加上多个注册中心的地址
  5. eureka.client.service-url.defaultZone=http://127.0.0.1:9998/eureka/,http://127.0.0.1:9997/eureka/
  6. eureka.instance.prefer-ip-address=true
  7. #####Eureka Client Config#######
  8. #指定服务提供者的端口
  9. server.port=9996

刷新Eureka Server,查看高可用的Eureka Server

user服务同时注册在两个Eureka Server

eureka server ha

eureka server ha

九 Eureka Server实现安全验证

默认情况下Eureka Server允许匿名访问,这里创建一个需要登录后才能访问Eureka Server

在pom.xml中添加安全依赖

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-security</artifactId>
  4. </dependency>

然后在application.properties中添加http basic验证配置

  1. ##eureka server 启用安全验证
  2. security.user.name=tony
  3. security.user.password=666666
  4. security.basic.enabled=true

运行SpringcloudEurekaMasterServerApplication或者SpringcloudEurekaSlaveServerApplication后,访问Eureka Server需要提供用户名和密码才能访问 
eureka security

将服务注册到需要认证的Eureka Server,只需要将eureka.client.serviceUrl.defaultZone配置为http://user:password@127.0.0.1:9998/eureka/,http://user:password@127.0.0.1:9997/eureka/即可

例如 高可用Eureka Server的注册地址变更为

master

  1. spring.application.name=springcloud-eureka-server-ha
  2. server.port=9998
  3. eureka.instance.hostname=127.0.0.1
  4. eureka.client.serviceUrl.defaultZone=http://tony:666666@${eureka.instance.hostname}:9997/eureka/

slave

  1. spring.application.name=springcloud-eureka-server-ha
  2. server.port=9997
  3. eureka.instance.hostname=127.0.0.1
  4. eureka.client.serviceUrl.defaultZone=http://tony:666666@${eureka.instance.hostname}:9998/eureka/

十 使用Ribbon实现客户端负载均衡

所属maven模块:springcloud-consumer-h5-ribbon-hystrix

Ribbon是Netflix发布的负载均衡器,有助于控制HTTP和TCP客户端的行为,为Ribbon配置服务提供者地址列表后,Ribbon可以基于负载均衡算法(例如轮询、随机)自动的帮助消费者去请求。 
在SpringCloud中,当Ribbon与Eureka配合使用时,Ribbon可自动从Eureka Server获取服务提供者地址列表,并基于负载均衡算法,请求其中一个服务提供者实例。

10.1 为服务消费者整合Ribbon

pom.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven./POM/4.0.0" xmlns:xsi="http://www./2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven./POM/4.0.0 http://maven./xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <groupId>com.ekeyfund.springcloud</groupId>
  6. <artifactId>springcloud-consumer-h5-ribbon-hystrix</artifactId>
  7. <packaging>jar</packaging>
  8. <name>springcloud-consumer-h5-ribbon-hystrix</name>
  9. <description>Spring Cloud H5 Appliaction</description>
  10. <parent>
  11. <groupId>com.ekeyfund.springcloud</groupId>
  12. <artifactId>springcloud-parent</artifactId>
  13. <version>2.0.0-SNAPSHOT</version>
  14. <relativePath>../pom.xml</relativePath>
  15. </parent>
  16. <properties>
  17. <start-class>com.ekeyfund.springcloud.SpringcloudH5RibbonHystrixApplication</start-class>
  18. </properties>
  19. <dependencies>
  20. <dependency>
  21. <groupId>org.springframework.cloud</groupId>
  22. <artifactId>spring-cloud-starter-ribbon</artifactId>
  23. </dependency>
  24. <dependency>
  25. <groupId>org.springframework.cloud</groupId>
  26. <artifactId>spring-cloud-starter-hystrix</artifactId>
  27. </dependency>
  28. <dependency>
  29. <groupId>org.springframework.boot</groupId>
  30. <artifactId>spring-boot-starter-web</artifactId>
  31. </dependency>
  32. <dependency>
  33. <groupId>org.springframework.cloud</groupId>
  34. <artifactId>spring-cloud-starter-eureka</artifactId>
  35. </dependency>
  36. <dependency>
  37. <groupId>com.fasterxml.jackson.core</groupId>
  38. <artifactId>jackson-databind</artifactId>
  39. <version>2.8.8</version>
  40. </dependency>
  41. </dependencies>
  42. <dependencyManagement>
  43. <dependencies>
  44. <dependency>
  45. <groupId>org.springframework.cloud</groupId>
  46. <artifactId>spring-cloud-dependencies</artifactId>
  47. <version>${spring-cloud.version}</version>
  48. <type>pom</type>
  49. <scope>import</scope>
  50. </dependency>
  51. </dependencies>
  52. </dependencyManagement>
  53. <build>
  54. <plugins>
  55. <plugin>
  56. <groupId>org.springframework.boot</groupId>
  57. <artifactId>spring-boot-maven-plugin</artifactId>
  58. <configuration>
  59. <mainClass>${start-class}</mainClass>
  60. <layout>ZIP</layout>
  61. </configuration>
  62. <executions>
  63. <execution>
  64. <goals>
  65. <goal>repackage</goal>
  66. </goals>
  67. </execution>
  68. </executions>
  69. </plugin>
  70. </plugins>
  71. </build>
  72. </project>

MVCConfiguration.java

  1. package com.ekeyfund.springcloud.configuration;
  2. import org.springframework.cloud.client.loadbalancer.LoadBalanced;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.context.annotation.Configuration;
  5. import org.springframework.http.converter.HttpMessageConverter;
  6. import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
  7. import org.springframework.web.client.RestTemplate;
  8. import org.springframework.web.servlet.config.annotation.EnableWebMvc;
  9. import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
  10. import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
  11. import java.util.ArrayList;
  12. import java.util.List;
  13. /**
  14. * MVCConfiguration
  15. *
  16. * @author Liuguanglei 18601767221@163.com
  17. * @create 2017-06-下午1:01
  18. */
  19. @Configuration
  20. @EnableWebMvc
  21. public class MVCConfiguration extends WebMvcConfigurerAdapter{
  22. @Bean
  23. public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(){
  24. return new MappingJackson2HttpMessageConverter();
  25. }
  26. @Bean
  27. public RequestMappingHandlerAdapter requestMappingHandlerAdapter(MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter){
  28. RequestMappingHandlerAdapter requestMappingHandlerAdapter=new RequestMappingHandlerAdapter();
  29. List<HttpMessageConverter<?>> messageConverters=new ArrayList<>();
  30. messageConverters.add(mappingJackson2HttpMessageConverter);
  31. requestMappingHandlerAdapter.setMessageConverters(messageConverters);
  32. return requestMappingHandlerAdapter;
  33. }
  34. @Bean
  35. @LoadBalanced//开启客户端负载均衡
  36. public RestTemplate restTemplate(){
  37. return new RestTemplate();
  38. }
  39. }

相比之前的配置主要是在RestTemplate中添加了@LoadBalanced注解即可整合Ribbon实现客户端的负载均衡。

UserController.java

  1. package com.ekeyfund.springcloud.controller;
  2. import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
  3. import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
  4. import com.ekeyfund.springcloud.entity.User;
  5. import org.slf4j.LoggerFactory;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.cloud.client.ServiceInstance;
  8. import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
  9. import org.springframework.http.ResponseEntity;
  10. import org.springframework.web.bind.annotation.*;
  11. import org.springframework.web.client.RestTemplate;
  12. import java.util.ArrayList;
  13. import java.util.Arrays;
  14. import java.util.List;
  15. /**
  16. * User Controller
  17. *
  18. * @author Liuguanglei 18601767221@163.com
  19. * @create 2017-06-上午12:55
  20. */
  21. @RestController
  22. public class UserController {
  23. private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(UserController.class);
  24. @Autowired
  25. private RestTemplate restTemplate;
  26. @Autowired
  27. private LoadBalancerClient loadBalancerClient;
  28. @GetMapping("/login")
  29. public User login(@RequestParam String name, @RequestParam String password){
  30. LOGGER.info("call user service login method");
  31. ResponseEntity<User> responseEntity =this.restTemplate.getForEntity("http://SPRINGCLOUD-PROVIDER-USER-SERVICE/login?name={1},password={2}",User.class,name,password);
  32. return responseEntity.getBody();
  33. }
  34. @GetMapping("/list")
  35. public List<User> list(){
  36. User[] users=this.restTemplate.getForObject("http://SPRINGCLOUD-PROVIDER-USER-SERVICE/list",User[].class);
  37. List<User> userList = Arrays.asList(users);
  38. return userList;
  39. }
  40. @GetMapping("user/get/{id}")
  41. public User get(@PathVariable Long id){
  42. return this.restTemplate.getForObject("http://SPRINGCLOUD-PROVIDER-USER-SERVICE/get/id={1}",User.class,id);
  43. }
  44. /**
  45. * ribbon负载均衡测试方法
  46. */
  47. @GetMapping("/log-user-service-instance")
  48. public void logUserServiceInstance(){
  49. ServiceInstance serviceInstance=this.loadBalancerClient.choose("springcloud-provider-user-service");
  50. LOGGER.info("serviceInstance info ---> serviceId is "+serviceInstance.getServiceId()+" host is "+serviceInstance.getHost()+"port is "+serviceInstance.getPort() );
  51. }
  52. }

从UserController中的login,get和list方法可以看出,我们将请求地址变更为http://SPRINGCLOUD-PROVIDER-USER-SERVICE,而SPRINGCLOUD-PROVIDER-USER-SERVICE是用户微服务的虚拟主机名,当Ribbon和Eureka配合使用时,会自动将虚拟主机名映射城微服务的网络地址。

在新增的logUserServiceInstance方法中可以通过LoadBalancerClient的API更加直观的获取当前选择的用户微服务节点。

启动如下服务: 
ribbon-loadbalance

访问地址:http://127.0.0.1:9994/log-user-service-instance

观察控制台输出:

2017-06-29 11:26:39.112 INFO 13474 — [nio-9994-exec-7] c.e.s.controller.UserController : serviceInstance info —> serviceId is springcloud-provider-user-service host is 192.168.1.136port is 9996 
2017-06-29 11:26:41.000 INFO 13474 — [nio-9994-exec-8] c.e.s.controller.UserController : serviceInstance info —> serviceId is springcloud-provider-user-service host is 192.168.1.136port is 9995 
2017-06-29 11:26:42.126 INFO 13474 — [nio-9994-exec-1] c.e.s.controller.UserController : serviceInstance info —> serviceId is springcloud-provider-user-service host is 192.168.1.136port is 9996 
2017-06-29 11:26:48.926 INFO 13474 — [nio-9994-exec-4] c.e.s.controller.UserController : serviceInstance info —> serviceId is springcloud-provider-user-service host is 192.168.1.136port is 9995

可以看到此时请求会均匀分布到两个不同用户微服务节点上,说明已经实现了负载均衡。

application.properties

  1. spring.application.name=springcloud-consumer-h5-ribbon-hystrix
  2. server.port=9994
  3. eureka.client.service-url.defaultZone=http://tony:666666@127.0.0.1:9998/eureka/,http://tony:666666@127.0.0.1:9997/eureka/
  4. #eureka.instance.prefer-ip-address=true
  5. ##修改服务负载均衡规则为随机
  6. springcloud-provier-user-service.ribbon.NFLoadBalanceRuleClassName=com.netflix.loadbalancer.RandomRule

十一 使用Feign实现声明式REST调用

Feign是Netflix公司开发的声明式、模板化的HTTP客户端,其主要用途是更加便捷、优雅的调用HTTP API,Spring Cloud在原有基础上使Feign支持SpringMVC注解,并且整合了Ribbon和Eureka。

所属maven模块 springcloud-consumer-h5-feign

之前的maven模块springcloud-consumer-h5-ribbon-hystrix是使用RestTemplate(负载均衡是使用ribbon实现)调用RESTful API。 如下的登录方法:

  1. @GetMapping("/login")
  2. public User login(@RequestParam String name, @RequestParam String password){
  3. LOGGER.info("call user service login method");
  4. ResponseEntity<User> responseEntity =this.restTemplate.getForEntity("http://SPRINGCLOUD-PROVIDER-USER-SERVICE/login?name={1},password={2}",User.class,name,password);
  5. return responseEntity.getBody();
  6. }

由代码可知通过拼接字符串的方式构造URL,而在其他业务场景中可能还会有更多的参数,如果还以这种方式构造URL,那么就会变得更低效,难以维护。

引入Netflix公司开发的Feign实现声明式的RESTful API 调用

pom.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven./POM/4.0.0" xmlns:xsi="http://www./2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven./POM/4.0.0 http://maven./xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <groupId>com.ekeyfund.springcloud</groupId>
  6. <artifactId>springcloud-consumer-h5-feign</artifactId>
  7. <packaging>jar</packaging>
  8. <name>springcloud-consumer-h5-feign</name>
  9. <description>SpringCloud Feign H5 Application</description>
  10. <parent>
  11. <groupId>com.ekeyfund.springcloud</groupId>
  12. <artifactId>springcloud-parent</artifactId>
  13. <version>2.0.0-SNAPSHOT</version>
  14. <relativePath>../pom.xml</relativePath>
  15. </parent>
  16. <properties>
  17. <start-class>com.ekeyfund.springcloud.SpringcloudFeignH5Application</start-class>
  18. </properties>
  19. <dependencies>
  20. <dependency>
  21. <groupId>org.springframework.cloud</groupId>
  22. <artifactId>spring-cloud-starter-feign</artifactId>
  23. </dependency>
  24. </dependencies>
  25. <build>
  26. <plugins>
  27. <plugin>
  28. <groupId>org.springframework.boot</groupId>
  29. <artifactId>spring-boot-maven-plugin</artifactId>
  30. <configuration>
  31. <mainClass>${start-class}</mainClass>
  32. <layout>ZIP</layout>
  33. </configuration>
  34. <executions>
  35. <execution>
  36. <goals>
  37. <goal>repackage</goal>
  38. </goals>
  39. </execution>
  40. </executions>
  41. </plugin>
  42. </plugins>
  43. </build>
  44. </project>

创建一个Feign接口,并添加@FeignClient注解

  1. package com.ekeyfund.springcloud.feign;
  2. import com.ekeyfund.springcloud.entity.User;
  3. import org.springframework.cloud.netflix.feign.FeignClient;
  4. import org.springframework.web.bind.annotation.RequestMapping;
  5. import org.springframework.web.bind.annotation.RequestMethod;
  6. import org.springframework.web.bind.annotation.RequestParam;
  7. import java.util.List;
  8. /**
  9. * User Feign Client
  10. *
  11. * @author tony 18601767221@163.com
  12. * @create 2017-06-29-下午2:44
  13. * @see
  14. * @since JDK1.8u133
  15. */
  16. @FeignClient(value = "springcloud-provider-user-service") //
  17. public interface UserFeignClient {
  18. @RequestMapping(value = "/list",method = RequestMethod.GET)
  19. List<User> list();
  20. @RequestMapping(value = "/login",method = RequestMethod.GET)
  21. User login(@RequestParam("name") String name, @RequestParam("password") String password);
  22. }

@FeignClient注解中的springcloud-provider-user-service是一个任意的客户端名称,用于创建Ribbon负载均衡器。

修改Controller,让其调用Feign接口

  1. package com.ekeyfund.springcloud.controller;
  2. import com.ekeyfund.springcloud.entity.User;
  3. import com.ekeyfund.springcloud.feign.UserFeignClient;
  4. import org.slf4j.LoggerFactory;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.cloud.client.ServiceInstance;
  7. import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
  8. import org.springframework.web.bind.annotation.GetMapping;
  9. import org.springframework.web.bind.annotation.RequestParam;
  10. import org.springframework.web.bind.annotation.RestController;
  11. import java.util.List;
  12. /**
  13. * User Feign Controller
  14. *
  15. * @author Liuguanglei 18601767221@163.com
  16. * @create 2017-06-下午1:50
  17. */
  18. @RestController
  19. public class UserFeignController {
  20. private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(UserFeignController.class);
  21. @Autowired
  22. UserFeignClient userFeignClient;
  23. @Autowired
  24. private LoadBalancerClient loadBalancerClient;
  25. @GetMapping(value = "/list")
  26. public List<User> list(){
  27. return userFeignClient.list();
  28. }
  29. @GetMapping("/login")
  30. public User login(@RequestParam String name,@RequestParam String password){
  31. return userFeignClient.login(name,password);
  32. }
  33. /**
  34. * ribbon负载均衡测试方法
  35. * springcloud 将feign和ribbon以及eureka进行了集成
  36. */
  37. @GetMapping("/log-user-service-instance")
  38. public void loguserserviceinstance(){
  39. ServiceInstance serviceInstance=this.loadBalancerClient.choose("springcloud-provider-user-service");
  40. LOGGER.info("serviceInstance info ---> serviceId is "+serviceInstance.getServiceId()+" host is "+serviceInstance.getHost()+"port is "+serviceInstance.getPort() );
  41. }
  42. }

启动类

  1. package com.ekeyfund.springcloud;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
  5. import org.springframework.cloud.netflix.feign.EnableFeignClients;
  6. @EnableDiscoveryClient
  7. @EnableFeignClients //开启SpringCloud Feign的支持功能
  8. @SpringBootApplication
  9. public class SpringcloudFeignH5Application {
  10. public static void main(String[] args) {
  11. SpringApplication.run(SpringcloudFeignH5Application.class, args);
  12. }
  13. }

启动如下服务: 
feign

访问地址:http://127.0.0.1:9993/login?name=tony&password=666666

调用login接口返回的结果 
调用login接口返回的结果

访问http://127.0.0.1:9993/log-user-service-instance

查看控制台日志输出 
2017-06-29 14:56:56.341 INFO 16173 — [nio-9993-exec-4] c.e.s.controller.UserFeignController : serviceInstance info —> serviceId is springcloud-provider-user-service host is 192.168.1.136port is 9995 
2017-06-29 14:56:58.055 INFO 16173 — [nio-9993-exec-5] c.e.s.controller.UserFeignController : serviceInstance info —> serviceId is springcloud-provider-user-service host is 192.168.1.136port is 9996 
2017-06-29 14:56:59.310 INFO 16173 — [nio-9993-exec-6] c.e.s.controller.UserFeignController : serviceInstance info —> serviceId is springcloud-provider-user-service host is 192.168.1.136port is 9995 
2017-06-29 14:57:05.287 INFO 16173 — [nio-9993-exec-7] c.e.s.controller.UserFeignController : serviceInstance info —> serviceId is springcloud-provider-user-service host is 192.168.1.136port is 9996 
2017-06-29 14:57:06.340 INFO 16173 — [nio-9993-exec-8] c.e.s.controller.UserFeignController : serviceInstance info —> serviceId is springcloud-provider-user-service host is 192.168.1.136port is 9995

以上结果说明不仅实现了声明式的Restful API调用,还实现了客户端的负载均衡

十二 使用Hystrix实现微服务的容错处理

pom.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven./POM/4.0.0" xmlns:xsi="http://www./2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven./POM/4.0.0 http://maven./xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <groupId>com.ekeyfund.springcloud</groupId>
  6. <artifactId>springcloud-consumer-h5-ribbon-hystrix</artifactId>
  7. <packaging>jar</packaging>
  8. <name>springcloud-consumer-h5-ribbon-hystrix</name>
  9. <description>Spring Cloud H5 Appliaction</description>
  10. <parent>
  11. <groupId>com.ekeyfund.springcloud</groupId>
  12. <artifactId>springcloud-parent</artifactId>
  13. <version>2.0.0-SNAPSHOT</version>
  14. <relativePath>../pom.xml</relativePath>
  15. </parent>
  16. <properties>
  17. <start-class>com.ekeyfund.springcloud.SpringcloudH5RibbonHystrixApplication</start-class>
  18. </properties>
  19. <dependencies>
  20. <dependency>
  21. <groupId>org.springframework.cloud</groupId>
  22. <artifactId>spring-cloud-starter-ribbon</artifactId>
  23. </dependency>
  24. <dependency>
  25. <groupId>org.springframework.cloud</groupId>
  26. <artifactId>spring-cloud-starter-hystrix</artifactId>
  27. </dependency>
  28. <dependency>
  29. <groupId>org.springframework.boot</groupId>
  30. <artifactId>spring-boot-starter-web</artifactId>
  31. </dependency>
  32. <dependency>
  33. <groupId>org.springframework.cloud</groupId>
  34. <artifactId>spring-cloud-starter-eureka</artifactId>
  35. </dependency>
  36. <dependency>
  37. <groupId>com.fasterxml.jackson.core</groupId>
  38. <artifactId>jackson-databind</artifactId>
  39. <version>2.8.8</version>
  40. </dependency>
  41. </dependencies>
  42. <dependencyManagement>
  43. <dependencies>
  44. <dependency>
  45. <groupId>org.springframework.cloud</groupId>
  46. <artifactId>spring-cloud-dependencies</artifactId>
  47. <version>${spring-cloud.version}</version>
  48. <type>pom</type>
  49. <scope>import</scope>
  50. </dependency>
  51. </dependencies>
  52. </dependencyManagement>
  53. <build>
  54. <plugins>
  55. <plugin>
  56. <groupId>org.springframework.boot</groupId>
  57. <artifactId>spring-boot-maven-plugin</artifactId>
  58. <configuration>
  59. <mainClass>${start-class}</mainClass>
  60. <layout>ZIP</layout>
  61. </configuration>
  62. <executions>
  63. <execution>
  64. <goals>
  65. <goal>repackage</goal>
  66. </goals>
  67. </execution>
  68. </executions>
  69. </plugin>
  70. </plugins>
  71. </build>
  72. </project>

启动类:

添加@EnableCircuitBreaker为项目启动断路器支持

  1. package com.ekeyfund.springcloud;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
  5. import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
  6. @EnableCircuitBreaker //启动断路器支持
  7. @EnableDiscoveryClient
  8. @SpringBootApplication
  9. public class SpringcloudH5RibbonHystrixApplication {
  10. public static void main(String[] args) {
  11. SpringApplication.run(SpringcloudH5RibbonHystrixApplication.class, args);
  12. }
  13. }

修改UserController,让其中的list方法具备容错能力

  1. package com.ekeyfund.springcloud.controller;
  2. import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
  3. import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
  4. import com.ekeyfund.springcloud.entity.User;
  5. import org.slf4j.LoggerFactory;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.cloud.client.ServiceInstance;
  8. import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
  9. import org.springframework.http.ResponseEntity;
  10. import org.springframework.web.bind.annotation.*;
  11. import org.springframework.web.client.RestTemplate;
  12. import java.util.ArrayList;
  13. import java.util.Arrays;
  14. import java.util.List;
  15. /**
  16. * User Controller
  17. *
  18. * @author Liuguanglei 18601767221@163.com
  19. * @create 2017-06-上午12:55
  20. */
  21. @RestController
  22. public class UserController {
  23. private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(UserController.class);
  24. @Autowired
  25. private RestTemplate restTemplate;
  26. @Autowired
  27. private LoadBalancerClient loadBalancerClient;
  28. @GetMapping("/login")
  29. public User login(@RequestParam String name, @RequestParam String password){
  30. LOGGER.info("call user service login method");
  31. ResponseEntity<User> responseEntity =this.restTemplate.getForEntity("http://SPRINGCLOUD-PROVIDER-USER-SERVICE/login?name={1},password={2}",User.class,name,password);
  32. return responseEntity.getBody();
  33. }
  34. @HystrixCommand(fallbackMethod = "listFallback",commandProperties = {
  35. @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "50000"),
  36. @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds",value = "10000")
  37. },
  38. threadPoolProperties = {
  39. @HystrixProperty(name = "coreSize",value = "1"),
  40. @HystrixProperty(name="maxQueueSize",value = "20")
  41. }
  42. )
  43. @GetMapping("/list")
  44. public List<User> list(){
  45. User[] users=this.restTemplate.getForObject("http://SPRINGCLOUD-PROVIDER-USER-SERVICE/list",User[].class);
  46. List<User> userList = Arrays.asList(users);
  47. return userList;
  48. }
  49. /**
  50. * 当list方法所在的服务不可用时,会调用此方法
  51. * @return
  52. */
  53. public List<User> listFallback(){
  54. User user =new User();
  55. user.setName("admin");
  56. List<User> userList=new ArrayList<>();
  57. userList.add(user);
  58. return userList;
  59. }
  60. @GetMapping("user/get/{id}")
  61. public User get(@PathVariable Long id){
  62. return this.restTemplate.getForObject("http://SPRINGCLOUD-PROVIDER-USER-SERVICE/get/id={1}",User.class,id);
  63. }
  64. /**
  65. * ribbon负载均衡测试方法
  66. */
  67. @GetMapping("/log-user-service-instance")
  68. public void loguserserviceinstance(){
  69. ServiceInstance serviceInstance=this.loadBalancerClient.choose("springcloud-provider-user-service");
  70. LOGGER.info("serviceInstance info ---> serviceId is "+serviceInstance.getServiceId()+" host is "+serviceInstance.getHost()+"port is "+serviceInstance.getPort() );
  71. }
  72. }

由代码可知,为list方法添加一个回退方法listFallback,该方法与list方法具有相同的参数和返回值类型。

在list方法上,使用注解@HystrixCommand的fallBackMethod属性,指定回退方法是listFallback。

启动如下服务: 
这里写图片描述

访问地址:http://127.0.0.1:9994/list 
当服务状态可用时的返回结果 
服务状态可用

关掉两个springcloud-provider-user-service进程后 
user不可用
再次访问http://127.0.0.1:9994/list 
返回默认用户信息 
返回默认用户

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多