在企业级软件的架构模型上,我们主要讨论下SOA与微服务架构。

  SOA的全称是Service-Oriented Architecture,可译为“面向服务的架构”,它是一个组件模型,将应用程序的不同功能单元(称为服务)通过这些服务之间定义良好的接口和契约联系起来。接口是采用中立的方式进行定义的,它应该独立于实现服务的硬件平台、操作系统和编程语言。这使得构建在各种各样的系统中的服务可以以一种统一和通用的方式进行交互。

  SOA是一种粗粒度、松耦合服务架构,服务之间通过简单、精确定义接口进行通讯,不涉及底层编程接口和通讯模型。SOA可以看作是B/S模型、XML(标准通用标记语言的子集)/Web Service技术之后的自然延伸。

  SOA服务具有平台独立的自我描述XML文档。Web服务描述语言(WSDL, Web Services Description Language)是用于描述服务的标准语言。
  SOA 服务用消息进行通信,该消息通常使用XML Schema来定义(也叫做XSD, XML Schema Definition)。消费者和提供者或消费者和服务之间的通信多见于不知道提供者的环境中。服务间的通讯也可以看作企业内部处理的关键商业文档。
  在一个企业内部,SOA服务通过一个扮演目录列表(directory listing)角色的登记处(Registry)来进行维护。应用程序在登记处(Registry)寻找并调用某项服务。统一描述,定义和集成(UDDI, Universal Description, Definition, and Integration)是服务登记的标准。
  每项SOA服务都有一个与之相关的服务品质(QoS, quality of service)。QoS的一些关键元素有安全需求(例如认证和授权),可靠通信(译注:可靠消息是指,确保消息“仅且仅仅”发送一次,从而过滤重复信息。),以及谁能调用服务的策略。

  要运行,管理SOA应用程序,企业需要SOA基础,这是SOA平台的一个部分。SOA基础必须支持所有的相关标准,和需要的运行时容器。SOA基础结构示意图如下:

  上图中,WSDL,UDDI和SOAP是SOA基础的基础部件。WSDL用来描述服务;UDDI用来注册和查找服务;而SOAP,作为传输层,用来在消费者和服务提供者之间传送消息。SOAP是Web服务的默认机制。一个消费者可以在UDDI注册表(registry)查找服务,取得服务的WSDL描述,然后通过SOAP来调用服务。

  WS-I Basic Profile,由Web服务互用性组织(Web Services Interoperability Organization)提供,是SOA服务测试与互用性所需要的核心构件。服务提供者可以使用Basic Profile测试程序来测试服务在不同平台和技术上的互用性。

  尽管J2EE和.NET平台是开发SOA应用程序常用的平台,但SOA不仅限于此。像J2EE这类平台,不仅为开发者自然而然地参与到SOA中来提供了一个平台,还通过他们内在的特性,将可扩展性,可靠性,可用性以及性能引入了SOA世界。新的规范,例如 JAXB(Java API for XML Binding),用于将XML文档定位到Java类;JAXR(Java API for XML Registry)用来规范对UDDI注册表(registry)的操作;XML-RPC(Java API for XML-based Remote Procedure Call)在J2EE1.4中用来调用远程服务,这使得开发和部署可移植于标准J2EE容器的Web服务变得容易,与此同时,实现了跨平台(如.NET)的服务互用。

  在企业中,关键任务系统(mission-critical system,是指如果一个系统的可靠性对于一个组织是至关重要的,那么该系统就是该企业的关键任务系统)用来解决高级需求,例如安全性,可靠性,事物。当一个企业开始采用服务架构作为工具来进行开发和部署应用的时候,基本的Web服务规范,像WSDL,SOAP,以及UDDI就不能满足这些高级需求。这些需求也称作服务品质(QoS,quality of services)。与QoS相关的众多规范已经由一些标准化组织(standards bodies)提出,像W3C(World Wide Web Consortium)和OASIS(the Organization for the Advancement of Structured Information Standards)。

  在了解SOA后,什么是微服务(micro service)呢?微服务可以在“自己的程序”中运行,并通过“轻量级设备与HTTP型API进行沟通”。微服务不需要像普通服务那样成为一种独立的功能或者独立的资源。微服务主要围绕业务领域组件来创建应用,这些应用可独立地进行开发、管理和迭代。微服务的本质是用一些功能比较明确、业务比较精练的服务去解决更大、更实际的问题。

  微服务(Microservice)这个概念是2012年出现的,作为加快Web和移动应用程序开发进程的一种方法,2014年开始受到各方的关注,而2015年,可以说是微服务的元年,越来越多的论坛、社区、blog以及互联网行业巨头开始对微服务进行讨论、实践,可以说这样更近一步推动了微服务的发展和创新。

  我们接下来以Java web项目为例,比较传统开发模式与微服务开发模式的区别。

  在传统开发模式里,所有的功能打包在一个 WAR包里,基本没有外部依赖(除了容器),部署在一个JEE容器(Tomcat,JBoss,WebLogic)里,包含了 DO/DAO,Service,UI等所有逻辑,如下图所示:

  上述传统开发模式的优点是:
  ①开发简单,集中式管理;
  ②基本不会重复开发;
  ③功能都在本地,没有分布式的管理和调用消耗。
  缺点是:
  ①效率低:开发都在同一个项目改代码,相互等待,冲突不断;
  ②维护难:代码功功能耦合在一起,新人不知道何从下手;
  ③不灵活:构建时间长,任何小修改都要重构整个项目,耗时;
  ④稳定性差:一个微小的问题,都可能导致整个应用挂掉;
  ⑤扩展性不够:无法满足高并发下的业务需求。
  一般来说,常见的系统架构遵循的三个标准和业务驱动力有:
  ①提高敏捷性:及时响应业务需求,促进企业发展;
  ②提升用户体验:提升用户体验,减少用户流失;
  ③降低成本:降低增加产品、客户或业务方案的成本。

  相对来说,基于微服务的设计可以有效的拆分应用,实现敏捷开发和部署。示意图如下:

  微服务的具体特征有:①由一些独立的服务共同组成系统;②单独部署,跑在自己的进程中;③每个服务为独立的业务开发;④分布式管理;⑤非常强调隔离性。

  那么,SOA和微服务有哪些区别呢?

  ①SOA喜欢重用,微服务喜欢重写。
  SOA的主要目的是为了企业各个系统更加容易地融合在一起。SOA里有一个重要的ESB(Enterprise Service Bus,即企业服务总线)机制,ESB是传统中间件技术与XML、Web服务等技术结合的产物。ESB提供了网络中最基本的连接中枢,是构筑企业神经系统的必要元素。我们可以把ESB想象成一个连接所有企业级服务的脚手架。SOA还可以把一个服务路由到另一个服务上,也可以集中化管理业务逻辑,规则和验证等。它还有一个重要功能是消息队列和事件驱动的消息传递,比如把JMS服务转化成SOAP协议。各服务间可能有复杂的依赖关系。

  微服务通常由重写一个模块开始。我们向微服务迁移的时候通常从耦合度最低的模块或对扩展性要求最高的模块开始,把它们一个一个剥离出来敏捷地重写,可以尝试最新的技术、语言和框架,然 后单独布署。它通常不依赖其他服务。微服务中常用的API Gateway的模式主要目的也不是重用代码,而是减少客户端和服务间的往来。

  ②SOA喜欢水平服务,微服务喜欢垂直服务。
  SOA设计喜欢给服务分层(如Service Layers模式)。如对于一个Entity服务层的设计,可能美其名曰Data Access Layer。 这种设计要求所有的服务都通过这个Entity服务层来获取数据。这种设计非常不灵活,比如每次数据层的改动都可能影响到所有业务层的服务。而每个微服务通常有它自己独立的data store。 我们在拆分数据库时可以适当的做些去范式化(denormalization),让它不需要依赖其他服务的数据。
  微服务通常是直接面对用户的,每个微服务通常直接为用户提供某个功能。

  ③SOA喜欢自上而下,微服务喜欢自下而上。
  SOA架构在设计开始时会先定义好服务合同(service contract)。 它喜欢集中管理所有的服务,包括集中管理业务逻辑,数据,流程,schema等。 它使用Enterprise Inventory和Service Composition等方法来集中管理服务。 SOA架构通常会预先把每个模块服务接口都定义好。 模块系统间的通讯必须遵守这些接口,各服务是针对他们的调用者。
  微服务则敏捷得多。只要用户用得到,就先把这个服务挖出来。然后针对性的,快速确认业务需求,快速开发迭代。

  所有的微服务都是独立的Java进程跑在独立的虚拟机上,所以服务间的通信就是IPC(inter process communication)。

  相比较而言,SOA更关注企业规模范围,微服务架构则更关注应用规模范围。

  总的来说,微服务架构继承了面向服务架构(SOA)的整体思路,将应用分割为一系列细小的服务,每个服务专注于单一的功能,运行在独立的进程中,服务之间的边界清晰,采用轻量级通信机制相互沟通、配合来实现完整的应用,满足业务和用户的需求。微服务架构更多是属于应用技术架构。我们接下来看一个微服务架构的案例SpringBoot。

  Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。它默认配置了很多框架的使用方式,就像maven整合了所有的jar包,spring boot几乎整合了所有的框架,

  一般来说或,我们平时搭建一个spring web项目,往往要这样做:

  ①配置web.xml,加载spring和spring mvc;
  ②配置数据库连接、配置spring事务;
  ③配置加载配置文件的读取,开启注解;
  ④配置日志文件
  ...
  配置完成之后再部署tomcat,调试等。

  好了,下面我用Spring Boot创建一个案例。

  pom.xml文件:

<?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>
<!--组,项目id,版本,打包类型-->
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging> <!--项目名称,描述-->
<name>demo</name>
<description>Demo project for Spring Boot</description> <!--父模块-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.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>
</properties> <!--依赖-->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--配置mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--c3p0配置-->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<!--添加对tomcat的支持-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency> <!--添加对jsp的支持;tomcat插件,默认端口8080-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<!--此处的<scope></scope>一定不要加上,作用域为provided,可以为compile或缺省-->
</dependency>
</dependencies> <build>
<!--插件配置-->
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

  application.properties文件:

#jsp视图配置,如果报错,可修改为:spring.view.prefix和spring.view.suffix,这个和spring boot的版本有关
spring.mvc.view.prefix=/WEB-INF/
spring.mvc.view.suffix=.jsp c3p0.jdbcUrl=jdbc:mysql://localhost:3306/itszt4
c3p0.user=root
c3p0.password=2018
c3p0.driverClass=com.mysql.jdbc.Driver
c3p0.minPoolSize=2
c3p0.maxPoolSize=10
c3p0.maxIdleTime=1800000
c3p0.acquireIncrement=3
c3p0.maxStatements=1000
c3p0.initialPoolSize=3

  DemoApplication.java文件:

package com.example.demo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.web.servlet.DispatcherServlet;
import javax.sql.DataSource;
@SpringBootApplication
@Configuration
@MapperScan("com.example.demo.dao")
public class DemoApplication {
@Bean(name = "dataSource")
@Qualifier(value = "dataSource")
@Primary
@ConfigurationProperties(prefix = "c3p0")
public DataSource dataSource() {
return DataSourceBuilder.create().type(com.mchange.v2.c3p0.ComboPooledDataSource.class).build();
} //分发中心配置返回视图的规则
@Bean
public ServletRegistrationBean dispatcherRegistration(DispatcherServlet dispatcherServlet) {
ServletRegistrationBean reg = new ServletRegistrationBean(dispatcherServlet);
reg.getUrlMappings().clear();
reg.addUrlMappings("*.html");
reg.addUrlMappings("*.json");
return reg;
} public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

  接下来是domain,dao,service,controller层的文件:

//domain实体类

package com.example.demo.domain;

/**
* 实体类,映射数据库里的表
*/
public class User { private String username, userpwd; public User() {
} public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public String getUserpwd() {
return userpwd;
} public void setUserpwd(String userpwd) {
this.userpwd = userpwd;
} public User(String username, String userpwd) {
this.username = username;
this.userpwd = userpwd;
}
}
----------------------------------------------------------------
dao层: package com.example.demo.dao;
import com.example.demo.domain.User;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
/**
* 访问,操作数据库
*/
@Repository
public interface UserDao {
@Select("select * from user where username=#{username} and userpwd=#{userpwd}")
public User queryUser(@Param("username") String username,@Param("userpwd") String userpwd);
}
----------------------------------------------------------------
service层: package com.example.demo.service;
/**
* 业务接口
*/
public interface UserService {
boolean doLogin(String username,String userpwd);
} package com.example.demo.service;
import com.example.demo.dao.UserDao;
import com.example.demo.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* 引入userDao
*/
@Service
public class UserServiceImpl implements UserService{
@Autowired
private UserDao userDao; @Override
public boolean doLogin(String username, String userpwd) {
User user = userDao.queryUser(username, userpwd);
if(user==null){
return false;
}
return true;
}
}
---------------------------------------------------------------
controller层: package com.example.demo.controller;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* 引入业务实现类,判断是否登录成功
* 传递用户名和密码两个参数
*/
@RequestMapping("/userCenter")
@Controller
public class UserController {
@Autowired
private UserService userService; @RequestMapping("/login.html")
public String doLogin(@RequestParam("username") String username,@RequestParam("userpwd") String userpwd){
boolean boo = userService.doLogin(username, userpwd);
if(boo){
return "usercenter";
}
return "redirect:/index.jsp?errorInfo=登录错误!";
}
}

  web.xml文件:

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<display-name>demo</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>encoding</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-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>

  两个前端页面:

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/userCenter/login.html">
<input type="text" name="username" value="admin">
<hr>
<input type="text" name="userpwd" value="admin">
<hr>
<input type="submit" value="登录">
<hr>
</form>
<span style="color: red;font-weight: bold">${param.errorInfo}</span>
</body>
</html> -------------------------------------------------------
usercenter.jsp <%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
我是usercenter123456789。。
</body>
</html>

  启动DemoApplication.java中的main()函数,在浏览器中访问http://localhost:8080/index.jsp即可。

SpringBoot微服务的更多相关文章

  1. SpringBoot微服务架构下的MVC模型总结

    SpringBoot微服务架构下的MVC模型产生的原因: 微服务概念改变着软件开发领域,传统的开源框架结构开发,由于其繁琐的配置流程 , 复杂的设置行为,为项目的开发增加了繁重的工作量,微服务致力于解 ...

  2. springboot微服务的简单小结

    springboot微服务的简单小结 近来公司用springboot微服务,所以小结一下. 基础: 什么是SpingBoot微服务? 如何创建SpringBoot微服务? 如何管理和完善SpringB ...

  3. Docker从入门到掉坑(二):基于Docker构建SpringBoot微服务

    本篇为Docker从入门到掉坑第二篇:基于Docker构建SpringBoot微服务,没有看过上一篇的最好读过 Docker 从入门到掉坑 之后,阅读本篇. 在之前的文章里面介绍了如何基于docker ...

  4. 基于Openshift的SpringBoot微服务

    基于Openshift的SpringBoot微服务 OpenShift是红帽的云开发平台即服务(PaaS).自由和开放源码的云计算平台使开发人员能够创建.测试和运行他们的应用程序,并且可以把它们部署到 ...

  5. ZooKeeper+Dubbo+SpringBoot 微服务Demo搭建

    1. 首先创建springBoot项目,springBoot是一堆组件的集合,在pom文件中对需要的组件进行配置.生成如下目录结构 创建test项目,同步在test创建dubbo-api,dubbo- ...

  6. SpringBoot微服务电商项目开发实战 --- Redis缓存雪崩、缓存穿透、缓存击穿防范

    最近已经推出了好几篇SpringBoot+Dubbo+Redis+Kafka实现电商的文章,今天再次回到分布式微服务项目中来,在开始写今天的系列五文章之前,我先回顾下前面的内容. 系列(一):主要说了 ...

  7. SpringBoot微服务电商项目开发实战 --- 模块版本号统一管理及Redis集成实现

    上一篇文章总结了基于SpringBoot实现分布式微服务下的统一配置.分环境部署配置.以及服务端模块的分离(每一个提供者就是一个独立的微服务).微服务落地.Dubbo整合及提供者.消费者的配置实现.本 ...

  8. springBoot 微服务

    微服务,是OO (面向对象,Object Oriented) 专家 Martin Fowler 于2014年在他一篇文章<Microservice>提出的.在 Mattin 的头脑中,兴奋 ...

  9. 手把手使用Docker搭建SpringBoot微服务镜像

    一.环境准备 1.安装好Docker环境的Linux机器(安装教程) 2.准备好SpringBoot项目打包好的可运行jar包 二.编写Dockerfile 1.首先将SpringBoot打包好的ja ...

随机推荐

  1. 【BZOJ2756】奇怪的游戏(二分,网络流)

    [BZOJ2756]奇怪的游戏(二分,网络流) 题面 BZOJ Description Blinker最近喜欢上一个奇怪的游戏. 这个游戏在一个 N*M 的棋盘上玩,每个格子有一个数.每次 Blink ...

  2. Codeforces 582C. Superior Periodic Subarrays(数学+计数)

    首先可以把 i mod n=j mod n的看成是同一类,i mod s=j mod s的也看成是同一类,也就是i mod gcd(s,n)的是同一类,很好理解,但是不会数学证明...大概可以想成数轴 ...

  3. 专题训练之LCA

    推荐几个博客:https://www.cnblogs.com/JVxie/p/4854719.html Tarjan离线算法的基本思路及其算法实现 https://blog.csdn.net/shah ...

  4. HTML 页面源代码布局介绍

    http://www.cnblogs.com/polk6/archive/2013/05/10/3071451.html 此介绍以google首页源代码截图为例: 从上到下依次介绍: 1.<!D ...

  5. lua和C++的交互(1)

    /* 以前听的一个故事,当年Java的创造者讲课的时候,一开始先拿一个简单的不能简单的小例子, 不断的扩展,最后成为一个复杂而完美的程序. 一个重要之重要的概念,就是栈.Lua与别的语言交互以及交换数 ...

  6. 理解PV操作和信号量

    对于信号量,可以认为是一个仓库,有两个概念,容量和当前的货物个数. P操作从仓库拿货,如果仓库中没有货,线程一直等待,直到V操作,往仓库里添加了货物,为了避免P操作一直等待下去,会有一个超时时间. V ...

  7. NOIP模拟赛13

    期望得分:100+0+100=200 实际得分:100+5+100=205 T1 空间卡到30M.. n<=2.5*1e7 若x是整除区间[1,n]每个数的最小的数,那么对[1,n]每个数分解质 ...

  8. Ubuntu 14.04 安装Visual studio Code

    上一篇简单介绍了Ubuntu 14.04上如何创建.运行 hello world 程序. 这篇介绍Ubuntu 14.04如何安装Visual studio Code. 网上推荐的有通过Ubuntu ...

  9. 如何构建一个很棒网站页脚(Website Footer)

    对于很多人来说,制作页脚是只是设计师顺手而为的任务.它似乎很容易,似乎可以忽略不计.因为很多人都觉得网站底部很少人会去看,而且页脚链接的所有链接的点击率(CTR)都是最低的,何必呢? 真是这样的吗?下 ...

  10. Lua的各种资源2

    Lua Directory     This page is a top level directory of all Lua content at this wiki, grouped by top ...