
-
微服务架构
你的整个应用程序将会被拆分成一个个功能独立的子系统,独立运行,系统与系统之间通过RPC接口通信。这样这些系统之间的耦合度大大降低,你的系统将非常容易扩展,团队协作效率提升了N个档次。这种架构通过眼下流行的SpringBoot和阿里巴巴吊炸天的Dubbo框架来实现。
-
容器化部署
你的各个微服务将采用目前处于浪潮之巅的Docker来实现容器化部署,避免一切因环境引起的各种问题,让你们团队的全部精力集中在业务开发上。
-
自动化构建
项目被微服务化后,各个服务之间的关系错中复杂,打包构建的工作量相当可怕。不过没关系,本文将借助Jenkins,帮助你一键自动化部署,从此你便告别了加班。

-
系统之间的耦合度大大降低,可以独立开发、独立部署、独立测试,系统与系统之间的边界非常明确,排错也变得相当容易,开发效率大大提升。
-
系统之间的耦合度降低,从而系统更易于扩展。我们可以针对性地扩展某些服务。假设这个商城要搞一次大促,下单量可能会大大提升,因此我们可以针对性地提升订单系统、产品系统的节点数量,而对于后台管理系统、数据分析系统而言,节点数量维持原有水平即可。
-
服务的复用性更高。比如,当我们将用户系统作为单独的服务后,该公司所有的产品都可以使用该系统作为用户系统,无需重复开发。

-
基于SpringBoot快速开发
我们将选择目前热度很高的SpringBoot,最大限度地降低配置复杂度,把大量的精力投入到我们的业务开发中来。
-
基于Dubbo的微服务化
我们会使用阿里巴巴的开源框架Dubbo,将我们的系统拆分成多个独立的微服务,然后用Dubbo来管理所有服务的发布和引用。有了Dubbo之后,调用远程服务就像调用一个本地函数一样简单,Dubbo会帮我们完成远程调用背后所需要的一切。
-
基于Docker的容器化部署
由于使用了微服务架构后,我们的系统将会由很多子系统构成。为了达到多个系统之间环境隔离的目的,我们可以将它们部署在多台服务器上,可这样的成本会比较高,而且每台服务器的性能可能都没有充分利用起来。所以我们很自然地想到了虚拟机,在同一台服务器上运行多个虚拟机,从而实现环境的隔离,每个虚拟机上运行独立的服务。然而虚拟机的隔离成本依旧很高,因为它需要占用服务器较多的硬件资源和软件资源。所以,在微服务结构下,要实现服务环境的隔离,Docker是最佳选择。它比虚拟机更加轻量级,占用资源较少,而且能够实现快速部署。
-
基于Jenkins的自动化构建
当我们采用了微服务架构后,我们会发现这样一个问题。整个系统由许许多多的服务构成,这些服务都需要运行在单独的容器中,那么每次发布的复杂度将非常高。首先你要搞清楚这些服务之间的依赖关系、启动的先后顺序,然后再将多个子系统挨个编译、打包、发布。这些操作技术难度低,却又容易出错。那么有什么工具能够帮助我们解决这些问题呢?答案就是——Jenkins。 它是一款自动化构建的工具,简单的来说,就是我们只需要在它的界面上按一个按钮,就可以实现上述一系列复杂的过程。
-
产品管理,产品的增删改查。
-
订单管理,订单的增删改查、购物车功能。
-
用户管理,用户的登录、注册、权限管理、收货地址等等。
-
数据分析,提供对本系统数据分析的功能。
-
创建一个Maven Project,命名为“Gaoxi”。这个Project由多个Module构成,每个Module对应着“微服务”的一个子系统,可独立运行,是一个独立的项目。 这也是目前主流的项目组织形式,即多模块项目。
-
在Gaoxi这个项目下创建各个子模块,每个自模块都是一个独立的SpringBoot项目:
Gaoxi-User 用户服务
Gaoxi-Order 订单服务
Gaoxi-Product 产品服务
Gaoxi-Analysis 数据分析服务
Gaoxi-Controller 本系统的控制层,和以往三层结构中的Controller层的作用一样,都是用作请求调度,只不过在微服务架构中,我们将它抽象成一个单独的系统,可以独立运行。
Gaoxi-Common-Service-Facade 它处于本系统的最底层,被所有模块依赖,一些公用的类库都放在这里。
Gaoxi-Redis 我们将Redis封装成一个单独的服务,运行在独立的容器中,当哪一个模块需要使用Redis的时候,仅需要引入该服务即可,就免去了各种繁琐的、重复的配置。而这些配置均在Gaoxi-Redis系统中完成了。
<groupId>com.gaoxi</groupId>
<artifactId>gaoxi</artifactId>
<version>0.0.1-SNAPSHOT</version>
<groupId>com.gaoxi</groupId>
<artifactId>gaoxi-common-service-facade</artifactId>
<version>0.0.1</version>
<packaging>jar</packaging>
<groupId>com.gaoxi</groupId>
<artifactId>gaoxi-user</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<modules>
<module>Gaoxi-Analysis</module>
<module>Gaoxi-Order</module>
<module>Gaoxi-Product</module>
<module>Gaoxi-User</module>
<module>Gaoxi-Redis</module>
<module>Gaoxi-Controller</module>
<module>Gaoxi-Common-Service-Facade</module>
</modules>
<parent>
<groupId>com.gaoxi</groupId>
<artifactId>gaoxi</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- Spring MVC -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
<!-- Mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Dubbo -->
<dependency>
<groupId>io.dubbo.springboot</groupId>
<artifactId>spring-boot-starter-dubbo</artifactId>
<version>1.0.0</version>
</dependency>
<!-- gaoxi-common-service-facade -->
<dependency>
<groupId>com.gaoxi</groupId>
<artifactId>gaoxi-common-service-facade</artifactId>
<version>0.0.1</version>
</dependency>
<!-- AOP -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>23.3-jre</version>
</dependency>
</dependencies>}}}
当父模块的pom中配置了公用依赖后,子模块的pom文件将非常简洁,如下所示:
{{{<groupId>com.gaoxi</groupId>
<artifactId>gaoxi-user</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>gaoxi-user</name>
<parent>
<groupId>com.gaoxi</groupId>
<artifactId>gaoxi</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
docker pull chaimm/tomcat:1.1
-
gaoxi-user
-
gaoxi-product
-
gaoxi-order
-
gaoxi-analysis
-
gaoxi-controller
-
gaoxi-redis
docker run --name gaoxi-user-1 -p 8082:8080 -v /usr/web/gaoxi-log:/opt/tomcat/gaoxi-log chaimm/tomcat:1.1
-
–name:指定容器的名字
-
-p:指定容器的端口映射
-p 8082:8080 表示将容器的8080端口映射到宿主机的8082端口上
-
-v:指定容器数据卷的映射
xxx:yyy 表示将容器yyy目录映射到宿主机的xxx目录上,从而访问宿主机的xxx目录就相当于访问容器的yyy目录。
-
chaimm/tomcat:1.1:表示容器所对应的镜像。
docker pull chaimm/zookeeper-dubbo:1.0
docker run --name zookeeper-debug -p 2182:2181 -p 10000:8080 chaimm/zookeeper-dubbo:1.0
-
-p 2182:2181:将容器的2181端口映射到宿主机的2182端口上,该端口是ZooKeeper的端口号。
-
-p 10000:8080:将容器的8080端口映射到宿主机的10000端口上,该端口是Dubbo-Admin所在Tomcat的端口号。
<!-- Spring Boot Dubbo 依赖 -->
<dependency>
<groupId>io.dubbo.springboot</groupId>
<artifactId>spring-boot-starter-dubbo</artifactId>
<version>1.0.0</version>
</dependency>
public interface UserService {
public UserEntity login(LoginReq loginReq);
}
@Service(version = "1.0.0")
public class UserServiceImpl implements UserService {
@Override
public UserEntity login(LoginReq loginReq) {
// 具体的实现代码
}
}
spring.dubbo.application.name=user-provider # 本服务的名称
spring.dubbo.registry.address=zookeeper://IP:2182 # ZooKeeper所在服务器的IP和端口号
spring.dubbo.protocol.name=dubbo # RPC通信所采用的协议
spring.dubbo.protocol.port=20883 # 本服务对外暴露的端口号
spring.dubbo.scan=com.gaoxi.user.service # 服务实现类所在的路径
@RestController
public class UserControllerImpl implements UserController {
@Reference(version = "1.0.0")
private UserService userService;
@Override
public Result login(LoginReq loginReq, HttpServletResponse httpRsp) {
// 登录鉴权
UserEntity userEntity = userService.login(loginReq);
}
}
spring.dubbo.application.name=controller-consumer # 本服务的名称
spring.dubbo.registry.address=zookeeper://IP:2182 # zookeeper所在服务器的IP和端口号
spring.dubbo.scan=com.gaoxi # 引用服务的路径
docker pull docker.io/jenkins/jenkins
docker run --name jenkins -p 10080:8080 docker.io/jenkins/jenkins
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.6.5</version>
<configuration>
<container>
<!-- 指明使用的tomcat服务器版本 -->
<containerId>tomcat8x</containerId>
<type>remote</type>
</container>
<configuration>
<type>runtime</type>
<cargo.remote.username>Tomcat的用户名</cargo.remote.username>
<cargo.remote.password>Tomcat的密码</cargo.remote.password>
</configuration>
</configuration>
<executions>
<execution>
<phase>deploy</phase>
<goals>
<goal>redeploy</goal>
</goals>
</execution>
</executions>
</plugin>
<profiles>
<profile>
<id>dev</id>
<properties>
<profileActive>dev</profileActive>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>test</id>
<properties>
<profileActive>test</profileActive>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<profileActive>prod</profileActive>
</properties>
</profile>
</profiles>
<resources>
<resource>
<!-- 标识配置文件所在的目录 -->
<directory>src/main/resources</directory>
<filtering>true</filtering>
<!-- 构建时将这些配置文件全都排除掉 -->
<excludes>
<exclude>application.properties</exclude>
<exclude>application-dev.properties</exclude>
<exclude>application-test.properties</exclude>
<exclude>application-prod.properties</exclude>
</excludes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<!-- 标识构建时所需要的配置文件 -->
<includes>
<include>application.properties</include>
<!-- ${profileActive}这个值会在maven构建时传入 -->
<include>application-${profileActive}.properties</include>
</includes>
</resource>
</resources>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<delimiters>
<delimiter>@</delimiter>
</delimiters>
<useDefaultDelimiters>false</useDefaultDelimiters>
</configuration>
</plugin>
spring.profiles.active=@profileActive@
-
在Gaoxi-User系统中实现登录的业务逻辑,并发布成RPC服务。
-
在Gaoxi-Controller中远程调用登录服务,并向前端提供登录的REST接口。
public interface UserService {
public UserEntity login(LoginReq loginReq);
}
@Service(version = "1.0.0")
@org.springframework.stereotype.Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDAO userDAO;
@Override
public UserEntity login(LoginReq loginReq) {
// 校验参数
checkParam(loginReq);
// 创建用户查询请求
UserQueryReq userQueryReq = buildUserQueryReq(loginReq);
// 查询用户
List<UserEntity> userEntityList = userDAO.findUsers(userQueryReq);
// 查询失败
if (CollectionUtils.isEmpty(userEntityList)) {
throw new CommonBizException(ExpCodeEnum.LOGIN_FAIL);
}
// 查询成功
return userEntityList.get(0);
}
}
@RestController
public class UserControllerImpl implements UserController {
@Reference(version = "1.0.0")
private UserService userService;
@Override
public Result login(LoginReq loginReq, HttpServletResponse httpRsp) {
// 登录鉴权
UserEntity userEntity = userService.login(loginReq);
// 登录成功
doLoginSuccess(userEntity, httpRsp);
return Result.newSuccessResult();
}
}
-
微服务架构
我们借助于SpringBoot和Dubbo实现了微服务架构。微服务架构的理念就是将一个原本庞大、复杂的系统,按照业务功能拆分成一个个具有独立功能、可以独立运行的子系统,系统之间若有依赖,则通过RPC接口通信。从而最大限度地降低了系统之间的耦合度,从而更加易于扩展、更加易于维护。
-
容器化部署
我们借助于Docker实现了容器化部署。容器能够帮助我们屏蔽不同环境下的配置问题,使得我们只需要有一个Dockerfile文件,就可以处处运行。和虚拟机一样,Docker也拥有环境隔离的能力,但比虚拟机更加轻量级,由于每个容器仅仅是一条进程,因此它可以达到秒级的启动速度。
-
自动化构建
我们借助于Jenkins实现了所有项目的自动化构建与部署。我们只需要点击“立即构建”这个按钮,Jenkins就可以帮助我们梳理好错综复杂的项目依赖关系,准确无误地完成构建,并将war包发送到相应的web容器中。在启动的过程中,Dubbo会扫描当前项目所需要发布和引用的服务,将所需要发布的服务发布到ZooKeeper上,并向ZooKeeper订阅所需的服务。 有了Jenkins之后,这一切都是自动化完成。也许你并没有太强烈地感受到Jenkins所带来的便利。但是你想一想,对于一个具有错综复杂的依赖关系的微服务系统而言,如果每个服务的构建都需要你手动完成的话,你很快就会崩溃,你大把的时间将会投入在无聊但又容易出错的服务构建上。而Jenkins的出现能让这一切自动化完成。
Comments
要发表评论,您必须先登录。