用Hystrix构建SpringBoot_API Gateway解决Ajax跨域

好久没写东西分享最近看的东西了,一直看的比较杂什么都在看,但没有深层次的理解。也不拿不出手来分享,一般都是感觉项目用的上这个东西就去看,最后决定上不上。

最近在微信公众号,想做下前后端分离,但是遇到个问题就是前后端分离后Ajax调用存在跨域的风险,当然解决跨域的方法很多,包括使用jsonp返回的时候带上callback等等。由于一直在看Springboot,发现了Hystrix开源出来的hystrix dashboard可以监控服务,最后在加上SpringMVC中的@CrossOrigin。即完美的解决了跨域的问题,还能监控各个服务的调用情况。这里就不在介绍dashboard了,写的也很粗,有问题的地方可以多指教。

1.创建SpringBoot项目

图片[1]-用Hystrix构建SpringBoot_API Gateway解决Ajax跨域-第五维

2.引入Maven依赖包


<dependency>  
	<groupId>org.springframework.boot</groupId>  
	<artifactId>spring-boot-starter-web</artifactId>  
</dependency>
<dependency>  
	<groupId>com.netflix.hystrix</groupId>  
	<artifactId>hystrix-core</artifactId>  
	<version>1.5.12</version>  
</dependency>
<dependency>  
	<groupId>com.netflix.hystrix</groupId>  
	<artifactId>hystrix-metrics-event-stream</artifactId>  
	<version>1.5.12</version>  
</dependency>    
<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>fastjson</artifactId>
	<version>1.2.31</version>
</dependency>
<dependency>
	<groupId>org.dom4j</groupId>
	<artifactId>dom4j</artifactId>
	<version>2.0.0</version>
</dependency>
<dependency>
	<groupId>org.apache.httpcomponents</groupId>
	<artifactId>httpclient</artifactId>
</dependency>

3.创建SpringBoot启动类以及注册Hystrix Servlet

GatewayApplication.java

@SpringBootApplication
@RestController
public class GatewayApplication {
	public static void main(String[] args) {
		 SpringApplication.run(GatewayApplication.class);
	}
	@RequestMapping("/")
	public String index() {
       return "Hello Word!";
    }
}

HystrixConfig.java

@Configuration  
public class HystrixConfig {  
	@Bean
    public HystrixMetricsStreamServlet hystrixMetricsStreamServlet(){
        return new HystrixMetricsStreamServlet();
    }
    
    @Bean
    public ServletRegistrationBean registration(HystrixMetricsStreamServlet servlet){
        ServletRegistrationBean registrationBean = new ServletRegistrationBean();
        registrationBean.setServlet(servlet);
        registrationBean.setEnabled(true);//是否启用该registrationBean
        registrationBean.addUrlMappings("/hystrix.stream");
        return registrationBean;
    }
    @Bean(initMethod="start")
    public UrlConfigThread urlThread(){
    	UrlConfigThread urlConfig=new UrlConfigThread();
    	return  urlConfig;
    }

} 

4.创建访问入口Controller

这里使用@CrossOrigin解决ajax跨域的问题,spring4.2增加的特性,并且区分get与post请求,以此来传递参数

HystrixController.java

@CrossOrigin
@RestController
@RequestMapping("/hystrix")
public class HystrixController {
	@Autowired
	private HystrixUtil hystrixUtil;
	@RequestMapping(value = "/{ServiceName}/{ServiceMethod}", method = { RequestMethod.GET, RequestMethod.POST })
	public ResultInfo HystrixData(@PathVariable String ServiceName,@PathVariable String ServiceMethod, HttpServletRequest request,HttpServletResponse response) throws InterruptedException, ExecutionException{
		boolean isGet = request.getMethod().toLowerCase().equals("get");
		Map<String, String> Parameter=getParameter(request);
		String url=UrlProperties.get(ServiceMethod);
		ResultInfo info=new ResultInfo();
		if(isGet){
			info= hystrixUtil.execute(ServiceName, ServiceMethod,url,Parameter,"GET");
		}else{
			info= hystrixUtil.execute(ServiceName, ServiceMethod,url,Parameter,"POST");
		}
		return info;
	}
	/**
	 * 取出请求的参数
	 */
	public Map<String, String> getParameter(HttpServletRequest request){
		Enumeration<String> param =  request.getParameterNames();
		Map<String, String> map = new HashMap<String,String>();
		while(param.hasMoreElements()){
			String key = param.nextElement();
			String value = request.getParameter(key);
			map.put(key, value);
		}
		return map;
	}
}

5.创建HystrixUtil和CommandHttpCall

这里就是主要的走Hystrix的类,创建HystrixUtil转一次主要为了区分各个服务的名称

HystrixUtil.java

@Component
public class HystrixUtil {
	public ResultInfo execute(String ServiceName, String ServiceMethod,String url, Map<String, String> Parameter,String RequestType) throws InterruptedException, ExecutionException {
			Setter setter = Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(ServiceName));//被调用服务
			setter.andCommandKey(HystrixCommandKey.Factory.asKey(ServiceMethod));//被调用服务的一个被调用方法
			setter.andCommandPropertiesDefaults( HystrixCommandProperties.Setter()
                    .withCircuitBreakerRequestVolumeThreshold(2)
                    .withCircuitBreakerSleepWindowInMilliseconds(60 * 1000).
                    withFallbackEnabled(true).
                    withExecutionIsolationThreadInterruptOnTimeout(true).withExecutionTimeoutInMilliseconds(5000));
				/* 使用HystrixThreadPoolKey工厂定义线程池名称*/  
	            /*当对同一业务依赖做隔离时使用CommandGroup做区分,
	             * 但是对同一依赖的不同远程调用如(一个是redis 一个是http),
	             * 可以使用HystrixThreadPoolKey做隔离区分.
	             * 最然在业务上都是相同的组,但是需要在资源上做隔离时,s
	             * 可以使用HystrixThreadPoolKey区分
	             * */
			return new CommandHttpCall(setter, url, Parameter,RequestType).execute();//同步执行
			//Future<z> future = new CommandHttpCal(setter, url).queue();//异步执行
			//return future.get();//需要时获取	
	}
}

CommandHttpCall.java

public class CommandHttpCall extends HystrixCommand<ResultInfo>{
	
	private final String url;
	
	private  Map<String, String> Parameter;
	
    private  String RequestType;
    
    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(CommandHttpCall.class);
    
    public CommandHttpCall(Setter setter,String url,Map<String, String> Parameter,String RequestType) {
        super(setter);
        this.url=url;
        this.Parameter=Parameter;
        this.RequestType=RequestType;
    }

    @Override
    protected ResultInfo run() throws Exception {
    	System.out.println("服务正被调用,当前线程:'{}'"+ Thread.currentThread().getName());
    	ResultInfo info = new ResultInfo(200,"ok");
    	if(RequestType.equals("GET")){
    		info=new GetHttpClient(url,Parameter).execute();
    	}else if(RequestType.equals("POST")){
    		info=new PostHttpClient(url,Parameter).execute();
    	}
    	/*Request request = new Request.Builder().url(url).build();
    	System.out.println(JSON.toJSONString(new OkHttpClient().newCall(request).execute().body().toString()));
    	info.setObj(JSON.toJSONString(new OkHttpClient().newCall(request).execute().body().toString()));*/
        return info;
    }

    @Override
    protected ResultInfo getFallback() {
        return new ResultInfo(500,"服务异常,请稍后重试!");
    }
}

到这里基本就是主要的代码了,为了能更灵活的使用它,增加了线程调用解析XML中配置的最终跳转的url

6.创建gateway_url.xml

<?xml version="1.0" encoding="UTF-8"?>
<urls>
	<host>
		http://192.168.0.56
	</host>

	<!-- url 路由配置-->
	<items>
		<item ServiceMethod="countylist" targeturl="/hsWxServices/county/countylist.action">
    </items>
</urls>

host节点作为访问的IP加端口域名也是可以的  items下item就是各个服务的路径    ServiceMethod作为key取对应的targeturl

7.创建UrlConfigThread和UrlProperties

使用线程去扫面并放到map中避免造成重复解析url

UrlConfigThread.java

public class UrlConfigThread extends Thread{

	@Override
	public void run() {
		// TODO Auto-generated method stub
		String host = "";
		
		 try {
			 SAXReader reader = new SAXReader();          
		     Document   document = reader.read(this.getClass().getClassLoader().getResourceAsStream("gateway_url.xml"));
		     Element root = document.getRootElement();
		     //先获取host
		     host = root.elementText("host").trim();
		     //获取全部的路由
		     Element items= root.element("items");
		     for(Iterator it=items.elementIterator();it.hasNext();){     
		         Element element = (Element) it.next();
		         String ServiceMethod = element.attribute("ServiceMethod").getText();
		         String targeturl = element.attribute("targeturl").getText();
		         /*UrlConfig config = new UrlConfig();
		         config.setServiceMethod(ServiceMethod); 
		         config.setTargeturl(targeturl);*/
		         UrlProperties.put(ServiceMethod, host+targeturl);
		     }
		} catch (Exception e) {
		}
	}
}

UrlProperties.java


public class UrlProperties {

	private static final Map<String, String> urlconfig = new HashMap<String , String>();
	
	private UrlProperties(){}
	
	public static void put(String key,String url){
		UrlProperties.urlconfig.put(key, url);
	}
	
	public static String get(String key){
		return UrlProperties.urlconfig.get(key);
	}
	
}

8.下载dashboard与启动

下载地址:https://repo1.maven.org/maven2/com/netflix/hystrix/hystrix-dashboard/1.5.9/

下载jar或者war看你自己了,启动hystrix-dashboard和刚刚创建的项目

图片[2]-用Hystrix构建SpringBoot_API Gateway解决Ajax跨域-第五维

输入localhost:8001/hystrix.stream,之后点击”Add Stream”,最后点击”Monitor Stream”即可。

图片[3]-用Hystrix构建SpringBoot_API Gateway解决Ajax跨域-第五维

至此项目的创建已经完成了,注意我在CommandHttpCall中区分了get和post,这里由于存在多种可能行比如你的post需要提交json参数而非key–value或者form表单等,http的代码我就不贴了。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享