Springboot Eureka简单例子

一、菜鸟版

目录结构
在这里插入图片描述

1、新建一个Distribute父工程

2、新建一个eureka子项目

pom.xml主要依赖
<!--springboot版本-->
<version>2.2.6.RELEASE</version>

<!--springclooud版本-->
<properties>
	<java.version>1.8</java.version>
	<spring-cloud.version>Hoxton.SR8</spring-cloud.version>
</properties>

<!--eureka服务端依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

<!--springcloud版本控制-->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
主要代码

启动类上标注@EnableEurekaServer注解,启用eureka服务端

@SpringBootApplication
@EnableEurekaServer //启用eureka服务端
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class, args);
    }
}
application.yml配置文件
server:
  port: 10086 #启动端口
spring:
  application:
    name: huan-eureka #服务名称
eureka:
  client:
    service-url:
      defaultZone: http://localhost:${server.port}/eureka  #注册的服务
④访问http://localhost:10086 搭建成功

在这里插入图片描述

3、新建service-provider(服务的提供方)

目录结构
在这里插入图片描述

pom.xml主要依赖
<!--springboot版本-->
<version>2.2.6.RELEASE</version>

<!--springclooud版本-->
<properties>
	<java.version>1.8</java.version>
	<spring-cloud.version>Hoxton.SR8</spring-cloud.version>
</properties>

<!--eureka客户端依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--jdbc-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--web-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--mybatis-->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.4</version>
</dependency>
<!--mysql-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<!--lombok-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<!--springcloud版本控制-->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
②主要代码

a、User实体类

@Data   //提供get和set方法
@AllArgsConstructor //添加一个构造函数,该构造函数含有所有已声明字段属性参数
@NoArgsConstructor  //创建一个无参构造函数
public class User {
    private int id;
    private String username;
    private String password;
}

b、UserMapper接口

@Mapper
@Repository
public interface UserMapper {
    @Select("select * from t_user")
    public List<User> listUser();

    @Select("select * from t_user where id = #{id}")
    public User GetUserById(@Param("id") int id);
}

c、UserService业务类

@Service
public class UserService {

    @Autowired
    public UserMapper userMapper;

    public List<User> listUser(){
        return userMapper.listUser();
    }

    public User GetUserById(int id) {
        return userMapper.GetUserById(id);
    }
}

d、UserController控制类

@Controller
public class UserController {
    @Autowired
    UserService userService;

    @GetMapping("user")
    @ResponseBody
    public List<User> listUser(){
        return  userService.listUser();
    }

    @GetMapping({"user/{id}"})
    @ResponseBody
    public User GetUserById(@PathVariable int id){
        return userService.GetUserById(id);
    }
}

e、启动类中配置包扫描以及服务发现

@SpringBootApplication
@MapperScan("com.huan.service.mapper")//mapper接口的包扫描
@EnableDiscoveryClient //启动服务发现
public class ServiceProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServiceProviderApplication.class, args);
    }
}
③application.yml配置文件
server:
  port: 8080 #启动端口
spring:
  datasource: #MySQL数据库
    username: root
    password: root
    url: jdbc:mysql://123.60.12.197:3306/swagger
    driver-class-name: com.mysql.cj.jdbc.Driver
  application:
    name: service-provider #服务名称
mybatis:
  type-aliases-package: com.huan.service.pojo #mybatis实体类

eureka:
  client:
    service-url:
      defaultZone: http://localhost:10086/eureka #把服务注册到eureka
④接口测试(成功)

在这里插入图片描述
在这里插入图片描述

4、新建service-consumer(服务的消费方)

pom.xml主要依赖
<!--springboot版本-->
<version>2.2.6.RELEASE</version>

<!--springclooud版本-->
<properties>
	<java.version>1.8</java.version>
	<spring-cloud.version>Hoxton.SR8</spring-cloud.version>
</properties>

<!--eureka客户端依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--jdbc-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--web-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--mybatis-->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.4</version>
</dependency>
<!--mysql-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<!--lombok-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<!--springcloud版本控制-->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
②主要代码

a、启动类

@SpringBootApplication
@MapperScan("com.huan.service.mapper")//mapper接口的包扫描
@EnableDiscoveryClient //启动服务发现
public class ServiceConsumerApplication {
    /**
     * HTTP 请求工具,它提供了常见的REST请求方案的模版,
     * 例如 GET 请求、POST 请求、PUT 请求、DELETE 请求以及一些通用的请求执行方法 exchange 以及 execute
     */
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

    public static void main(String[] args) {
        SpringApplication.run(ServiceConsumerApplication.class, args);
    }
}

b、Controller控制器

@Controller
public class UserController {
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private DiscoveryClient discoveryClient; //包含了拉取的所有服务信息

    @Autowired
    UserService userService;

    @GetMapping("user")
    @ResponseBody
    public List<User> listUser(){
        return  userService.listUser();
    }

    @GetMapping({"user/{id}"})
    @ResponseBody
    public User GetUserById(@PathVariable int id){
        //获取服务
        List<ServiceInstance> instances = discoveryClient.getInstances("service-provider");
        //获得服务实例
        ServiceInstance instance = instances.get(0);
        //instance.getHost()获取主机号,instance.getPort()获取端口
        return this.restTemplate.getForObject("http://"+instance.getHost()+":"+instance.getPort()+"/user/"+id,User.class);
    }
}
③application.yml配置文件
server:
  port: 8081
spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://123.60.12.197:3306/swagger
    driver-class-name: com.mysql.cj.jdbc.Driver
  application:
    name: service-consumer #服务名称
mybatis:
  type-aliases-package: com.huan.service.pojo

eureka:
  client:
    service-url:
      defaultZone: http://localhost:10086/eureka #注册服务到eureka注册中心

5、最后测试

①启动三个模块

在这里插入图片描述

②访问http://localhost:10086,所有服务已成功注册

在这里插入图片描述

③访问消费方服务,成功调用

在这里插入图片描述

二、菜鸟plus版

①ribbon负载均衡

多启动一个加个服务提供方,启动类上加个@LoadBalanced就搞定了
在这里插入图片描述

@SpringBootApplication
@MapperScan("com.huan.service.mapper")//mapper接口的包扫描
@EnableDiscoveryClient //启动服务发现
public class ServiceConsumerApplication {
    /**
     * HTTP 请求工具,它提供了常见的REST请求方案的模版,
     * 例如 GET 请求、POST 请求、PUT 请求、DELETE 请求以及一些通用的请求执行方法 exchange 以及 execute
     */
    @Bean
    @LoadBalanced  //开启负载均衡
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

    public static void main(String[] args) {
        SpringApplication.run(ServiceConsumerApplication.class, args);
    }
}

地址改为service-provider服务提供方的id

@Controller
public class UserController {
    @GetMapping({"user/{id}"})
    @ResponseBody
    public User GetUserById(@PathVariable int id){
        return this.restTemplate.getForObject("http://service-provider/user/"+id,User.class);
    }
}

三、hystrix

分布式系统环境下,服务间类似依赖非常常见,一个业务调用通常依赖多个基础服务。对于同步调用,当库存服务不可用时,商品服务请求线程被阻塞,当有大批量请求调用库存服务时,最终可能导致整个商品服务资源耗尽,无法继续对外提供服务。并且这种不可用可能沿请求调用链向上传递,这种现象被称为雪崩效应。

添加依赖
<!--hystrix-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
添加@EnableCircuitBreaker 注解开启熔断器
@SpringBootApplication
@MapperScan("com.huan.service.mapper")//mapper接口的包扫描
@EnableDiscoveryClient //启动服务发现
@EnableCircuitBreaker   //开启熔断器
public class ServiceConsumerApplication {
    /**
     * HTTP 请求工具,它提供了常见的REST请求方案的模版,
     * 例如 GET 请求、POST 请求、PUT 请求、DELETE 请求以及一些通用的请求执行方法 exchange 以及 execute
     */
    @Bean
    @LoadBalanced  //开启负载均衡
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

    public static void main(String[] args) {
        SpringApplication.run(ServiceConsumerApplication.class, args);
    }
}
③添加一个GetUserByIdHystrix(int id)方法,通过@HystrixCommand(fallbackMethod = “GetUserByIdHystrix”)关联,返回类型改为String
@Controller
public class UserController {

    @GetMapping({"user/{id}"})
    @ResponseBody
    @HystrixCommand(fallbackMethod = "GetUserByIdHystrix")
    public String GetUserById(@PathVariable int id){
        return this.restTemplate.getForObject("http://service-provider/user/"+id,String.class);
    }

    public String GetUserByIdHystrix(int id){
        return "服务器繁忙,请稍后重试";
    }
}
④全局的熔断方法

@DefaultProperties(defaultFallback = “allHystrix”) //定义全局的熔断方法
@HystrixCommand //不写参数代表使用全局的熔断方法

@Controller
@DefaultProperties(defaultFallback = "allHystrix")  //定义全局的熔断方法
public class UserController {
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    UserService userService;

    @GetMapping("user")
    @ResponseBody
    @HystrixCommand //不写参数代表使用全局的熔断方法
    public String listUser(){
        return this.restTemplate.getForObject("http://service-provider/user/",String.class);
    }

    @GetMapping({"user/{id}"})
    @ResponseBody
    @HystrixCommand(fallbackMethod = "GetUserByIdHystrix") //指定熔断时执行的方法
    public String GetUserById(@PathVariable int id){
        
        return this.restTemplate.getForObject("http://"+instance.getHost()+":"+instance.getPort()+"/user/"+id,User.class);*/
        return this.restTemplate.getForObject("http://service-provider/user/"+id,String.class);
    }

    //指定的熔断方法(返回值要一致,参数列表必须跟熔断的方法一样)
    public String GetUserByIdHystrix(int id){
        return "服务器繁忙,请稍后重试";
    }

    //全局的熔断方法(返回值要一致,不用带参数)
    public String allHystrix(){
        return "全局-服务器繁忙,请稍后重试";
    }
}
⑤配置hystrix熔断器超时时间
hystrix:
  command:
    default:  #default全局有效
      execution:
        timeout:
          #是否开启超时熔断
          enabled: true
        isolation:
          thread:
            timeoutInMilliseconds: 6000 #断路器超时时间,默认1000ms

@SpringCloudApplication //组合注解包含了@SpringBootApplication、@EnableDiscoveryClient、@EnableCircuitBreaker

⑥hystrix的三种状态

关闭(closed)

正常情况下hystrix为关闭状态,所有请求都可以正常访问

半打开(half open)

在进入该状态后会放入部分请求;判断请求是否成功,不成功,进入open状态,重新计时,进入halfopen状态;成功,进入closed状态

打开(open)

统计请求的失败比例,达到阀值时,打开熔断器,请求被降级处理;延时一段时候后(默认休眠时间是5S)会进入halfopen状态;默认失败比例阀值是50%,请求次数最少不低于20次;

四、feign

①引入依赖
<!--openfeign-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
②启动类上加上@EnableFeignClients注解
@EnableFeignClients //启用feign组件

然后这些代码就可以注释掉了

/*@Bean
@LoadBalanced  //开启负载均衡
public RestTemplate restTemplate(){
    return new RestTemplate();
}*/
/*@Autowired
private RestTemplate restTemplate;*/
//return this.restTemplate.getForObject("http://service-provider/user/",String.class);
//return this.restTemplate.getForObject("http://service-provider/user/"+id,String.class);
③创建一个调用远程服务的接口UserClient(方法与Controller中的方法一样)
@FeignClient("service-provider")//调用服务的id
public interface UserClient {

    @GetMapping("users/user")//全局的请求路径在这里加上
    public List<User> listUser();

    @GetMapping("users/user/{id}")//全局的请求路径在这里加上
    public User GetUserById(@PathVariable int id);
}
④在Controller中调用方法
@Controller
@RequestMapping("users")
@DefaultProperties(defaultFallback = "allHystrix")  //定义全局的熔断方法
public class UserController {
    
    @Autowired
    UserClient userClient;

    @GetMapping("user")
    @ResponseBody
    @HystrixCommand //不写参数代表使用全局的熔断方法
    public String listUser(){
        return this.userClient.listUser().toString();
    }

    @GetMapping({"user/{id}"})
    @ResponseBody
    @HystrixCommand(fallbackMethod = "GetUserByIdHystrix") //指定熔断时执行的方法
    public String GetUserById(@PathVariable int id){        
        return this.userClient.GetUserById(id).toString();
    }

    //指定的熔断方法(返回值要一致,参数列表必须跟熔断的方法一样)
    public String GetUserByIdHystrix(int id){
        return "服务器繁忙,请稍后重试";
    }

    //全局的熔断方法(返回值要一致,不用带参数)
    public String allHystrix(){
        return "全局-服务器繁忙,请稍后重试";
    }
}
⑤开启feign的熔断功能
a、yml配置
feign:
  hystrix:
    enabled: true #开启feign的熔断功能
b、编写远程调用接口的实现类UserClientFallback
@Component//注入容器
public class UserClientFallback implements UserClient {
    @Override
    public List<User> listUser() {
        List<User> userList = null;
        User user=new User();
        user.setUsername("服务器忙,请稍后再试!(feign)");
        userList.add(user);
        return userList;
    }

    @Override
    public User GetUserById(int id) {
        User user=new User();
        user.setUsername("服务器忙,请稍后再试!(feign)");
        return user;
    }
}
c、上面的接口注解那里声明一下熔断实现类
@FeignClient(value = "service-provider",fallback = UserClientFallback.class)//调用服务的以及熔断的实现类
public interface UserClient {

    @GetMapping("users/user")//全局的请求路径在这里加上
    public List<User> listUser();

    @GetMapping("users/user/{id}")//全局的请求路径在这里加上
    public User GetUserById(@PathVariable int id);
}

貌似public List<User> listUser();这个方法熔断失败,后续再研究一下

五、zuul

1、菜鸟版

①新建一个子模块zuul

在这里插入图片描述

②引入zuul依赖
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
③启动类上加上@EnableZuulProxy注解
@SpringBootApplication
@EnableZuulProxy    //启用zuul组件
public class ZuulApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication.class, args);
    }
}
④配置文件
server:
  port: 10010
spring:
  application:
    name: zuul
zuul:
  routes:
    service-provider: #路由名称,可以随便写,习惯上路由名称
      path: /service-provider/** #你想把带有这个service-provider的请求路径路由到下面的地址
      url: http://localhost:8082

2、菜鸟puls版

①引入eureka
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
②把zuul网关注册到eureka
eureka:
  client:
    service-url:
      defaultZone: http://localhost:10086/eureka #注册服务到eureka注册中心
③在启动类中启动服务发现@EnableDiscoveryClient
@SpringBootApplication
@EnableZuulProxy    //启用zuul组件
@EnableDiscoveryClient //启动服务发现
public class ZuulApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication.class, args);
    }
}
④配置文件升级一下
zuul:
  routes:
    service-provider: #路由名称,可以随便写,习惯上路由名称
      path: /service-provider/** #你想把带有这个service-provider的请求路径路由到下面的地址
      #url: http://localhost:8082
      serviceId: service-provider #把zuul注册到eureka,这样就可以直接路由到这个服务(因为这个相同功能的服务可能分布式部署到了多台服务器上面)
   prefix: /api  #前缀
⑤配置文件大多数这样写

简简单单,真香
http://localhost:10010/api/service-provider/users/user/1

zuul:
  routes:
    service-provider: /service-provider/** #可以看作前面的是服务id,后面的是接口中的请求路径(把带有后面的请求路径的请求路由到前面的服务上面去)

3、zull过滤器

①编写Filter类
  • http://localhost:10010/api/service-provider/users/user/?name=huan
  • http://localhost:10010/api/service-consumer/users/user/?name=huan
package com.huan.zuul.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpStatus;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
/**
 * @author :huan
 * @date :2021/4/23 14:47
 * @description:TODO
 **/
@Component//放进spring容器
public class LoginFilter extends ZuulFilter {

    /**
     * @author: huan
     * @description:
     * 过滤器的类型:pre route post error
     * pre:在请求被路由(转发)之前调用
     * route:在路由(请求)转发时被调用
     * error:服务网关发生异常时被调用
     * post:在路由(转发)请求后调用
     */
    @Override
    public String filterType() {
        //登录应该在之前就过滤一下
        return "pre";
    }

    /**
     * @author: huan
     * @description:
     * 执行顺序,返回值越小,优先级越高
     */
    @Override
    public int filterOrder() {
        //弄大一点,这样以后前面如果还要加过滤器的话,就还有扩展的机会
        return 10;
    }

    /**
     * @author: huan
     * @description:
     * 是否执行下面的run方法
     * true:代表执行
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /**
     * @author: huan
     * @description:
     * 这里编写过滤器的业务逻辑
     */
    @Override
    public Object run() throws ZuulException {
        //初始化zuul的context上下文对象 import com.netflix.zuul.context.RequestContext;
        RequestContext context = RequestContext.getCurrentContext();
        //获取request对象
        HttpServletRequest request = context.getRequest();
        //获取请求参数
        String name = request.getParameter("name");
        if (StringUtils.isBlank(name)){//判断是否为空
            //拦截,不转发请求
            context.setSendZuulResponse(false);
            //响应状态码401
            context.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);
            //设置响应的提示
            context.setResponseBody("Didn't login!");
        }
        //返回null代表该过滤器啥都不做
        return null;
    }
}

六、最终版

e…就是把上面组件集成后的产品了
需要代码 留言

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值