SpringCloud 微服务搭建和使用 二


在这里插入图片描述

  客户模块间通过 RestTemplate 调用。customer 调用 search。

  customer 在 application 里添加 bean。


// CustomerApplication.java

	@Bean
    public RestTemplate getTemplate() {
        return new RestTemplate();
    }

  controller 里调用。


// CustomerController.java

@RestController
@RequestMapping("/customer")
public class CustomerController {

    @Autowired
    private EurekaClient eurekaClient;

    @Autowired
    private RestTemplate restTemplate;
    
    @RequestMapping("/customer")
    public String customer() {

        InstanceInfo info = eurekaClient.getNextServerFromEureka("SEARCH", false);

        String url = info.getHomePageUrl();
        System.out.println(url);

        String result = restTemplate.getForObject(url + "/search/search", String.class);
        
        // 或者
		// String result = restTemplate.getForObject("http://SEARCH/search/search", String.class);
		
        return result;
    }
 
}

  客户模块间通过 Feign 调用。

  customer 添加依赖。


// pom.xml

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

  application 添加注解。


// CustomerApplication.java 

@EnableFeignClients

  创建调用 search模块的接口类。


// SearchClient.java

@FeignClient("SEARCH")   // 指定服务名称
public interface SearchClient {

    // value,目标服务的请求路径
    @RequestMapping(value = "/search",method = RequestMethod.GET)
    String search();

}

  controller 里掉用。


// CustomerApplication.java

@Autowired
private SearchClient searchClient;

@RequestMapping("/customer")
public String customer(){
    String result = searchClient.search();
    return result;
}

  EurekaServer 的安全性。加入登录验证。


// pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>


// WebSecurityConfig.java
// 绕过 csrf 令牌,对 eureka 的请求路径放行

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().ignoringAntMatchers("/eureka/**");
        super.configure(http);
    }

}


// applicaion.yml
// 访问 http://localhost:8761/ 的账户密码为 root

spring:
  security:
    user:
      name: root
      password: root

// 其他服务注册注册到 server 需要修改为
eureka:
  client:
    service-url:
      defaultZone: http://用户名:密码@localhost:8761/eureka

  启动多 EurekaServer ,并配置相互注册,这样当一个服务挂掉后,另外多服务仍可运行。

  新建 EUREKA2。


// pom.xml

<dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
    </dependencies>

// application.xml
// 同时第一个 EurekaServer 的port: 8761;name: EUREKA1;defaultZone: http://root:root@localhost:8762/eureka/  

server:
  port: 8762

eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: true # 注册到 eureka 上
    fetchRegistry: true      # 从 eureka 拉取信息
    serviceUrl:
      defaultZone: http://root:root@localhost:8761/eureka/

spring:
  security:
    user:
      name: root
      password: root
  application:
    name: EUREKA2


  其他模块注册多服务的方式。


eureka:
  client:
    service-url:
      defaultZone: http://root:root@localhost:8761/eureka,http://root:root@localhost:8762/eureka

  Ribbon 负载均衡。
  RandomRule,随机策略。
  RoundRobbinRule,轮询策略。
WeightedResponseTimeRule,默认会采用轮询的策略,后续会根据服务的响应时间,自动分配权重。
  BestAvailableRule,根据被调用方并发数最小的去分配。

  启动两个 search 模块。
在这里插入图片描述

  search 模块修改代码。


// application.yml

# 把当前服务注册到 eureka 端
eureka:
  client:
    serviceUrl:
      defaultZone: http://root:root@localhost:8761/eureka/,http://root:root@localhost:8762/eureka/

spring:
  application:
    name: SEARCH
server:
  port: 8081


// SearchController.java

@RestController
@RequestMapping("/search")
public class SearchController {

    @Value("${server.port}")
    private int port;

    @RequestMapping("/search")
    public String search() {
        return "SEARCH: " + port;
    }

}


  customer模块 配置负载均衡三种方式。


// 1. application.java

	@Bean
    @LoadBalanced // 负载均衡 默认轮询
    public RestTemplate getTemplate() {
        return new RestTemplate();
    }

// 2. application.java
@Bean
public IRule robbinRule(){
    return new RandomRule();
}

// 3. application.yml
#指定调用SEARCH服务使用的随机的负载均衡策略
SEARCH:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

// 测试
http://localhost/customer/customer/

  Stream,服务间消息传递。
  Stream 就是在消息队列的基础上,对其进行封装,让咱们更方便的去操作 MQ 消息队列。

  customer 作生产者,search 作消费者在不同模块间收发消息。
  代码结构。
在这里插入图片描述


// search 模块

// pom.xml 新增
		<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
        </dependency>

// application.yml

# 把当前服务注册到 eureka 端
eureka:
  client:
    serviceUrl:
      defaultZone: http://root:root@localhost:8761/eureka/,http://root:root@localhost:8762/eureka/

spring:
  application:
    name: SEARCH
  rabbitmq:
    host: 10.36.144.157
    port: 5672
    username: test
    password: test
    virtual-host: /virtual2
  cloud:
    stream:
      bindings:
        exchange: # rabbitmq 交换机
          group: customer # 消费者组
      rabbit:
          bindings:
            exchange:
              consumer:
                acknowledgeMode: MANUAL # 手动 ack

server:
  port: 8081


// StreamClient.java 监听交换机

public interface StreamClient {
    @Input("exchange")
    SubscribableChannel input();
}

// StreamReceiver.java 监听消息

@Component
@EnableBinding(StreamClient.class)
public class StreamReceiver {

    @StreamListener("exchange")
    public void msg(Object msg,
                    @Header(name = AmqpHeaders.CHANNEL) Channel channel,
                    @Header(name = AmqpHeaders.DELIVERY_TAG) Long deliveryTag) throws IOException {
        System.out.println("接收到消息: " + msg);
        channel.basicAck(deliveryTag, false);
    }

}


// customer 模块

// pom.xml 新增
		<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
        </dependency>

// application.yml

version: v1

# 把当前服务注册到 eureka 端
eureka:
  client:
    serviceUrl:
      defaultZone: http://root:root@localhost:8761/eureka/,http://root:root@localhost:8762/eureka/
      
spring:
  application:
    name: CUSTOMER-${version}
  rabbitmq:
    host: 10.36.144.157
    port: 5672
    username: test
    password: test
    virtual-host: /virtual2

#指定调用SEARCH服务使用的随机的负载均衡策略
SEARCH:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule


// StreamClient.java 创建交换机绑定的接口

public interface StreamClient {

    @Output("exchange")
    MessageChannel outut();

}

// CustomerApplication.java 绑定交换机

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@EnableBinding(StreamClient.class)
public class CustomerApplication {

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

    @Bean
    @LoadBalanced // 负载均衡 默认轮询
    public RestTemplate getTemplate() {
        return new RestTemplate();
    }


//    @Bean  // 负载均衡配置 随机
//    public IRule robbinRule(){
//        return new RandomRule();
//    }

}

// CustomerController.java  
// http://localhost:8080/customer/rabbitmqSend 发送消息

@RestController
@RequestMapping("/customer")
public class CustomerController {

    @Autowired
    private EurekaClient eurekaClient;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private StreamClient streamClient;

    @Value("${version}")
    private String version;

    @RequestMapping("/customer")
    public String customer() {

//        InstanceInfo info = eurekaClient.getNextServerFromEureka("SEARCH", false);
//
//        String url = info.getHomePageUrl();
//        System.out.println(url);
//
//        String result = restTemplate.getForObject(url + "/search/search", String.class);

        String result = restTemplate.getForObject("http://SEARCH/search/search", String.class);

        return result;
    }

    @RequestMapping("/version")
    public String version() {
        return version;
    }

    @RequestMapping("/rabbitmqSend")
    public String rabbitmqSend() {
        streamClient.outut().send(MessageBuilder.withPayload("hello,rabbit!").build());
        return "发送消息成功";
    }

}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值