springcloud学习1

一、搭建服务注册中心
1、搭建服务注册中心
当服务实例启动的时候,它会按照名称将自己注册到Eureka中。服务的名称为“some-service”。“some-service”可能会有多个完全等价的实例,但是在Eureka注册时,它们的名称是相同的。
在这里插入图片描述

在某个时间点,另一个服务(other-service)需要使用“some-service”的端点。“other-service”没有使用特定的主机和端口信息对“some-service”进行硬编码,而是根据名字从Eureka查找“some-service”。Eureka的回应中将会包含它所知道的“some-service”的所有实例。
现在other-service服务需要做决定。 它将使用some-service哪个实例? 如果它们都是等价的,那么这并不重要。 但是为了避免每次选择任何同一个实例,最好用一些客户端负载平衡算法来分散请求。 这就是另一个Netflix项目——Ribbon

虽然other-service完全可以自行查找和选择“some-service”的实例,但在这里使用依赖Ribbon。
2)使用客户端负载均衡器
引入依赖:带有Eureka Server标签的复选框

<dependency>
	 <groupId>org.springframework.cloud</groupId>
	 <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<properties>
 <!-- -->
 ...
 <spring-cloud.version>Finchley.SR1</spring-cloud.version>
</properties>

<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>

启用Eureka服务器,在应用的主引导类添加@EnableEurekaServer,如:

@EnableEurekaServer
@SpringBootApplication
public class LearndemoApplication {

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

}

此时启动应用,Eureka服务注册中心就会运行起来并监听8080.
在http://localhost:8080,,就可以看到web页面。但此时,在eureka日志中,每隔大约30秒就会打印一些异常。
需要配置Eureka。
2、配置Eureka

Eureka默认行为是与其他Eureka服务器建立关联。
可以通过配置,使其当前的接受一个的状态。

eureka:
    instance:
        hostname: localhost		# (可选属性)如果不指定,Eureka会尝试通过环境变量确定它的主机。
        						# 如果指定了,会告诉Eureka它正运行在哪个主机(host)上。
    client:
        fetch-registry: false	     # 默认值是true
        register-with-eureka: false	# 默认值是true,
        							# true表明从其他的Eureka实例获取注册信息,并应该将自身注册为其他Eureka服务器中的服务
        service-url:
            defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka

1)指定Eureka的服务器端口

server:
    port: 8761

application.yml:

server:
    port: 8761	# Eureka默认监听的端口

eureka:
    instance:
        hostname: localhost
    client:
        fetch-registry: false
        register-with-eureka: false
        service-url:
            defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka

2)禁用自我保护模式
在开发环境可以禁用自我保护模式,但是在投入生产环境时需要将其启用。

server:
        enable-self-preservation: false

application.yml:

server:
    port: 8761

eureka:
    instance:
        hostname: localhost
    client:
        fetch-registry: false
        register-with-eureka: false
        service-url:
            defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka
    
    server:
        enable-self-preservation: false			# Eureka希望服务实例能够注册上来,并且每隔30秒向它发送一次注册更新的请求,
										        # 如果Eureka在3个更新周期(90秒)内没有收到服务的更新请求,就会将改服务注销。	
        										# Eureka假设出现了网络问题,今日自我保护模式,所以不会注销服务实例。

3、扩展Eureka
在开发环境中,每个Eureka实例会更加便利;但在将应用投入生产环境时,我们可能至少需要两个Eureka实例,以实现高可用性。
1)生产环境可用的Spring Cloud Services
配置2个或以上Eureka实例最简单直接的方式是在application.yml中使用Spring profile,然后针对两个profile各启动一次。
或者在application.propreties定义。
①application.yml方式:
application.yml:

eureka:
  client:
    service-url:
      defaultZone: http://${other.eureka.host}:${other.eureka.port}/eureka
#   是否将自己注册到Eureka Server上,默认为true
#   register-with-eureka: false
    #是否从Eureka Server上获取注册信息,默认为true
#    fetch-registry: false
---
spring:
  profiles: eureka-1
  application:
    name: eureka-server

server:
  port: 8761

eureka:
  instance:
    hostname: eureka1.learneurekademo.com

other:
  eureka:
    host: eureka2.learneurekademo.com
    port: 8762

---
spring:
  profiles: eureka-2
  application:
    name: eureka-server

server:
  port: 8762

eureka:
  instance:
    hostname: eureka2.learneurekademo.com

other:
  eureka:
    host: eureka1.learneurekademo.com
    port: 8761

注:上面面这个配置,先启动的会报错,后启动不会。
在命令行执行:

java -jar demoeureka-0.0.1-SNAPSHOT.jar --spring.profiles.active=eureka-1
java -jar demoeureka-0.0.1-SNAPSHOT.jar --spring.profiles.active=eureka-2

访问:

http://eureka1.learneurekademo.com:8761/
http://eureka2.learneurekademo.com:8762/

②application.properties
新建application-eureka1.properties文件,新建application-eureka2.properties 文件。
配置项与application.yml中一样,以properties语法格式写即可。
然后打包jar,分别在终端执行:

java -jar demoeureka-0.0.1-SNAPSHOT.jar --spring.profiles.active=eureka-1
java -jar demoeureka-0.0.1-SNAPSHOT.jar --spring.profiles.active=eureka-2

二、注册和发现服务
1、配置Eureka客户端属性
1)引入依赖:

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

springcloud版本属性:

 <properties>     
       <spring-cloud.version>Finchley.SR1</spring-cloud.version>
 </properties>

2)配置Eureka属性

server:
 port: 0

将端口设置为0将导致应用程序在随机选择的可用端口上启动。

eureka:
  client:
    service-url:
      defaultZone: http://eureka1.learneurekademo.com:8761/eureka/

最好使用两个或以上的Eureka实例,如:

eureka:
  client:
    service-url:
      defaultZone: http://eureka1.learneurekademo.com:8761/eureka/
			  http://eureka2.learneurekademo.com:8762/eureka/

当服务启动的时候,会尝试使用zone中的第一个服务器进行注册,如果因为某种原因失败,会使用列表中的下一个服务器来进行注册。最终,如果出现故障的服务器重新恢复在线状态,它将会从对等的端上复制注册信息,这样就能将该服务的注册条目包含进来。
2、消费服务
有两种方式可以消费从Eureka中查找到的服务:

支持负载均衡的RestTemplate;
Feign生成的客户端接口。

1)使用RestTemplate消费服务

public Ingredient getIngredientById(String ingredientId) {
 	return rest.getForObject("http://localhost:8080/ingredients/{id}", Ingredient.class, ingredientId);
}

上面getForObject()的URL硬编码了特定的主机和端口。就算把这个提取到一个属性,如果配置的URL始终指向同一个特定实例,这样就没有负载均衡器请求分散到多个服务实例中了。

可以将应用变成Eureka客户端,就可以声明支持负载均衡的RestTemplate bean了。
①声明一个常规的RestTemplate bean;
②并为带有@Bean注解的方法在添上@LoadBalanced
如:

@Bean
@LoadBalanced
public RestTemplate restTemplate() {
 	return new RestTemplate();
}

@LoadBalanced注解,会告诉SpringCloud这个RestTemplate要能够通过Ribbon来查找服务。其次,会作为一个注入限定符,所有有两个或以上RestTemplate bean的话,可以在注入的地方声明此处想要支持负载均衡的RestTemplate。
如:

@Component
public class IngredientServiceClient {

	 private RestTemplate rest;
	 
	 public IngredientServiceClient(@LoadBalanced RestTemplate rest) {
	 this.rest = rest;
	 }
	// ...
}

修改上面的getIngredientById()方法,使用注册服务的注册名,而不再明确使用主机和端口:

public Ingredient getIngredientById(String ingredientId) {
	 return rest.getForObject(
		 "http://ingredient-service/ingredients/{id}",
		 Ingredient.class, ingredientId);
}

这里使用了服务名ingredient-service,RestTemplate会让Ribbon根据名称查找服务并从中选择一个实例。

2)使用WebClient消费服务
与RestTemplate类似的方式将WebClient作为支持负载均衡的客户端。
声明返回一个WebClient.Builder bean 的方法,方法要添加@LoadBalanced注解。

@Bean
@LoadBalanced
public WebClient.Builder webClientBuilder() {
 	return WebClient.builder();
}

声明完之后,可以将WebClient.Builder 注入到任何需要它的地方。
如:

@Component
public class IngredientServiceClient {
	 private WebClient.Builder wcBuilder;
	 
	 public IngredientServiceClient(@LoadBalanced WebClient.Builder webclientBuilder wcBuilder) {
		 this.wcBuilder = wcBuilder;
	 }
	// ...
}

最后在需要使用它的时候,可以利用WebClient.Builde 构建一个WebClient,然后就能够使用Eureka注册的服务名来发送请求了。如:

public Mono<Ingredient> getIngredientById(String ingredientId) {
	 return wcBuilder.build()
		 .get()
		 .uri("http://ingredient-service/ingredients/{id}", ingredientId)
		 .retrieve().bodyToMono(Ingredient.class);
}

3)定义Feign客户端接口
Feign是一个REST客户端库,使用一种特殊的、接口驱动的方式来定义REST客户端。
①引入依赖:

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

②将@EnableFeignClients添加到某个配置类上:

@Configuration
@EnableFeignClients
public RestClientConfiguration {
}

如,想通过注册在Eureka中名为ingredient-service的服务获取一个Ingredient,需要做的是定义以下接口:

package demo.ingredientclient.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import tacos.ingredientclient.Ingredient;

@FeignClient("ingredient-service")
public interface IngredientClient {

	 @GetMapping("/ingredients/{id}")
	 Ingredient getIngredient(@PathVariable("id") String id);
}

在运行期,当Feign发现它的时候,Feign会创建一个实现类并将其暴露为Spring应用上下文中的bean。
接口上的@FeignClient注解会制定该接口上的所有方法都会对名为ingredient-service的服务发送请求。在内部,服务将会通过Ribbon进行查找,这与支持负载均衡的RestTemplate运行方式是一样的。
getIngredient()方法的@GetMapping注解来自SpringMVC。@PathVariable也是来自SpringMVC。
接下来,就是讲Feign实现的接口注入需要的地方,并使用它。如:

@Controller
@RequestMapping("/ingredients")
public class IngredientController {
	private IngredientClient client;
	
	@Autowired
	public IngredientController(IngredientClient client) {
		this.client = client;
	}
	
	@GetMapping("/{id}")
	public String ingredientDetailPage(@PathVariable("id") String id, Model model) {
		model.addAttribute("ingredient", client.getIngredient(id));
		return "ingredientDetail";
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值