谈谈架构演变
单体应用:ALL IN ONE
在之前我们,开发一个应用时,只创建一个项目,把所有的页面、代码都放着里面,把这个项目打成war包部署在tomcat中。
优点:
- 开发测试简便:由于是一个应用,不存在多个应用之间的互联互调
- 部署简便:打一个war包部署在tomcat中,不会给运维带来太多工作挑战
- 水平拓展简便:当应用负载能力差时,只需将相同的这一个应用拷贝到很多个服务器上面,多个服务器同时跑这个项目,通过负载均衡机制提高并发能力
缺点:
- 牵一发动全身:只要是修改代码,那么就得重新部署项目
- 随着现代软件应用发展,任何一个应用都可能是一个大型应用,不可能ALL IN ONE,维护和分工困难
微服务
为了解决上面所说的问题,觉定把项目细化,分出多个模块,微化服务。每一个服务都是一个可替换可独立升级的软件单元,每个软件单元通过http互联互调就形成了一个轻量级应用网。这些服务可以通过http或者RPC的方式进行互通。
- 节省了调用资源。
- 每个功能元素的服务都是一个可替换的、可独立升级的软件代码。真正的高内聚、低耦合。
而在微服务阶段,面临的问题如:服务的部署、连桥,服务间调度、负载均衡、服务熔断、消息队列等都需要去了解学习。路还很长加油!!!
springboot可以快速的构建一个软件单元,也就是快速的构建一个独立的服务。而大型分布式网络服务的调用,是有springcloud来完成,实现分布式
SpringCloud
是一套目前完整的微服务框架,它是是一系列框架的有序集合。它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过SpringBoot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用SpringBoot的开发风格做到一键启动和部署。
第一个SpringCloud程序
案例的环境依赖
<?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>com.baidu</groupId>
<artifactId>cloud-test</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>user-service</module>
<module>consumer-demo</module>
<module>eureka-sever</module>
</modules>
<packaging>pom</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.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>Finchley.SR1</spring-cloud.version>
<mapper.starter.version>2.0.3</mapper.starter.version>
<mysql.version>5.1.32</mysql.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- springCloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--通用Mapper启动器-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>${mapper.starter.version}</version>
</dependency>
<!-- mysqL驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
user-service子服务
作为服务的提供方。
application.yml配置
server:
port: 8081
#控制日志级别
logging:
level:
com.baidu: debug
# 数据库连接信息
spring:
application:
name: user-service
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/spring_study_db?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
username: root
password: admin
#配置mybatis的信息
mybatis:
#pojo别名扫描
type-aliases-package: com.baidu.user.pojo
#加载mybatis映射文件,使用通用Mapper这个就不用了
#mapper-locations: classpath:mapper/*mapper.xml
controller代码:
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/findById/{id}")
public User findById(@PathVariable("id")Integer id){
return userService.findById(id);
}
@GetMapping("/findAll")
public List<User> findAll(){
return userService.findAll();
}
}
consemer-demo子服务
作为服务的消费方。
application.yml配置
server:
port: 8082
spring:
application:
name: consumer-server
controller代码:
@RestController
@Reques tMapp ing ("Consumer")
public class Consume rController [
@Autowired
private RestTemplate restTemplate;
@GetMapping("{id}" )
public User queryById (@PathVariable("id") Long id){
String url = "http: //Localhost: 8081/user/findById/" + id;
User user = restTemplate.getForobject(url, User.class) ;
return user;
}
}
这里我们通过consemer-demo子服务去调用了user-service子服务。
思考上面代码问题
简单回顾一下写了什么,有没有问题?
user-service:对外提供了查询用户的接口
consumer:通过RestTemplate访问 http: //Localhost: 8081/user/findById/{id} 接口,查询用户数据
- 存在问题:
●在consumer中, 我们把url地址硬编码到了代码中,不方便后期维护
●consumer需要记忆user-service的地址,如果出现变更,可能得不到通知,地址将失效
●consumer不清楚user-service的状态, 服务宕机也不知道
●user-service只有1台服务, 不具备高可用性
●即便user-service形成集群, consumer还需自己实现负载均衡