Spring cloud实战 从零开始一个简单搜索网站
Posted dikeboy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring cloud实战 从零开始一个简单搜索网站相关的知识,希望对你有一定的参考价值。
上文已经完成了一个简单的 浏览器 到 Client 到CSDN端的通路
我们的架构是每个博客网址为一个单独的组件, 这里为了方便直接先用CSDN 那个组件复制下
我这里改成 SDN 修改下 application.properties 端口记得改
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
spring.application.name=sdn
server.port=8983
下面是TOMCAT 和 eureka server运行的截图
好了 有两个搜索端了,我这里把CSDN SDN 叫做搜索端了 , 下面修改下 Client端 让他能分别调用2个组件
我修改了下github上的配置 把我们新建的serviceID加入进去
我们会回到Client项目的 ClientService 多了个SDN,需要修改下代码,能让程序自动加载多个HOST(这里只是简单介绍,如果搜索端好几个肯定得改进)
@Service public class ClientService { @Autowired RestTemplate restTemplate; @Autowired private EurekaClient discoveryClient; @Value("${serviceIds}") public String serviceIds; public String search(String key,String page) { StringBuffer sb =new StringBuffer(); if(serviceIds.contains(",")) { String[] ids = serviceIds.split(","); for(int i=0;i<ids.length;i++) { sb.append(searchDetail(key, page, ids[i])); } } else { sb.append(searchDetail(key, page,serviceIds)); } return sb.toString(); } public String searchDetail(String key,String page,String serviceId) { HashMap<String, String> map = new HashMap<>(); map.put("key", key); map.put("page", page); String str= restTemplate.getForObject(serviceUrl(serviceId)+"/search?key={key}&page={page}",String.class,map); return str; } @Bean RestTemplate restTemplate() { return new RestTemplate(); } public String serviceUrl(String serviceId) { InstanceInfo instance = discoveryClient.getNextServerFromEureka(serviceId, false); return instance.getHomePageUrl(); } }
因为数据比较多 我把两个搜索端直接改成返回一个字符串了
@RestController public class CsdnController { Gson gson = new Gson(); @RequestMapping(value = "/search") public String search(@RequestParam("key") String key, @RequestParam("page") String page) { System.out.println("search"); ArrayList<HashMap<String, String>> result; try { // result = SearchUtil.search(key, "blog", page); // return gson.toJson(result); return "i am csdn 1"; } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } }
public class CsdnController { Gson gson = new Gson(); @RequestMapping(value = "/search") public String search(@RequestParam("key") String key, @RequestParam("page") String page) { System.out.println("search"); ArrayList<HashMap<String, String>> result; try { // result = SearchUtil.search(key, "blog", page); // return gson.toJson(result); return "i am sdn 1"; } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } }
这下有两个端了,搜索时间也延长了2倍, 但万一个端有异常 另外一个端良好 怎么办 这时候就需要断路由 hystrix
在client pom里面导入下
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
POM 代码
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>tsearch_web</groupId> <artifactId>springtest-client</artifactId> <version>0.0.1</version> <packaging>jar</packaging> <name>springtest-client</name> <description>Note Server catch</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.1.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <spring-cloud.version>Greenwich.M3</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <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-netflix-hystrix</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Finchley.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> </project>
修改下application
@EnableEurekaClient
@SpringBootApplication
@EnableCircuitBreaker
public class SpringtestClientApplication {
public static void main(String[] args) {
SpringApplication.run(SpringtestClientApplication.class, args);
}
}
新增个SearchUtil 类
@Component public class SearchUtil { @Autowired RestTemplate restTemplate; @Autowired private EurekaClient discoveryClient; @HystrixCommand(groupKey = "searchDetail1", commandKey = "searchDetail1",fallbackMethod = "stubMyService") public String searchDetail1(String key, String page, String serviceId) { System.out.println("come="+serviceId); HashMap<String, String> map = new HashMap<>(); map.put("key", key); map.put("page", page); String str = restTemplate.getForObject(serviceUrl(serviceId) + "/search?key={key}&page={page}", String.class, map); return str; } @HystrixCommand(groupKey = "searchDetail2", commandKey = "searchDetail2",fallbackMethod = "stubMyService") public String searchDetail2(String key, String page, String serviceId) { System.out.println("come="+serviceId); HashMap<String, String> map = new HashMap<>(); map.put("key", key); map.put("page", page); String str = restTemplate.getForObject(serviceUrl(serviceId) + "/search?key={key}&page={page}", String.class, map); return str; } public String stubMyService(String key, String page, String serviceId) { return "error"; } @Bean RestTemplate restTemplate() { return new RestTemplate(); } public String serviceUrl(String serviceId) { InstanceInfo instance = discoveryClient.getNextServerFromEureka(serviceId, false); return instance.getHomePageUrl(); } }
修改下 ClientService
@Service
public class ClientService {
@Autowired
SearchUtil sc;
@Value("${serviceIds}")
public String serviceIds;
public String search(String key, String page) {
StringBuffer sb = new StringBuffer();
if (serviceIds.contains(",")) {
String[] ids = serviceIds.split(",");
sb.append(sc.searchDetail1(key, page, ids[0]));
sb.append(sc.searchDetail2(key, page, ids[1]));
}
else {
sb.append(sc.searchDetail1(key, page, serviceIds));
}
return sb.toString();
}
}
不断刷新 浏览器 好像没啥区别
给CSDN的Client加个超载
@RestController public class CsdnController { Gson gson = new Gson(); @RequestMapping(value = "/search") public String search(@RequestParam("key") String key, @RequestParam("page") String page) { System.out.println("search"); ArrayList<HashMap<String, String>> result; try { // result = SearchUtil.search(key, "blog", page); // return gson.toJson(result); Thread.sleep(5000); return "i am csdn 1"; } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } }
继续刷新
然后看下控制台 不是说好的垄断吗 为啥 还是进来了 虽然时间减少了
用Hystrix的时候要注意一点 Hystrix的 超时时间一点要大于resttemplete 或者你用 ribbon
Hystrix 的默认值全在 com.netflix.hystrix.HystrixCommandProperties
这个就是出错次数 private static final Integer default_circuitBreakerRequestVolumeThreshold = 20;// default => statisticalWindowVolumeThreshold: 20 requests in 10 seconds must occur before statistics matter
我们改下 SearchUtil
@Component public class SearchUtil { @Autowired RestTemplate restTemplate; @Autowired private EurekaClient discoveryClient; @HystrixCommand(groupKey = "searchDetail1", commandKey = "searchDetail1",fallbackMethod = "stubMyService", commandProperties = { @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "5") }) public String searchDetail1(String key, String page, String serviceId) { System.out.println("come="+serviceId); HashMap<String, String> map = new HashMap<>(); map.put("key", key); map.put("page", page); String str = restTemplate.getForObject(serviceUrl(serviceId) + "/search?key={key}&page={page}", String.class, map); return str; } @HystrixCommand(groupKey = "searchDetail2", commandKey = "searchDetail2",fallbackMethod = "stubMyService") public String searchDetail2(String key, String page, String serviceId) { System.out.println("come="+serviceId); HashMap<String, String> map = new HashMap<>(); map.put("key", key); map.put("page", page); String str = restTemplate.getForObject(serviceUrl(serviceId) + "/search?key={key}&page={page}", String.class, map); return str; } public String stubMyService(String key, String page, String serviceId) { return "error"; } @Bean RestTemplate restTemplate() { return new RestTemplate(); } public String serviceUrl(String serviceId) { InstanceInfo instance = discoveryClient.getNextServerFromEureka(serviceId, false); return instance.getHomePageUrl(); } }
重启下 不断刷新浏览器 发现 searchDetail1方法不执行了 好了 垄断完成
我们需要知道组件的当前状态 这时候就需要hystrix的dashbox
POM 中引入
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId> </dependency>
修改下ClientApplication 加入dashboard注释
@EnableEurekaClient
@SpringBootApplication
@EnableCircuitBreaker
@EnableHystrixDashboard
public class SpringtestClientApplication {
public static void main(String[] args) {
SpringApplication.run(SpringtestClientApplication.class, args);
}
@Bean
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
}
在浏览器输入http://localhost:8881/hystrix 就能看到界面
按上面的填写好 点击Monitor Stream就能进入统计页面
写个函数拼命跑 会发现数字多有变化 鼠标放上去可以看到具体说明
public class TestHystic { public static void main(String[] args) { long time1=System.currentTimeMillis(); String b =""; System.out.println(b.length()); for(int i=0;i<100;i++) { try { getData(); System.out.println("usertime="+(System.currentTimeMillis()-time1)); time1=System.currentTimeMillis(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public static void getData() throws Exception { URL serverUrl = new URL("http://localhost:8881/search?key=spring&page=1"); HttpURLConnection conn = (HttpURLConnection) serverUrl.openConnection(); InputStream in = conn.getInputStream(); BufferedReader br =new BufferedReader(new InputStreamReader(in, "UTF-8")); StringBuffer sb= new StringBuffer(); String line; while((line=br.readLine())!=null) { sb.append(line); } System.out.println(sb.toString()); in.close(); } }
以上是关于Spring cloud实战 从零开始一个简单搜索网站的主要内容,如果未能解决你的问题,请参考以下文章
让你从零开始搭建Spring Cloud Alibaba!这份Alibaba内部笔记太牛了
手把手教你,从零开始搭建Spring Cloud Alibaba!这份笔记太牛了
手把手教你,从零开始搭建Spring Cloud Alibaba!这份笔记太牛了