Springcloud环境搭建与集成

创建父工程


添加pom依赖

<!--公共的一些配置-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>
​
    <!--1.管理 SpringBoot的jar包-->
    <!--SpringBoot-->
    <parent>
        <groupId> org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
    </parent>
​
    <!--2.管理 SpringCloud的jar包
    -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR3</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
​
    <!--3.这里是所有子项目都可以用的jar包-->
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

创建子工程


创建EurekaServer

  1. 添加pom依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--    eurekaServer-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
  1. 主类添加注解@EnableEurekaServer

@EnableEurekaServer
@SpringBootApplication
publicclassEurekaServerApplication10010 {
    publicstaticvoidmain(String[] args) {
        SpringApplication.run(EurekaServerApplication10010.class);
    }
}
  1. yml配置

server:
  port: 10010
​
eureka:
  instance:
    hostname: localhost #主机
  client:
    registerWithEureka: false #关闭自我注册
    fetchRegistry: false  # 禁止获取注册表
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
  server:
    enable-self-preservation: false  #关闭自我保护

创建EurekaClient

  1. 添加pom依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--        ereka客户端-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
  1. 添加注解@EnableEurekaClient

@SpringBootApplication
@EnableEurekaClient
publicclassUserApplication10020 {
    publicstaticvoidmain(String[] args) {
        SpringApplication.run(UserApplication10020.class);
    }
}
  1. yml配置

server:
  port: 10020
​
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:10010/eureka/
  instance:
    prefer-ip-address: true
    instance-id: user-server:10020
spring:
  application:
    name: user-server​

创建一个公共模块

多个EurekaClient都要用到的东西可以放在公共模块中

  1. 如pom依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.22</version>
    <scope>compile</scope>
</dependency>
<!--ereka客户端-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
在其他工程中导入
<dependency>
    <groupId>org.qyf</groupId>
    <artifactId>Common</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>
  1. 创建公共实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    long id;
    String name;
    int age;
    String info;
}

获取ip与端口


@Resource
private RestTemplate restTemplate;
@Resource
private DiscoveryClient discoveryClient;

@RequestMapping("/getUser/{id}")
public User getUser(@PathVariable("id") Long id){
    //        获取Eureka服务的ip和端口
    List<ServiceInstance> instanceList = discoveryClient.getInstances("user-server");//根据服务名获取实例集合
    ServiceInstance instanceInfo = instanceList.get(0);

    String ip=instanceInfo.getHost();
    int port=instanceInfo.getPort();
    System.out.println(ip+" ,"+port);

    String url="http://"+ip+":"+port+"/user/getUser/"+id;
    return restTemplate.getForObject(url,User.class);
}

RestTemplate服务通信

微服务的通信协议主流的有RPC,Http,SpringCloud是基于Http Restful 风格 ,在Java中发起一个Http请求的方式很多,比如 Apache的HttpClient , OKHttp等等 。Spring为我们封装了一个基于Restful的使用非常简单的Http客户端工具 RestTemplate ,我们就用它来实订单服务和用户服务的通信。

配置RestTemplate

  1. 直接在EurekaClient主类中配置

@SpringBootApplication
@EnableEurekaClient
public class OrderApplication10030 {
    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }

    public static void main(String[] args) {
        SpringApplication.run(OrderApplication10030.class);
    }
}
  1. 创建配置类

@Component
public class RestTemplateConfig {
     @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(){
        return  new RestTemplate();
    }
}

EurekaClient集群


以User-server为例

  1. 复制User-server-10020,重新命名为User-server-10021

  1. 记得rename

  1. 修改yml配置

  1. 启动

集成Ribbon负载均衡


  1. 导入依赖

<!--ribbon 负载均衡-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
  1. 开启负载均衡@LoadBalanced

@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
    return  new RestTemplate();
}
  1. Ribbon负载均衡算法与Template一致,主类或配置类 配置

 //负载均衡算法————随机
@Bean
public RandomRule randomRule(){
    return new RandomRule();
}

默认轮询算法,此外还有随机、权重、机房、重试算法

  1. 测试

@RestController
@RequestMapping("/order")
public class OrderController {
//    @Value("${server.port}")
//    private int port;
    @Resource
    private RestTemplate restTemplate;
    @Resource
    private DiscoveryClient discoveryClient;

    @RequestMapping("/getUser/{id}")
    public User getUser(@PathVariable("id") Long id) {
        //        获取Eureka服务的ip和端口
        List<ServiceInstance> instanceList = discoveryClient.getInstances("user-server");//根据服务名获取实例集合
        ServiceInstance instanceInfo = instanceList.get(0);

        String ip = instanceInfo.getHost();
        int port = instanceInfo.getPort();

        System.out.println(ip + " ," + port);

       // String url="http://"+ip+":"+port+"/user/getUser/"+id; 不在使用拼接的方式,使用服务名调用
        String url="http://user-server/user/getUser/"+id;

        User user=restTemplate.getForObject(url,User.class);
        return user;
    }
}

结果

http://192.168.206.1:10030/order/getUser/1

{
    "id": 1,
    "name": "张三",
    "age": 18,
    "info": "haha: 10021"
}
{
    "id": 1,
    "name": "张三",
    "age": 18,
    "info": "haha: 10020"
}

feign集成


  1. 导入依赖

 <!--        openFgign-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
  1. 主类添加注解@EnableFeignClients

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class PayApplication10040 {
    public static void main(String[] args) {
        SpringApplication.run(PayApplication10040.class);
    }
}
  1. 提供接口IUserFeignClient

@FeignClient(name="user-server") 
public interface IUserFeignClient {
    @RequestMapping("/user/getUser/{id}")
    public User getUser(@PathVariable("id") long id);
}
  1. Controller注入接口@Resource IUserFeignClient iUserFeignClient

@RestController
@RequestMapping("/pay")
public class PayController {
    @Resource
    IUserFeignClient iUserFeignClient;

    @RequestMapping("/getUser/{id}")
    public User getUser(@PathVariable("id") long id){
        return iUserFeignClient.getUser(id);
    }
}

Hystix集成


Ribbon集成Hystix

  1. 导入依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
  1. 启动类添加注解@EnableHystrix开启熔断支持

@SpringBootApplication
@EnableEurekaClient
@EnableHystrix
public class OrderApplication10030 {
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(){
        return  new RestTemplate();
    }
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication10030.class);
    }
}
  1. controller中的具体的调用方法上添加注解@HystrixCommand(fallbackMethod = "ribbonFallback")

fallbackMethod = "ribbonFallback"中的ribbonFallback是兜底方法
@RestController
@RequestMapping("/order")
public class OrderController {
    @Value("${server.port}")
    private int port;
    @Resource
    private RestTemplate restTemplate;
    @Resource
    private DiscoveryClient discoveryClient;

    @RequestMapping("/getUser/{id}")
    @HystrixCommand(fallbackMethod = "ribbonFallback")
    public User getUser(@PathVariable("id") Long id) {
        String url="http://user-server/user/getUser/"+id;
        User user=restTemplate.getForObject(url,User.class);
        return user;
    }
  1. 添加兜底方法(降级方法),方法名必须与fallbackMethod = "ribbonFallback"一致,方法参数必须与原方法一致

public User ribbonFallback(@PathVariable("id") long id) {
        return new User(id,"error",0,"ribbon hystrix 兜底方法,服务端大概是挂了");
    }
  1. 测试

http://192.168.206.1:10030/order/getUser/1
getUser服务有10020和10021两个端口
当轮询到10021时,关闭10021服务
{
    "id": 1,
    "name": "error",
    "age": 0,
    "info": "ribbon hystrix 兜底方法,服务端大概是挂了10030"
}

fegin集成Hystix

  1. feign已经集成Hystix,不需要额外导包

  1. yml配置

#    开启fegin的熔断
feign:
  hystrix:
    enabled: true
  1. 关联兜底方法fallbackFactory = UserFeginClientFackFactory.class

@FeignClient(name="user-server",fallbackFactory = UserFeginClientFackFactory.class)
public interface IUserFeignClient {
    @RequestMapping("/user/getUser/{id}")
    public User getUser(@PathVariable("id") long id);
}

创建UserFeginClientFackFactory类

@Component
public class UserFeginClientFackFactory implements FallbackFactory<IUserFeignClient> {
    @Override
    public IUserFeignClient create(Throwable throwable) {
        throwable.printStackTrace();
//        创建实现类
        return new IUserFeignClient(){
            @Override
            public User getUser(long id) {
                return new User(id,"熔断",18,"fegin的熔断兜底方法");
            }
        };
    }
}
  1. 测试

http://192.168.206.1:10040/pay/getUser/1
getUser服务有10020和10021两个端口
当轮询到10021时,关闭10021服务
{
    "id": 1,
    "name": "熔断",
    "age": 18,
    "info": "fegin的熔断兜底方法"
}

Zuul集成


  1. 导入依赖

<!--    zull-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
  1. 启动类添加注解@EnableZuulProxy

@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class ZuulApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication.class);
    }
}
  1. 自定义过滤器

@Component
public class LoginZuulFilter extends ZuulFilter {
    @Override
    public String filterType() {
//        return FilterConstants.PRE_TYPE;
        return "pre";
    }
    /**
     * 过滤器的执行顺序
     * 数值越小越先执行
     * @return
     */
    @Override
    public int filterOrder() {
        return 0;
    }
    /**
     * 判断当前请求是否需要过滤
     * @return true 会执行run
     */
    @Override
    public boolean shouldFilter() {
        //获取请求路径
        RequestContext context=RequestContext.getCurrentContext();
        String uri = context.getRequest().getRequestURI();
        System.out.println(uri);
        //登录页面不拦截
        if (uri.contains("login")) {
            return false;
        }
        return  true;
    }
    /**
     * 核心过滤方法
     * @return
     * @throws ZuulException
     */
    @Override
    public Object run() throws ZuulException {
//        判断用户的权限
//        获取请求头里面的token
        RequestContext context = RequestContext.getCurrentContext();
        String token = context.getRequest().getHeader("token");
//        有则放行
        if (StringUtils.isEmpty(token)){
            HttpServletResponse response = context.getResponse();
            response.setContentType("application/json;charset=utf-8");
            PrintWriter writer=null;
            try {
                writer= response.getWriter();

                Map map=new HashMap();
                map.put("res","请求失败");
                map.put("code",405);
                map.put("msg","缺少权限哦");

                //JSON转字符串
                writer.write(JSON.toJSONString(map));
            } catch (IOException e) {
                throw new RuntimeException(e);
            }finally {
                writer.close();
            }
//            不在执行其他过滤器
            context.setSendZuulResponse(false);
        }
        return null;
    }
}
  1. yml配合

server:
  port: 10050

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:10010/eureka/

  instance:
    instance-id: zuul-server:10050 # 实例id
    prefer-ip-address: true  #开启ip支持
spring:
  application:
    name: zull-server  #配置服务名称
#配置某个服务的负载均衡算法
#ribbon:

logging:
  level:
    cn.itsource.springboot.feignclient.UserFeignClient: debug

#    开启fegin的熔断
feign:
  hystrix:
    enabled: true
zuul:
  routes:
    pay-server-10040: "/p/**"   #指定pay-server这个服务使用 /pay路径来访问  - 别名
    order-server-10030: "/o/**"   #指定order-server这个服务使用 /order路径来访问
  prefix: "/apis" #统一访问前缀
  ignoredServices: "*"  #禁用掉使用浏览器通过服务名的方式访问服务

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值