客户模块间通过 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 "发送消息成功";
}
}