RPC调用_单体架构_SOA架构
系统架构的演变
1 传统的单体架构
1.1 什么是单体架构
一个归档包(例如 war 格式或者 Jar 格式)包含了应用所有功能的应用程序,我们通常称之 为单体应用。也称之为单体应用架构,这是一种比较传统的架构风格。
1.2 单体架构优点
便于开发:只需借助 IDE 的开发,调试功能即可完成 易于测试:只需要通过单元测试或浏览器即可完成测试 易于部署:打包成单一可执行 jar 或者 war 包,完成 jar 或者 war 部署即可
1.3 单体架构缺点
复杂性高:整个项目包含的模块非常多,模块的边界模糊,依赖关系不清晰,代码质量参差 不齐,整个项目非常复杂,修改一个 BUG 都会造成隐含的缺陷。
部署速度逐渐变慢:随着代码的增加,构建和部署的时间也会增加。而在单体应用中,每次 功能的变更或缺陷的修复都会导致我们需要重新部署整个应用。
扩展能力受限:单体应用只能作为一个整体进行扩展,无法结合业务模块的特点进行伸缩。
阻碍技术创新: 单体应用往往使用统一的技术平台或方案解决所有问题,团队的每个成员都 必须使用相同的开发语言和架构,想要引入新的框架或技术平台非常困难。
2SOA 架构(重点理解)
2.1 什么是 SOA 架构
SOA 是 Service-Oriented Architecture 的英文缩写,就是面向服务的架构。这里的服务可以理 解为 service 层业务服务。将系统拆分为不同的服务单元,通过网络协议服务单元之间进行 通信。服务单元完成一个特定功能(如:验证、支付、登录等等),通过服务单元之间的集成 组成完整的应用程序。
SOA 架构中由两个重要的角色:
服务提供者(Provider)和服务使用者(Consumer)
2.2SOA 架构的优点
更易维护:业务服务提供者和业务服务使用者的松散耦合关系。当需求发生变化的时候,不 需要修改提供业务服务的接口,只需要调整业务服务流程或者修改操作即可,整个应用系统 也更容易被维护。
更高的可用性:该特点是在于服务提供者和服务使用者的松散耦合关系上得以发挥与体现。 使用者无须了解提供者的具休实现细节。
更好的伸缩性:依靠业务服务设计、开发和部署等所采用的架构模型实现伸缩性。使得服务 提供者可以互相彼此独立地进行调整,以满足新的服务需求。
2.3SOA 架构的缺点
减低了系统的性能
系统之间交互需要使用远程通信,接口开发增加工作量
3 什么是 RPC 调用
RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求 服务,而不需要了解底层网络技术的协议。请求程序就是一个客户机,而服务提供程序就是 一个服务器
4 RPC 的应用场景
支付宝、微信、银联等第三方支付接入
公司内部的不同业务系统,不同技术平台的整合
5 RPC 的实现方式
RMI:Java 提供的基于 java 平台 RPC 远程调用技术,服务消费者和服务提供者是 java 平台
WEBSERVICE:通过 Http 协议,请求发送 xml 和响应 xml 的 RPC 远程调用技术,最大的特征使用 xml 进行数据交互,可以实现跨平台调用。
HttpClient:Http 客户端工具,Java 程序通过 HttpClient 发送 Http 协议的请求,直接获得远程 资源
HttpClient 实现 RPC 调用
1、HttpClient 介绍 HTTP 协议可能是现在 Internet 上使用得最多、最重要的协议了,越来越多的 Java 应用程 序需要直接通过 HTTP 协议来访问网络资源。 HttpClient 是 Apache Jakarta Common 下的子项目,供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包。实现了所有 HTTP 的方法(GET,POST,PUT,HEAD 等)支持 RestFul。
2、服务提供者实现
2.1 业务需求说明
实现:通过用户系统访问订单系统,获得某个用户的订单信息。
2.2 创建 order-sys 项目
<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>com.bjsxt.provider</groupId><artifactId>order-sys</artifactId><version>0.0.1-SNAPSHOT</version><packaging>war</packaging><properties><!-- spring 依赖 --><spring.version>4.3.18.RELEASE</spring.version><jstl.version>1.2</jstl.version><servlet-api.version>2.5</servlet-api.version><jsp-api.version>2.0</jsp-api.version><jackson.version>2.9.0</jackson.version></properties><dependencies><!-- jsp相关依赖 --><!-- servlet依赖 --><!-- jstl依赖 --><dependency><groupId>jstl</groupId><artifactId>jstl</artifactId><version>${jstl.version}</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId><version>${servlet-api.version}</version><scope>provided</scope></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jsp-api</artifactId><version>${jsp-api.version}</version><scope>provided</scope></dependency><!-- springmvc依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>${jackson.version}</version></dependency></dependencies><build><finalName>order</finalName><plugins><!-- 配置Tomcat插件 --><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><version>2.2</version><configuration><path>/order</path><port>7070</port></configuration></plugin></plugins></build>
</project>
2.3 创建 Order 订单实体类
package com.bjsxt.domain;/**** 订单的实体类* @author Administrator**/
public class Order {private String id;private Double total;private String date;public String getId() {return id;}public void setId(String id) {this.id = id;}public Double getTotal() {return total;}public void setTotal(Double total) {this.total = total;}public String getDate() {return date;}public void setDate(String date) {this.date = date;}}
3.4 创建 OrderController
package com.bjsxt.controller;import java.util.ArrayList;
import java.util.List;import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import com.bjsxt.domain.Order;@Controller
public class OrderController {/*** 接收http请求,响应订单集合* **/@RequestMapping("/loadOrderList")public String loadOrderList(String uid,Model model){Order o1=new Order();o1.setId("111");o1.setTotal(123.0);o1.setDate("2018-10-10");Order o2=new Order();o2.setId("222");o2.setTotal(1232.0);o2.setDate("2018-10-13");Order o3=new Order();o3.setId("333");o3.setTotal(333.0);o3.setDate("2018-10-31");List<Order> list = new ArrayList<>();list.add(o1);list.add(o2);list.add(o3);model.addAttribute("list", list);return "index.jsp";}/*** 接收http请求,响应订单集合,完成的是异步响应* 将List集合序列化为json串响应* **/@RequestMapping("/loadOrderList02")@ResponseBodypublic List<Order> loadOrderList02(String uid){System.out.println("uid="+uid);Order o1=new Order();o1.setId("111");o1.setTotal(123.0);o1.setDate("2018-10-10");Order o2=new Order();o2.setId("222");o2.setTotal(1232.0);o2.setDate("2018-10-13");Order o3=new Order();o3.setId("333");o3.setTotal(333.0);o3.setDate("2018-10-31");List<Order> list = new ArrayList<>();list.add(o1);list.add(o2);list.add(o3);return list;}
}
2.5 配置 springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>-<beans xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns="http://www.springframework.org/schema/beans"><!-- 扫描controller --><context:component-scan base-package="com.bjsxt.controller"/><mvc:annotation-driven/></beans>
2.6 配置 web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"version="2.5"><display-name>order</display-name><welcome-file-list><welcome-file>index.html</welcome-file><welcome-file>index.htm</welcome-file><welcome-file>index.jsp</welcome-file><welcome-file>default.html</welcome-file><welcome-file>default.htm</welcome-file><welcome-file>default.jsp</welcome-file></welcome-file-list><servlet-mapping><servlet-name>default</servlet-name><url-pattern>/favicon.ico</url-pattern></servlet-mapping><!-- 以监听器的方式启动spring容器 --><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!-- 指定spring的配置文件 --><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext-*.xml</param-value></context-param><!-- POST请求的乱码过滤器 --><filter><filter-name>encodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><!-- 指定编码方式 --><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param></filter><!-- 映射filter --><filter-mapping><filter-name>encodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping><!-- springmvc的servlet --><servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- 指定springmvc的配置文件 --><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc.xml</param-value></init-param><!-- 让springmvc随系统启动而启动 --><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>springmvc</servlet-name><url-pattern>/</url-pattern></servlet-mapping>
</web-app>
2.7 启动 order-sys 项目
3 服务消费者实现
3.1 创建 user-sys 项目
<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>com.bjsxt.consumer</groupId><artifactId>user-sys</artifactId><version>0.0.1-SNAPSHOT</version><!-- 添加httpClient依赖 --><dependencies><dependency><groupId>org.apache.httpcomponents</groupId><version>4.3.5</version><artifactId>httpclient</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.47</version></dependency></dependencies></project>
3.2 拷贝 Order 订单实体类
3.3 创建测试类
package com.sxt.test.client;import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;import com.alibaba.fastjson.JSON;
import com.sxt.domain.Order;public class TestHttpClient {public static void main(String[] args) throws ClientProtocolException, IOException {/*** 启动消费者进行服务的消费*///创建NameValuePair对象,封装发送服务提供者的 信息NameValuePair id = new BasicNameValuePair("uid", "1001");/*NameValuePair id1 = new BasicNameValuePair("uid1", "1001");NameValuePair id2 = new BasicNameValuePair("uid2", "1001");*/List<NameValuePair> list = new ArrayList<>();list.add(id);//发送远程的http请求的地址String url="http://localhost:7070/order/loadOrderList01";//创建HttpClient客户端对象HttpClient client = HttpClients.createDefault();//创建httpPost對象,发送post请求HttpPost post = new HttpPost(url);//封装请求体post.setEntity(new UrlEncodedFormEntity(list,"UTF-8"));//发送具体的http请求HttpResponse response = client.execute(post);//获取响应头消息Header[] headers = response.getAllHeaders();for (Header header : headers) {System.out.println(header.getName()+"-----"+header.getValue());}//获取服务提供者提供的具体数据HttpEntity entity = response.getEntity();//获取http的响应体InputStream content = entity.getContent();int length = 0;char [] buf= new char[1024];//将字节流转换为字符流InputStreamReader is = new InputStreamReader(content);//创建StringBufferStringBuffer sb = new StringBuffer();while((length = is.read(buf))!=-1){sb.append(String.valueOf(buf, 0, length));}System.out.println(sb);//将sb,json字符串转换为order集合List<Order> list1 = JSON.parseArray(sb.toString(), Order.class);for (Order o :list1 ) {System.out.println(o.getId()+"t"+o.getDate()+"t"+o.getTotal());}}
}
使用 Spring 提供的 restTemplate 完成 Http 服务消费
2RestTemplate 介绍 RestTemplate 是 Spring 提供的用于访问 Rest 服务的客户端,RestTemplate 提供了多种便捷访 问远程 Http 服务的方法,能够大大提高客户端的编写效率。
3 服务消费者实现
3.1 业务需求说明
实现:通过红包系统访问订单系统,获得某个用户的订单信息,派发红包.
3.2 创建 red-sys 项目
<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>com.bjsxt.red.consumer</groupId><artifactId>red-sys</artifactId><version>0.0.1-SNAPSHOT</version><packaging>war</packaging><properties><!-- spring 依赖 --><spring.version>4.3.18.RELEASE</spring.version><jstl.version>1.2</jstl.version><servlet-api.version>2.5</servlet-api.version><jsp-api.version>2.0</jsp-api.version><jackson.version>2.9.0</jackson.version></properties><dependencies><!-- jsp相关依赖 --><!-- servlet依赖 --><!-- jstl依赖 --><dependency><groupId>jstl</groupId><artifactId>jstl</artifactId><version>${jstl.version}</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId><version>${servlet-api.version}</version><scope>provided</scope></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jsp-api</artifactId><version>${jsp-api.version}</version><scope>provided</scope></dependency><!-- springmvc依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>${jackson.version}</version></dependency></dependencies><build><finalName>red</finalName><plugins><!-- 配置Tomcat插件 --><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><version>2.2</version><configuration><path>/red</path><port>8080</port></configuration></plugin></plugins></build>
</project>
3.3 拷贝 Order 订单实体类
拷贝 order-sys 中的实体类
3.4 创建 RedController 类
package com.sxt.controller;import java.util.Arrays;
import java.util.List;
import java.util.Map.Entry;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;
import org.w3c.dom.Entity;@Controller
public class RedController {//注入由spring提供的RestTemplate对象@Autowiredprivate RestTemplate restTemplate;/*** 发送远程的http请求,消费http服务* 获取订单的集合*/@RequestMapping("/loadOnList01")@ResponseBodypublic List<Order> loadOrderList01(String uid){//发送到远程服务的urlString url = "http://localhost:7070/order/loadOrderList01";//发送到远程服务的参数MultiValueMap<String, Object> params = new LinkedMultiValueMap<String, Object>();params.add("uid", uid);//通过restTemplate对象发送post请求Order[] orders = restTemplate.postForObject(url, params,Order[].class);//转换为listreturn Arrays.asList(orders);}@RequestMapping("/loadOnList02")@ResponseBodypublic List<Order> loadOrderList02(String uid){//发送到远程服务的urlString url = "http://localhost:7070/order/loadOrderList02";//发送到远程服务的参数MultiValueMap<String, Object> params = new LinkedMultiValueMap<String, Object>();params.add("uid", uid);//通过restTemplate对象发送post请求ResponseEntity<Order[]> entity = restTemplate.postForEntity(url, params,Order[].class);//get方式//restTemplate.getForEntity(url, responseType, uriVariables);//restTemplate.getForObject(url, params, uriVariables)//获得响应头信息HttpHeaders headers = entity.getHeaders();for (Entry<String, List<String>> e :headers.entrySet()) {System.out.println(e.getKey()+e.getValue()); } //获取响应状态码int statusCode = entity.getStatusCodeValue();System.out.println(statusCode);//获得远程服务的响应体Order[] orders = entity.getBody();return Arrays.asList(orders);}
}
3.5 配置 springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 扫描controller --><context:component-scan base-package="com.sxt.controller" /><mvc:annotation-driven></mvc:annotation-driven><!-- 实例化RestTemplate对象 --><bean id="restTemplate" class="org.springframework.web.client.RestTemplate"></bean>
</beans>
3.6 配置 web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"version="2.5"><display-name>red</display-name><welcome-file-list><welcome-file>index.html</welcome-file><welcome-file>index.htm</welcome-file><welcome-file>index.jsp</welcome-file><welcome-file>default.html</welcome-file><welcome-file>default.htm</welcome-file><welcome-file>default.jsp</welcome-file></welcome-file-list><servlet-mapping><servlet-name>default</servlet-name><url-pattern>/favicon.ico</url-pattern></servlet-mapping><!-- 以监听器的方式启动spring容器 --><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!-- 指定spring的配置文件 --><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext-*.xml</param-value></context-param><!-- POST请求的乱码过滤器 --><filter><filter-name>encodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><!-- 指定编码方式 --><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param></filter><!-- 映射filter --><filter-mapping><filter-name>encodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping><!-- springmvc的servlet --><servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- 指定springmvc的配置文件 --><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc.xml</param-value></init-param><!-- 让springmvc随系统启动而启动 --><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>springmvc</servlet-name><url-pattern>/</url-pattern></servlet-mapping>
</web-app>
3.7 启动 order-sys
3.8 启动访问 red-sys
RPC跨域问题
1、Ajax 跨域介绍
跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器 对 JavaScript 施加的安全限制。
3Ajax 跨域问题
3.1 建立 ajax-origin 项目
<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>com.sxt</groupId><artifactId>ajax-origin</artifactId><version>0.0.1-SNAPSHOT</version><packaging>war</packaging><properties><!-- spring 依赖 --><spring.version>4.3.18.RELEASE</spring.version><jstl.version>1.2</jstl.version><servlet-api.version>2.5</servlet-api.version><jsp-api.version>2.0</jsp-api.version><jackson.version>2.9.0</jackson.version></properties><dependencies><!-- jsp相关依赖 --><!-- servlet依赖 --><!-- jstl依赖 --><dependency><groupId>jstl</groupId><artifactId>jstl</artifactId><version>${jstl.version}</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId><version>${servlet-api.version}</version><scope>provided</scope></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jsp-api</artifactId><version>${jsp-api.version}</version><scope>provided</scope></dependency></dependencies><build><finalName>ajax</finalName><plugins><!-- 配置Tomcat插件 --><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><version>2.2</version><configuration><path>/ajax</path><port>9090</port></configuration></plugin></plugins></build>
</project>
3.2 发送 Ajax 请求
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.3.js"></script>
<script type="text/javascript">function sendAjax(){/* $.post("http://localhost:7070/order/loadOrderList02","uid=1234",function(data){alert(data);}); */$.getJSON("http://localhost:7070/order/loadOrderList03?callback=?","uid=1234",function(data){var str = JSON.stringify(data);alert(str);});}function doCallback(data){//将json对象转换为字符串var str = JSON.stringify(data);alert(str);}
</script>
</head>
<body><a href="javascript:sendAjax()">sendAjax</a><script src="http://localhost:7070/order/loadOrderList03?uid=9999&callback=doCallback"></script>
</body>
</html>
4Ajax 跨域解决方案
4.1 服务器段解决
服务端设置 response header 中 Access-Control-Allow-Origin 字段 ,服务器段,使用 CORSFilter 过滤器解决跨域问题
通过 CORSFilter 过滤器在服务器端修改 Http 的响应头 Access-Control-Allow-Origin: * Access-Control-Allow-Origin: http://example.com:8080/
修改 order-sys 项目
(1)添加 CORSFilter 依赖
<dependency><groupId>com.thetransactioncompany</groupId><artifactId>cors-filter</artifactId><version>2.5</version><scope>runtime</scope></dependency>
(2) web.xml 配置 CORSFilter
<filter-name>CORS</filter-name> <filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class> <init-param> <param-name>cors.allowOrigin</param-name> <param-value>*</param-value> </init-param> <init-param> <param-name>cors.supportedMethods</param-name> <param-value>GET, POST, HEAD, PUT, DELETE</param-value> </init-param> <init-param> <param-name>cors.supportedHeaders</param-name> <param-value>Accept, Origin, X-Requested-With, Content-Type, Last-Modified</param-value> </init-param> <init-param> <param-name>cors.exposedHeaders</param-name> <param-value>Set-Cookie</param-value> </init-param> <init-param> <param-name>cors.supportsCredentials</param-name> <param-value>true</param-value> </init-param>
</filter> <filter-mapping> <filter-name>CORS</filter-name> <url-pattern>/*</url-pattern>
</filter-mapping>
4.2 前端 JSONP 解决
利用 script 标签,不受同源策略的限制,用户从服务请求数据,服务器返回一个带有方法和数据 的 js 代码。
在 js 中,我们直接用 XMLHttpRequest 请求不同域上的数据时,是不可以的。但是,在页面 上引入不同域上的 js 脚本文件却是可以的,jsonp 正是利用这个特性来实现的。
例如: <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
从不同域的服务器直接请求 js 代码,jsonp 就是通过获得不同域的服务器上的 js 代码(js 代码 中包含一个在本地定义的 js 函数和需要获得数据),来获得不同域的数据。
3 修改 order-sys 项目
3.1 注释 web.xml 中 CORSFilter 配置
3.2 添加 fastjson 依赖
<!-- fastjson --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.47</version></dependency></dependencies>
3.3 修改 OrderController 类
Controller 添加一个接收远程 ajax 请求的方法,该方法后一个接收回调函数的参数.
/*** 接收json请求,响应js的字符串到客服端* @param uid* @param callback* @return*/@RequestMapping("/loadOrderList03")@ResponseBodypublic String loadOrderList03(String uid,String callback){Order order1 = new Order();order1.setId("111");order1.setTotal(123.0);order1.setDate("2018-10-01");Order order2 = new Order();order2.setId("222");order2.setTotal(1213.0);order2.setDate("2018-10-21");Order order3 = new Order();order3.setId("333");order3.setTotal(1233.0);order3.setDate("2018-10-31");List<Order> list = new ArrayList<>();list.add(order1);list.add(order2);list.add(order3);//函数名+函数的实参String result = callback+"("+JSON.toJSONString(list)+")";return result;}
3.4 启动 order-sys 项目
4 修改 ajax-origin 项目 4.1 导入 juqery 函数库
<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.3.js"></script>
4.2 发送请求
利用<script src="url?callback=doSomething"></script>发送请求
<script src="http://localhost:7070/order/loadOrderList03?uid=9999&callback=doCallback"></script>
4.3 定义 callback 回调函数
function doCallback(data){//将json对象转换为字符串var str = JSON.stringify(data);alert(str);}
5jquery 对 jsonp 支持
function sendAjax(){/* $.post("http://localhost:7070/order/loadOrderList02","uid=1234",function(data){alert(data);}); */$.getJSON("http://localhost:7070/order/loadOrderList03?callback=?","uid=1234",function(data){var str = JSON.stringify(data);alert(str);});}
RPCRMI服务集群部署_消费_服务注册和发现
目标:理解服务的集群部署
理解服务发现
1.1 服务单机部署
将某个应用服务,部署到一台服务器,所有服务消费者的并发访问都发送到一台服务器.
在系统业务的发展,不露出相应的问题: 高并发访问题: 会出现系统资源不够用(带宽,cpu,内存)等等 系统的单节点故障: 当单节点服务器出现宕机故障的时候,会出现服务访问没法访问的 问
1.2 服务的集群部署
将某个应用服务部署到,同时部署到 n 个服务器节点,由 n 个服务器节点对外提供相同服务. 同时可以提供备用节点服务器.
通过集群部署的方式可以解决,服务的高并发访问和单节点故障问题: 高并发访问: 通过特定的负载均衡(Load Balance)算法,将并发访问的请求,分发到不同节点的服务器进行处理,以将每一台服务器的负载压力,实现负载均衡。
单节点故障: 当实现服务集群部署的时候,单个服务器节点宕机,可以由其他正常的服务器节点,正 常向外提供服务,不会出现服务的不可访问问题,实现服务的(HA)高可用
3RMI 模拟服务器集群部署
3.1 发布集群服务
启动程序三次,每次启动修改端口号,实现服务的集群部署
3.2RMI 消费集群服务
package com.sxt.app;import java.rmi.Naming;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;import com.sxt.service.UserService;public class consumerApp {public static void main(String[] args) {List<String> urls = new ArrayList<String>();urls.add("rmi://localhost:7777/rmi");urls.add("rmi://localhost:8888/rmi");urls.add("rmi://localhost:9999/rmi");String url = null;try {while(true){//通过随机的负载均衡算法,产生随机的访问地址int index = ThreadLocalRandom.current().nextInt(urls.size());url = urls.get(index);UserService service = (UserService)Naming.lookup(url);System.out.println("获取的远程服务的代理对象:"+service.getClass().getName()); //通过远程服务的代理对象代用远程代理方法String result = service.helloRmi("///"+url+"--------------rmi");System.out.println("result"+result);Thread.sleep(3000);}} catch (Exception e) {urls.remove(url); e.printStackTrace();}}
}
4、 服务注册与发现
(0)服务容器负责启动,加载,运行服务提供者。
(1)服务提供者在启动时,向注册中心注册自己提供的服务 URL。
(2)服务消费者在启动时,向注册中心订阅自己所需的服务。
(3)注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送 变更数据给消费者。
(4)服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如 果调用失败,再选另一台调用。
让消费能够感知到服务提供者的状态发生了变化(宕机,重启)