個人博客請訪問 http://www.x0100.top
首先還是需要去們的Spring Cloud服務管理框架Eureka簡單示例(三)這篇博客底部拿到源碼,這是一個最微型的集羣。爲了符合後面的測試,先把eureka-provider項目com.init.springCloud包下的ProviderApp類修改成按照端口啓動:
package com.init.springCloud;
import java.util.Scanner;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class ProviderApp {
public static void main(String[] args) {
@SuppressWarnings("resource")
Scanner scan = new Scanner(System.in);
String port = scan.nextLine();
new SpringApplicationBuilder(ProviderApp.class).properties("server.port=" + port).run(args);
}
}
接着爲ProviderController控制器添加一個方法,用於返回簡單的JSON字符串:
@RequestMapping(value = "/hello/{name}", method = RequestMethod.GET)
public String sayHello(@PathVariable String name){
return "hello "+name+", I'm glad to see you.";
}
然後修改eureka-consumer項目的application.yml配置文件,將啓動端口號修改爲9090:
server:
port: 9090
之後依次運行三個項目的**App類裏面的main方法,啓動三個項目。注意,eureka-provider項目需要在控制檯輸入端口號之後回車。之後訪問:http://localhost:8761,http://localhost:8080/search/1,http://localhost:9090/router,看看是否都能正常調用。
引入Spring Cloud中的Feign
因爲feign是用於服務調用端,做服務調用的,我們在eureka-consumer項目中引入它的依賴:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
然後開啓feign,讓eureka-consumer能夠使用到feign提供的能力。找到ConsumerApp啓動類,增加@EnableFeignClients的註解:
package com.init.springCloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class ConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class, args);
}
}
然後,我們需要定義一個接口PersonClient,用做Feign處理請求調用:
package com.init.springCloud;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@FeignClient("eureka-provider")
public interface PersonClient {
@RequestMapping(method = RequestMethod.GET, value = "/hello/{name}")
String sayHello(@PathVariable("name") String name);
}
在接口上,我們使用了@FeignClient註解,表明需要請求的服務提供者的服務ID(ServiceId),然後在抽象方法上面用Spring提供的註解@RequestMapping,註明請求的方式和路徑,參數也用Spring註解@PathVariable修飾(注意需要把參數名稱填進去),Feign內部有專門的SpringMvcContract註解解釋器(這個註解解釋器可以查看OpenFeign之feign使用簡介(十一))來理解Spring的@RequestMapping註解,所以在這裏使用Spring的註解來替代feign提供的@RequestLine,讓我們迴歸到了熟悉的配置上,簡化了開發難度。
接下來就是重新編寫ConsumerController控制器,注入我們剛剛編寫的PersonClient接口:
package com.init.springCloud;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ConsumerController {
@Autowired PersonClient PersonClient;
@RequestMapping(method = RequestMethod.GET, value = "/router/{name}",
produces = MediaType.APPLICATION_JSON_VALUE)
public String router(@PathVariable String name){
return PersonClient.sayHello(name);
}
}
重新啓動eureka-consumer項目,訪問:http://localhost:9090/router/spirit,瀏覽器能正常返回我們的字符串,就說明我們編寫的Feign客戶端運行正常
Feign的負載均衡效果
基於Ribbon,Feign也擁有負載均衡的效果(不用再引入Ribbon依賴)。
修改eureka-provider的Person實體類,新增一個屬性,用端口來確認訪問的哪一個服務:
package com.init.springCloud;
import lombok.Data;
@Data
public class Person {
private Integer id; //主鍵ID
private String name; //姓名
private String info; //url路徑信息
}
然後修改ProviderController控制器,通過請求獲取這個url信息:
@RequestMapping(value = "/search/{id}", method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public Person searchPerson(@PathVariable Integer id, HttpServletRequest request){
Person person = new Person();
person.setId(id);
person.setName("Spirit");
person.setInfo(request.getRequestURL().toString());
return person;
}
啓動兩個eureka-provider項目,端口分別是8080和8081。
然後拷貝eureka-provider項目的Person實體到eureka-consumer中(lombok需要引入相關依賴,也可以改寫成自己生成getter、setter方法),在PersonClient接口中新增方法,用於返回這個實體:
@RequestMapping(method = RequestMethod.GET, value = "/search/{id}")
Person getPersonById(@PathVariable("id") Integer id);
然後在ConsumerController項目中新增方法,返回Person實體類的JSON字符串:
@RequestMapping(method = RequestMethod.GET, value = "/find/{id}",
produces = MediaType.APPLICATION_JSON_VALUE)
public Person getPersonById(@PathVariable Integer id){
return PersonClient.getPersonById(id);
}
重啓eureka-consumer項目,瀏覽器多次訪問:http://localhost:9090/find/1,我們可以看到Feign實現了負載均衡的效果:
Feign提供的Bean組件
Spring Cloud Netflix在默認情況下提供了以下bean(Bean類型 Bean名稱:類名):
- Decoder feignDecoder: ResponseEntityDecoder (which wraps a SpringDecoder)
- Encoder feignEncoder: SpringEncoder
- Logger feignLogger: Slf4jLogger
- Contract feignContract: SpringMvcContract
- Feign.Builder feignBuilder: HystrixFeign.Builder
- Client feignClient: if Ribbon is enabled it is a LoadBalancerFeignClient, otherwise the default feign client is used.
我們可以通過設置feign.okhttp.enabled或者feign.httpclient.enabled屬性爲true來分別啓用OkHttpClient和ApacheHttpClient的Feign客戶端,然後分別在類路徑中使用它們。
Spring Cloud Netflix在默認情況下不提供以下bean,但仍然從應用程序上下文中查找這些類型的bean,以創建feign客戶端:
- Logger.Level
- Retryer
- ErrorDecoder
- Request.Options
- Collection<RequestInterceptor>
- SetterFactory