參考:http://blog.didispace.com/springcloud1/
創建一個基礎的Spring Boot工程,每個項目都需加上SpringCloud的依賴
使用的是Brixton版本
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Brixton.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
一.服務註冊中心
a)加入依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
b)在主程序中加入註解@EnableEurekaServer
啓動一個服務註冊中心
c)默認情況下,註冊中心會將自己作爲客戶端需要禁用,配置application.properties
server.port=1111
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.serviceUrl.defaultZone=http://localhost:${server.port}/eureka/
二.服務提供方
a)加入依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
b)實現處理接口,通過DiscoveryClient獲取信息
@RestController
public class ComputeController {
private final Logger logger = Logger.getLogger(getClass());
@Autowired
private DiscoveryClient client;
@RequestMapping(value = "/add" ,method = RequestMethod.GET)
public Integer add(@RequestParam Integer a, @RequestParam Integer b) {
ServiceInstance instance = client.getLocalServiceInstance();
Integer r = a + b;
logger.info("/add, host:" + instance.getHost() + ", service_id:" + instance.getServiceId() + ", result:" + r);
return r;
}
}
c)在主類中加入@EnableDiscoveryClient註解
激活Eureka中的DiscoveryClient實現
d)配置application.properties
#微服務的名稱
spring.application.name=compute-service
server.port=2222
#指定服務註冊中心得位置
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
三.服務消費者
a)Ribbon
1)加入依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
2)在應用主類中加入@EnableDiscoveryClient註解
添加發現服務的能力,創建RestTemplate實例,添加@LoadBalanced註解開啓均衡負載能力
@SpringBootApplication
@EnableDiscoveryClient
public class RibbonApplication {
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(RibbonApplication.class, args);
}
}
3)創建ConsumerController來消費,直接通過RestTemplate來調用服務
@RestController
public class ConsumerController {
@Autowired
RestTemplate restTemplate;
@RequestMapping(value = "/add", method = RequestMethod.GET)
public String add() {
return restTemplate.getForEntity("http://COMPUTE-SERVICE/add?a=10&b=20", String.class).getBody();
}
}
4)配置application.properties
spring.application.name=ribbon-consumer
server.port=3333
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
b)Feign
1)加入依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
2)在應用主類加入@EnableFeignClients註解
開啓Fegin功能
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class FeignApplication {
public static void main(String[] args) {
SpringApplication.run(FeignApplication.class, args);
}
}
3)定義想要調用的服務的接口
//通過FeignClient("compute-service")綁定接口對應的service服務
@FeignClient("compute-service")
public interface ComputeClient {
//是這裏的value在起作用,它映射到服務提供方的方法
@RequestMapping(method = RequestMethod.GET, value = "/add")
Integer add(@RequestParam(value = "a") Integer a, @RequestParam(value = "b") Integer b);
}
4)在web層調用接口
@RestController
public class ConsumerController {
@Autowired
ComputeClient computeClient;
@RequestMapping(value = "/add", method = RequestMethod.GET)
public Integer add() {
return computeClient.add(10, 20);
}
}
5)配置application.properties
spring.application.name=feign-consumer
server.port=3333
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
四.斷路器
a)Ribbon引入Hystrix
1)添加依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
2)在主類中加入@EnableCircuitBreaker註解
開啓斷路器功能
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public class RibbonApplication {
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(RibbonApplication.class, args);
}
}
3)改造原來的服務消費方式,新增ComputeService類,在使用的函數上增加@HystrixCommand註解指定回調方法
@Service
public class ComputeService {
@Autowired
RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "addServiceFallback")
public String addService() {
return restTemplate.getForEntity("http://COMPUTE-SERVICE/add?a=10&b=20", String.class).getBody();
}
public String addServiceFallback() {
return "error";
}
}
4)將提rest接口的Controller改爲調用ComputeService的addService
@RestController
public class ConsumerController {
@Autowired
private ComputeService computeService;
@RequestMapping(value = "/add", method = RequestMethod.GET)
public String add() {
return computeService.addService();
}
}
b)Feign使用Hystrix
1)使用@FeignClient註解中的fallback屬性指定回調類
@FeignClient(value = "compute-service", fallback = ComputeClientHystrix.class)
public interface ComputeClient {
@RequestMapping(method = RequestMethod.GET, value = "/add")
Integer add(@RequestParam(value = "a") Integer a, @RequestParam(value = "b") Integer b);
}
2)創建回調類ComputeClientHystrix,實現含有@FeignClient註解的接口
@Component
public class ComputeClientHystrix implements ComputeClient {
@Override
public Integer add(@RequestParam(value = "a") Integer a, @RequestParam(value = "b") Integer b) {
return -9999;
}
}
五.分佈式配置中心
a)構建Config Server
1)加入依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
2)在應用主類中加入@EnableConfigServer註解
開啓Config Server
@EnableConfigServer
@SpringBootApplication
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(true).run(args);
}
}
3)配置application.properties,添加服務和git信息
spring.application.name=config-server
server.port=7001
# git管理配置
#git倉庫的位置
spring.cloud.config.server.git.uri=http://git.oschina.net/didispace/SpringBoot-Learning/
#配置倉庫路徑下的相對搜索路徑,可配置多個
spring.cloud.config.server.git.searchPaths=Chapter9-1-4/config-repo
#訪問git倉庫的用戶名
spring.cloud.config.server.git.username=username
#訪問git倉庫的用戶密碼
spring.cloud.config.server.git.password=password
b)微服務端映射配置
1)加入依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
2)創建bootstrap.properties配置,指定config server
#{application}-{profile}.properties對應的配置文件
spring.application.name=didispace
spring.cloud.config.profile=dev
#對應當前配置的git分支
spring.cloud.config.label=master
#配置中心的地址
spring.cloud.config.uri=http://localhost:7001/
server.port=7002
3)創建一個Rest Api來返回配置中心的from屬性
@RefreshScope
@RestController
class TestController {
//通過@Value("${from}")綁定配置服務中配置的from屬性
@Value("${from}")
private String from;
@RequestMapping("/from")
public String from() {
return this.from;
}
}
六.分佈式配置中心(高可用)
a)config-server配置
1)新增依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
2)配置application.properties
spring.application.name=config-server
server.port=7001
# 配置服務註冊中心
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
# git倉庫配置
spring.cloud.config.server.git.uri=http://git.oschina.net/didispace/SpringCloud-Learning/
spring.cloud.config.server.git.searchPaths=Chapter1-1-8/config-repo
spring.cloud.config.server.git.username=username
spring.cloud.config.server.git.password=password
3)新增@EnableDiscoveryClient註解,將config-server註冊到服務註冊中心
@EnableDiscoveryClient
@EnableConfigServer
@SpringBootApplication
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(true).run(args);
}
}
b)config-client配置
1)新增依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
2)配置bootstrap.properties
spring.application.name=didispace
server.port=7002
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
#開啓通過服務訪問Config Server的功能
spring.cloud.config.discovery.enabled=true
#指定Config Server註冊的服務名
spring.cloud.config.discovery.serviceId=config-server
spring.cloud.config.profile=dev
3)在應用主類新增@EnableDiscoveryClient註解
用來發現config-server服務
c)配置刷新
1)新增依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
七.服務網關
a)使用Zuul
1)添加依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
2)在應用主類加入@EnableZuulProxy註解
開啓Zuul
@EnableZuulProxy
//整合了@SpringBootApplication、@EnableDiscoveryClient、@EnableCircuitBreaker
@SpringCloudApplication
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(true).run(args);
}
}
3)配置application.properties
spring.application.name=api-gateway
server.port=5555
c)服務路由
1)通過url直接映射(不太友好)
# routes to url
zuul.routes.api-a-url.path=/api-a-url/**
zuul.routes.api-a-url.url=http://localhost:2222/
2)通過serviceId
zuul.routes.api-a.path=/api-a/**
zuul.routes.api-a.serviceId=service-A
zuul.routes.api-b.path=/api-b/**
zuul.routes.api-b.serviceId=service-B
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
d)服務過濾
1)創建Zuul過濾器
public class AccessFilter extends ZuulFilter {
private static Logger log = LoggerFactory.getLogger(AccessFilter.class);
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
log.info(String.format("%s request to %s", request.getMethod(), request.getRequestURL().toString()));
Object accessToken = request.getParameter("accessToken");
if(accessToken == null) {
log.warn("access token is empty");
//令zuul過濾該請求,不對其進行路由
ctx.setSendZuulResponse(false);
//設置了其返回的錯誤碼
ctx.setResponseStatusCode(401);
return null;
}
log.info("access token ok");
return null;
}
}
2)實例化自定義過濾器
@EnableZuulProxy
@SpringCloudApplication
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(true).run(args);
}
@Bean
public AccessFilter accessFilter() {
return new AccessFilter();
}
}
八.高可用服務註冊中心
a)創建application-peer1.properties,作爲peer1服務中心的配置,並將serviceUrl指向peer2
spring.application.name=eureka-server
server.port=1111
eureka.instance.hostname=peer1
eureka.client.serviceUrl.defaultZone=http://peer2:1112/eureka/
b)創建application-peer2.properties,作爲peer2服務中心的配置,並將serviceUrl指向peer1
spring.application.name=eureka-server
server.port=1112
eureka.instance.hostname=peer2
eureka.client.serviceUrl.defaultZone=http://peer1:1111/eureka/
c)對hosts文件進行轉換
127.0.0.1 peer1
127.0.0.1 peer2
d)將項目打包(mvn install),通過spring.profiles.active屬性啓動peer1和peer2
java -jar eureka-server-1.0.0.jar --spring.profiles.active=peer1
java -jar eureka-server-1.0.0.jar --spring.profiles.active=peer2
e)服務註冊與發現
修改application.properties
spring.application.name=compute-service
server.port=2222
#將服務指向了peer1和peer2
eureka.client.serviceUrl.defaultZone=http://peer1:1111/eureka/,http://peer2:1112/eureka/
九.消息總線
a)RabbitMQ
1)擴展config-client-eureka,加入依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
2)在配置文件中增加關於RabbitMQ的連接和用戶信息
需要先安裝RabbitMQ,然後創建一個用戶,爲用戶添加角色和權限
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=springcloud
spring.rabbitmq.password=123456
3)指定刷新範圍
/bus/refresh接口還提供了destination參數,用來定位具體要刷新的應用程序。比如,我們可以請求/bus/refresh?destination=customers:9000,destination參數除了可以定位具體的實例之外,還可以用來定位具體的服務。定位服務的原理是通過使用Spring的PathMatecher(路徑匹配)來實現,比如:/bus/refresh?destination=customers:**,該請求會觸發customers服務的所有實例進行刷新。
4)架構優化
在之前的架構中,服務的配置更新需要通過向具體服務中的某個實例發送請求,再觸發對整個服務集羣的配置更新。
1.在Config Server中也引入Spring Cloud Bus,將配置服務端也加入到消息總線中來。
2./bus/refresh請求不在發送到具體服務實例上,而是發送給Config Server,並通過destination參數來指定需要更新配置的服務或實例。
b)Kafka
1)整合Spring Cloud Bus,替換依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-kafka</artifactId>
</dependency>
2)Kafka的配置
屬性名 說明 默認值
spring.cloud.stream.kafka.binder.brokers Kafka的服務端列表 localhost
spring.cloud.stream.kafka.binder.defaultBrokerPort Kafka服務端的默認端口,當brokers屬性中沒有配置端口信息時,就會使用這個默認端口 9092
spring.cloud.stream.kafka.binder.zkNodes Kafka服務端連接的ZooKeeper節點列表 localhost
spring.cloud.stream.kafka.binder.defaultZkPort ZooKeeper節點的默認端口,當zkNodes屬性中沒有配置端口信息時,就會使用這個默認端口