diff --git a/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Client/pom.xml b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Client/pom.xml new file mode 100644 index 00000000..8149f25d --- /dev/null +++ b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Client/pom.xml @@ -0,0 +1,60 @@ + + + 4.0.0 + + com.example + Eureka-Client + 0.0.1-SNAPSHOT + jar + + Eureka-Client + Demo project for Spring Boot + + + org.springframework.boot + spring-boot-starter-parent + 1.5.13.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + + + + + + org.springframework.cloud + spring-cloud-dependencies + Edgware.SR3 + pom + import + + + + + + + org.springframework.cloud + spring-cloud-starter-eureka + + + org.springframework.boot + spring-boot-starter + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + diff --git a/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Client/src/main/java/com/example/demo/DemoApplication.java b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Client/src/main/java/com/example/demo/DemoApplication.java new file mode 100644 index 00000000..5d549d22 --- /dev/null +++ b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Client/src/main/java/com/example/demo/DemoApplication.java @@ -0,0 +1,15 @@ +package com.example.demo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; + +@EnableDiscoveryClient +@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) +public class DemoApplication { + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } +} diff --git a/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Client/src/main/java/com/example/demo/controller/TestController.java b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Client/src/main/java/com/example/demo/controller/TestController.java new file mode 100644 index 00000000..c50fdd4e --- /dev/null +++ b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Client/src/main/java/com/example/demo/controller/TestController.java @@ -0,0 +1,32 @@ +package com.example.demo.controller; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class TestController { + + private Logger log = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private DiscoveryClient client; + + @GetMapping("/info") + public String info() { + @SuppressWarnings("deprecation") + ServiceInstance instance = client.getLocalServiceInstance(); + String info = "host:" + instance.getHost() + ",service_id:" + instance.getServiceId(); + log.info(info); + return info; + } + + @GetMapping("/hello") + public String hello() { + return "hello world"; + } +} diff --git a/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Client/src/main/java/com/example/demo/controller/UserController.java b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Client/src/main/java/com/example/demo/controller/UserController.java new file mode 100644 index 00000000..aaff86d0 --- /dev/null +++ b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Client/src/main/java/com/example/demo/controller/UserController.java @@ -0,0 +1,57 @@ +package com.example.demo.controller; + +import com.example.demo.domain.User; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.List; + +@RestController +@RequestMapping("user") +public class UserController { + + private Logger log = LoggerFactory.getLogger(this.getClass()); + + @GetMapping("/{id:\\d+}") + public User get(@PathVariable Long id) { + log.info("获取用户id为 " + id + "的信息"); + return new User(id, "mrbird", "123456"); + } + + @GetMapping("users") + public List get(String ids) { + log.info("批量获取用户信息"); + List list = new ArrayList<>(); + for (String id : ids.split(",")) { + list.add(new User(Long.valueOf(id), "user" + id, "123456")); + } + return list; + } + + @GetMapping + public List get() { + List list = new ArrayList<>(); + list.add(new User(1L, "mrbird", "123456")); + list.add(new User(2L, "scott", "123456")); + log.info("获取用户信息 " + list); + return list; + } + + @PostMapping + public void add(@RequestBody User user) { + log.info("新增用户成功 " + user); + } + + @PutMapping + public void update(@RequestBody User user) { + log.info("更新用户成功 " + user); + } + + @DeleteMapping("/{id:\\d+}") + public void delete(@PathVariable Long id) { + log.info("删除用户成功 " + id); + } + +} diff --git a/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Client/src/main/java/com/example/demo/domain/User.java b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Client/src/main/java/com/example/demo/domain/User.java new file mode 100644 index 00000000..4ce63e1a --- /dev/null +++ b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Client/src/main/java/com/example/demo/domain/User.java @@ -0,0 +1,55 @@ +package com.example.demo.domain; + +import java.io.Serializable; + +public class User implements Serializable { + + private static final long serialVersionUID = 1339434510787399891L; + private Long id; + + private String username; + + private String password; + + public User() { + } + + public User(Long id, String username, String password) { + this.id = id; + this.username = username; + this.password = password; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + @Override + public String toString() { + return "User{" + + "id=" + id + + ", username='" + username + '\'' + + ", password='" + password + '\'' + + '}'; + } +} diff --git a/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Client/src/main/resources/application.yml b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Client/src/main/resources/application.yml new file mode 100644 index 00000000..8bd92b28 --- /dev/null +++ b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Client/src/main/resources/application.yml @@ -0,0 +1,13 @@ +server: + port: 8082 + +spring: + application: + name: Server-Provider + +eureka: + client: + register-with-eureka: true + fetch-registry: true + serviceUrl: + defaultZone: http://mrbird:123456@peer1:8080/eureka/,http://mrbird:123456@peer2:8081/eureka/ \ No newline at end of file diff --git a/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Service/pom.xml b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Service/pom.xml new file mode 100644 index 00000000..4bdff943 --- /dev/null +++ b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Service/pom.xml @@ -0,0 +1,69 @@ + + + 4.0.0 + + com.example + Eureka-Service + 0.0.1-SNAPSHOT + jar + + Eureka-Service + Demo project for Spring Boot + + + org.springframework.boot + spring-boot-starter-parent + 1.5.13.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + + + + + + org.springframework.cloud + spring-cloud-dependencies + Edgware.SR3 + pom + import + + + + + + + org.springframework.cloud + spring-cloud-starter-eureka-server + + + org.springframework.boot + spring-boot-starter-security + + + + + + + nexus-aliyun + Nexus aliyun + http://maven.aliyun.com/nexus/content/groups/public + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + diff --git a/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Service/src/main/java/com/example/demo/DemoApplication.java b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Service/src/main/java/com/example/demo/DemoApplication.java new file mode 100644 index 00000000..f1a6ef57 --- /dev/null +++ b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Service/src/main/java/com/example/demo/DemoApplication.java @@ -0,0 +1,14 @@ +package com.example.demo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; + + +@EnableEurekaServer +@SpringBootApplication +public class DemoApplication { + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } +} diff --git a/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Service/src/main/resources/application-peer1.yml b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Service/src/main/resources/application-peer1.yml new file mode 100644 index 00000000..22742c97 --- /dev/null +++ b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Service/src/main/resources/application-peer1.yml @@ -0,0 +1,15 @@ +server: + port: 8080 + +spring: + application: + name: Eureka-Server + +eureka: + instance: + hostname: peer1 + client: + serviceUrl: + defaultZone: http://mrbird:123456@peer2:8081/eureka/ + server: + enable-self-preservation: false diff --git a/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Service/src/main/resources/application-peer2.yml b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Service/src/main/resources/application-peer2.yml new file mode 100644 index 00000000..960449bc --- /dev/null +++ b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Service/src/main/resources/application-peer2.yml @@ -0,0 +1,15 @@ +server: + port: 8081 + +spring: + application: + name: Eureka-Server + +eureka: + instance: + hostname: peer2 + client: + serviceUrl: + defaultZone: http://mrbird:123456@peer1:8080/eureka/ + server: + enable-self-preservation: false diff --git a/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Service/src/main/resources/application.yml b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Service/src/main/resources/application.yml new file mode 100644 index 00000000..09c8efe5 --- /dev/null +++ b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Service/src/main/resources/application.yml @@ -0,0 +1,9 @@ +security: + basic: + enabled: true + user: + name: mrbird + password: 123456 +spring: + profiles: + active: peer1 \ No newline at end of file diff --git a/30.Spring-Cloud-Hystrix-Circuit-Breaker/Ribbon-Consumer/pom.xml b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Ribbon-Consumer/pom.xml new file mode 100644 index 00000000..ff24dc96 --- /dev/null +++ b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Ribbon-Consumer/pom.xml @@ -0,0 +1,69 @@ + + + 4.0.0 + + com.example + Ribbon-Consumer + 0.0.1-SNAPSHOT + jar + + Ribbon-Consumer + Demo project for Spring Boot + + + org.springframework.boot + spring-boot-starter-parent + 1.5.13.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + + + + + + org.springframework.cloud + spring-cloud-dependencies + Edgware.SR3 + pom + import + + + + + + org.springframework.cloud + spring-cloud-starter-eureka + + + org.springframework.boot + spring-boot-starter + + + org.springframework.cloud + spring-cloud-starter-ribbon + + + + org.springframework.cloud + spring-cloud-starter-hystrix + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + diff --git a/30.Spring-Cloud-Hystrix-Circuit-Breaker/Ribbon-Consumer/src/main/java/com/example/demo/DemoApplication.java b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Ribbon-Consumer/src/main/java/com/example/demo/DemoApplication.java new file mode 100644 index 00000000..dc80e978 --- /dev/null +++ b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Ribbon-Consumer/src/main/java/com/example/demo/DemoApplication.java @@ -0,0 +1,21 @@ +package com.example.demo; + +import org.springframework.boot.SpringApplication; +import org.springframework.cloud.client.SpringCloudApplication; +import org.springframework.cloud.client.loadbalancer.LoadBalanced; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; + +@SpringCloudApplication +public class DemoApplication { + + @Bean + @LoadBalanced + RestTemplate restTemplate() { + return new RestTemplate(); + } + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } +} diff --git a/30.Spring-Cloud-Hystrix-Circuit-Breaker/Ribbon-Consumer/src/main/java/com/example/demo/Service/UserService.java b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Ribbon-Consumer/src/main/java/com/example/demo/Service/UserService.java new file mode 100644 index 00000000..f31c4c3e --- /dev/null +++ b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Ribbon-Consumer/src/main/java/com/example/demo/Service/UserService.java @@ -0,0 +1,113 @@ +package com.example.demo.Service; + +import com.example.demo.domain.User; +import com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser; +import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; +import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; +import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey; +import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove; +import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult; +import com.netflix.hystrix.contrib.javanica.command.AsyncResult; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.client.RestTemplate; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.Future; + +/** + * @author MrBird + */ +@Service("userService") +public class UserService { + + private Logger log = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private RestTemplate restTemplate; + + @HystrixCollapser(batchMethod = "findUserBatch", collapserProperties = { + @HystrixProperty(name = "timerDelayInMilliseconds", value = "100") + }) + public Future findUser(Long id) { + log.info("获取单个用户信息"); + // return new AsyncResult() { + // @Override + // public User invoke() { + // return restTemplate.getForObject("http://Server-Provider/user/{id}", User.class, id); + // } + // }; + return null; + } + + @HystrixCommand + public List findUserBatch(List ids) { + log.info("批量获取用户信息,ids: " + ids); + User[] users = restTemplate.getForObject("http://Server-Provider/user/users?ids={1}", User[].class, StringUtils.join(ids, ",")); + return Arrays.asList(users); + } + + public String getCacheKey(Long id) { + return String.valueOf(id); + } + + @CacheResult(cacheKeyMethod = "getCacheKey") + @HystrixCommand(fallbackMethod = "getUserDefault", commandKey = "getUserById", groupKey = "userGroup", + threadPoolKey = "getUserThread") + public User getUser(Long id) { + log.info("获取用户信息"); + return restTemplate.getForObject("http://Server-Provider/user/{id}", User.class, id); + } + + @HystrixCommand(fallbackMethod = "getUserDefault2") + public User getUserDefault(Long id) { + String a = null; + // 测试服务降级 + a.toString(); + User user = new User(); + user.setId(-1L); + user.setUsername("defaultUser"); + user.setPassword("123456"); + return user; + } + + public User getUserDefault2(Long id, Throwable e) { + System.out.println(e.getMessage()); + User user = new User(); + user.setId(-2L); + user.setUsername("defaultUser2"); + user.setPassword("123456"); + return user; + } + + public List getUsers() { + return this.restTemplate.getForObject("http://Server-Provider/user", List.class); + } + + public String addUser() { + User user = new User(1L, "mrbird", "123456"); + HttpStatus status = this.restTemplate.postForEntity("http://Server-Provider/user", user, null).getStatusCode(); + if (status.is2xxSuccessful()) { + return "新增用户成功"; + } else { + return "新增用户失败"; + } + } + + @CacheRemove(commandKey = "getUserById") + @HystrixCommand + public void updateUser(@CacheKey("id") User user) { + this.restTemplate.put("http://Server-Provider/user", user); + } + + public void deleteUser(@PathVariable Long id) { + this.restTemplate.delete("http://Server-Provider/user/{1}", id); + } +} diff --git a/30.Spring-Cloud-Hystrix-Circuit-Breaker/Ribbon-Consumer/src/main/java/com/example/demo/controller/TestController.java b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Ribbon-Consumer/src/main/java/com/example/demo/controller/TestController.java new file mode 100644 index 00000000..f584730e --- /dev/null +++ b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Ribbon-Consumer/src/main/java/com/example/demo/controller/TestController.java @@ -0,0 +1,64 @@ +package com.example.demo.controller; + +import com.example.demo.Service.UserService; +import com.example.demo.domain.User; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +@RestController +public class TestController { + + @Autowired + private UserService userService; + + @GetMapping("testRequestMerge") + public void testRequerstMerge() throws InterruptedException, ExecutionException { + Future f1 = userService.findUser(1L); + Future f2 = userService.findUser(2L); + Future f3 = userService.findUser(3L); + f1.get(); + f2.get(); + f3.get(); + Thread.sleep(200); + Future f4 = userService.findUser(4L); + f4.get(); + } + + @GetMapping("testCache") + public void testCache() { + userService.getUser(1L); + userService.getUser(1L); + userService.getUser(1L); + } + + @GetMapping("user/{id}") + public User getUser(@PathVariable Long id) { + return userService.getUser(id); + } + + @GetMapping("user") + public List getUsers() { + return userService.getUsers(); + } + + @GetMapping("user/add") + public String addUser() { + return userService.addUser(); + } + + @GetMapping("user/update") + public void updateUser() { + userService.updateUser(new User(1L, "mrbird", "123456")); + } + + @GetMapping("user/delete/{id:\\d+}") + public void deleteUser(@PathVariable Long id) { + userService.deleteUser(id); + } +} diff --git a/30.Spring-Cloud-Hystrix-Circuit-Breaker/Ribbon-Consumer/src/main/java/com/example/demo/domain/User.java b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Ribbon-Consumer/src/main/java/com/example/demo/domain/User.java new file mode 100644 index 00000000..acd13d45 --- /dev/null +++ b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Ribbon-Consumer/src/main/java/com/example/demo/domain/User.java @@ -0,0 +1,53 @@ +package com.example.demo.domain; + +import java.io.Serializable; + +public class User implements Serializable { + + private static final long serialVersionUID = 1339434510787399891L; + private Long id; + private String username; + private String password; + + public User() { + } + + public User(Long id, String username, String password) { + this.id = id; + this.username = username; + this.password = password; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + @Override + public String toString() { + return "User{" + + "id=" + id + + ", username='" + username + '\'' + + ", password='" + password + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/30.Spring-Cloud-Hystrix-Circuit-Breaker/Ribbon-Consumer/src/main/java/com/example/demo/filter/HystrixRequestContextServletFilter.java b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Ribbon-Consumer/src/main/java/com/example/demo/filter/HystrixRequestContextServletFilter.java new file mode 100644 index 00000000..98841549 --- /dev/null +++ b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Ribbon-Consumer/src/main/java/com/example/demo/filter/HystrixRequestContextServletFilter.java @@ -0,0 +1,30 @@ +package com.example.demo.filter; + +import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext; +import org.springframework.stereotype.Component; + +import javax.servlet.*; +import javax.servlet.annotation.WebFilter; +import java.io.IOException; + +/** + * @author MrBird + */ +@Component +@WebFilter(filterName = "hystrixRequestContextServletFilter", urlPatterns = "/*", asyncSupported = true) +public class HystrixRequestContextServletFilter implements Filter { + @Override + public void init(FilterConfig filterConfig) { + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + HystrixRequestContext context = HystrixRequestContext.initializeContext(); + filterChain.doFilter(servletRequest, servletResponse); + context.close(); + } + + @Override + public void destroy() { + } +} diff --git a/30.Spring-Cloud-Hystrix-Circuit-Breaker/Ribbon-Consumer/src/main/resources/application.yml b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Ribbon-Consumer/src/main/resources/application.yml new file mode 100644 index 00000000..231ae588 --- /dev/null +++ b/30.Spring-Cloud-Hystrix-Circuit-Breaker/Ribbon-Consumer/src/main/resources/application.yml @@ -0,0 +1,12 @@ +server: + port: 9000 + +spring: + application: + name: Server-Consumer + +eureka: + client: + serviceUrl: + defaultZone: http://mrbird:123456@peer1:8080/eureka/,http://mrbird:123456@peer2:8081/eureka/ +