第一章 SpringBoot 快速入门
Spring Boot简介
Spring Boot诞生于大数据微服务时代
设计理念:用来简化新Spring应用的初始搭建以及开发过程,约定大于配置,去繁从简
SpringBoot背景
J2EE笨重的开发、繁多的配置、低下的开发效率、复杂的部署流程、第三方技术集成难度大。
“Spring全家桶”时代。Spring Boot—>J2EE一站式解决方案Spring Cloud—>分布式整体解决方案
Spring Boot特点
- 创建独立的Spring应用程序
- 嵌入的Tomcat,无需部署WAR文件
- 简化Maven配置
- 自动配置Spring
- 没有xml配置
Spring Boot优缺点
缺点
- 新技术坑多,文档较少
- 入门容易深入难
优点
- 简化开发,简化配置,门槛低等
- 快速创建独立运行的Spring项目以及与主流框架集成
- 使用嵌入式的Servlet容器,应用无需打成WAR包
- starters自动依赖与版本控制
- 大量的自动配置,简化开发,也可修改默认值
- 无需配置XML,无代码生成,开箱即用
- 准生产环境的运行时应用监控
- 与云计算的天然集成
什么是微服务
微服务是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成。系统中的各个微服务可被独立部署,各个微服务之间是松耦合的。每个微服务仅关注于完成一件任务并很好地完成该任务。在所有情况下,每个任务代表着一个小的业务能力。
微服务的概念源于2014年3月Martin Fowler所写的一篇文章“Microservices”(http://martinfowler.com/articles/microservices.html)。尽管“微服务”这种架构风格没有精确的定义,但其具有一些共同的特性,如围绕业务能力组织服务、自动化部署、智能端点、对语言及数据的“去集中化”控制等等。微服务架构的思考是从与整体应用对比而产生的。
对应用组件封装的方式是整体架构与微服务架构的主要差异,微服务架构将相关联的业务逻辑及数据放在一起形成独立的边界,其目的是能在不影响其他应用组件(微服务)的情况下更快地交付并推出市场。
为什么需要微服务架构
- 使用传统的整体式架构(Monolithic Architecture)应用开发系统,如CRM、ERP等大型应用,随着新需求的不断增加,企业更新和修复大型整体式应用变得越来越困难;
- 随着移动互联网的发展,企业被迫将其应用迁移至现代化UI界面架构以便能兼容移动设备,这要求企业能实现应用功能的快速上线;
- 许多企业在SOA(面向服务的架构是一个组件模型,它将应用程序的不同功能单元[称为服务]通过这些服务之间定义良好的接口和契约联系起来。 接口是采用中立的方式进行定义的,它应该独立于实现服务的硬件平台、操作系统和编程语言。)投资中得到的回报有限,SOA可以通过标准化服务接口实现能力的重用,但对于快速变化的需求,受到整体式应用的限制,有时候显得力不从心;
- 随着应用云化的日益普及,生于云端的应用具有与传统IT不同的技术基因和开发运维模式。此外,从技术方面看,云计算及互联网公司大量开源轻量级技术不停涌现并日渐成熟:互联网/内联网/网络更加成熟;
- 新的轻量级协议(RESTful API接口, 轻量级消息机制);
- 服务平台化(PaaS): 云服务平台上具有自动缩放、工作负载管理、SLA 管理、消息机制、缓存、构建管理等各种按需使用的服务;
- 新的可替代数据持久化模型:如NoSQL, MapReduce, BASE, CQRS等;
- 标准化代码管理:如Github等。
微服务架构的缺点
微服务的一些想法在实践上是好的,但当整体实现时也会呈现出其复杂性。
- 运维开销及成本增加:整体应用可能只需部署至一小片应用服务区集群,而微服务架构可能变成需要构建/测试/部署/运行数十个独立的服务,并可能需要支持多种语言和环境。这导致一个整体式系统如果由20个微服务组成,可能需要40~60个进程。
- 必须有坚实的DevOps开发运维一体化技能:开发人员需要熟知运维与投产环境,开发人员也需要掌握必要的数据存储技术如NoSQL,具有较强DevOps技能的人员比较稀缺,会带来招聘人才方面的挑战。
- 隐式接口及接口匹配问题:把系统分为多个协作组件后会产生新的接口,这意味着简单的交叉变化可能需要改变许多组件,并需协调一起发布。在实际环境中,一个新品发布可能被迫同时发布大量服务,由于集成点的大量增加,微服务架构会有更高的发布风险。
- 代码重复:某些底层功能需要被多个服务所用,为了避免将“同步耦合引入到系统中”,有时需要向不同服务添加一些代码,这就会导致代码重复。
- 分布式系统的复杂性:作为一种分布式系统,微服务引入了复杂性和其他若干问题,例如网络延迟、容错性、消息序列化、不可靠的网络、异步机制、版本化、差异化的工作负载等,开发人员需要考虑以上的分布式系统问题。
- 异步机制:微服务往往使用异步编程、消息与并行机制,如果应用存在跨微服务的事务性处理,其实现机制会变得复杂化。
- 可测性的挑战:在动态环境下服务间的交互会产生非常微妙的行为,难以可视化及全面测试。经典微服务往往不太重视测试,更多的是通过监控发现生产环境的异常,进而快速回滚或采取其他必要的行动。但对于特别在意风险规避监管或投产环境错误会产生显著影响的场景下需要特别注意。
创建Spring Boot项目步骤
- 配置maven环境
- 创建maven项目
- 添加Spring Boot依赖包
- 编写程序入口及demo类
- 配置properties文件
配置maven环境
官网下载地址
解压maven
配置maven环境变量
配置setting文件
setting文件默认存放目录:C:\Users\Administrator.m2
配置远程仓库地址
<mirrors> <!-- 配置镜像让Maven只使用私服 --> <mirror> <id>nexus</id> <mirrorOf>*</mirrorOf> <name>my maven repository</name> <url>http://192.168.41.16:8081/nexus/content/groups/public/</url> </mirror> </mirrors> <profiles> <!-- 配置Nexus仓库 --> <profile> <id>nexus</id> <repositories> <repository> <id>central</id> <!-- <url>http://central</url> --> <url>http://192.168.41.16:8081/nexus/content/groups/public/</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>central</id> <!-- <url>http://central</url> --> <url>http://192.168.41.16:8081/nexus/content/groups/public/</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </pluginRepository> </pluginRepositories> </profile> </profiles>
创建maven项目
File->New->Other->Maven Project
添加Spring Boot依赖包
- 指定springboot父项目版本
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.5.RELEASE</version>
<relativePath></relativePath>
</parent>
- springboot依赖包
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
springboot maven构建插件
编写程序入口及demo类
创建应用入口类,并在类上面加上以下三个注解
@EnableAutoConfiguration:开启配置文件读写
@SpringBootApplication:开启Spring Boot
@RestController:rest控制器
@EnableAutoConfiguration // 开启配置文件读写 @SpringBootApplication // 开启Spring Boot @RestController // rest控制器 public class DemoApplication { /** * 无参数请求 * @return */ @RequestMapping("/helloworld") public String helloworld() { return "hello world"; } /** * 支持(post/get)请求 * @param name * @return */ @RequestMapping("/testRequestParam") public String testRequestParam(@RequestParam("name") String name) { return "hello world: " + name; } /** * 只支持get请求 * @param username * @param age * @return */ @RequestMapping("/testPathVariable/{username}/{age}") public String testPathVariable(@PathVariable("username") String username, @PathVariable("age") Integer age) { return "username = " + username + " and age = " + age; } public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
配置properties文件
- 与程序相关配置都写在properties文件里
- 在resources目录下建application.properties文件
- 常用配置项
- server.port=#端口号
- server.contextPath=#服务地址指定如:/demo
# 端口号
server.port=8082
# 服务上下文路径
server.context-path=/demo
运行Spring Boot项目
- Eclipse里右击程序入口类run as -> Java Application 即可访问
- 通过maven打包成jar包,在doc下用java命令运行(java -jar xxxxx.jar )
starters
- Spring Boot为我们提供了简化企业级开发绝大多数场景的starter pom(启动器),只要引入了相应场景的starter pom,相关技术的绝大部分配置将会消除(自动配置),从而简化我们开发。业务中我们就会使用到Spring Boot为我们自动配置的bean
- 参考https://docs.spring.io/spring-boot/docs/1.5.9.RELEASE/reference/htmlsingle/#using-boot-starter
- 这些starters几乎涵盖了javaee所有常用场景,Spring Boot对这些场景依赖的jar也做了严格的测试与版本控制。我们不必担心jar版本合适度问题。
- spring-boot-dependencies里面定义了jar包的版本
入口类和@SpringBootApplication
- 程序从main方法开始运行
- 使用SpringApplication.run()加载主程序类
- 主程序类需要标注@SpringBootApplication
- @EnableAutoConfiguration是核心注解;
- @Import导入所有的自动配置场景
- @AutoConfigurationPackage定义默认的包扫描规则
- 程序启动扫描加载主程序类所在的包以及下面所有子包的组件;
SpringBoot热部署插件
Spring为开发者提供了一个名为spring-boot-devtools的模块来使Spring Boot应用支持热部署,提高开发者的开发效率,无需手动重启Spring Boot应用
<!-- 如果要使用devtools springboot的父项目可能需要在1.5.9.RELEASE后1.3.0.RELEASE之前是不能使用的 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
注意:
如果要使用springboot热部署,就必须设置以下内容:Project –> Build Automatically 要选中,不选中的话不起作用。
热部署使用说明:
1、devtools可以实现页面热部署(即页面修改后会立即生效,这个可以直接在application.properties文件中配置spring.thymeleaf.cache=false来实现),实现类文件热部署(类文件修改后不会立即生效),实现对属性文件的热部署。
即devtools会监听classpath下的文件变动,并且会立即重启应用(发生在保存时机),注意:因为其采用的虚拟机机制,该项重启是很快的
2、配置了后在修改java文件后也就支持了热启动,不过这种方式是属于项目重启(速度比较快的项目重启),会清空session中的值,也就是如果有用户登陆的话,项目重启后需要重新登陆。
3、默认情况下,/META-INF/maven,/META-INF/resources,/resources,/static,/templates,/public这些文件夹下的文件修改不会使应用重启,但是会重新加载(devtools内嵌了一个LiveReload server,当资源发生改变时,浏览器刷新)。devtools的配置
4、在application.properties中配置spring.devtools.restart.enabled=false,此时restart类加载器还会初始化,但不会监视文件更新。在SprintApplication.run之前调用System.setProperty(“spring.devtools.restart.enabled”, “false”);可以完全关闭重启支持,配置内容:
#热部署生效
spring.devtools.restart.enabled=true
#设置重启的目录
#spring.devtools.restart.additional-paths: src/main/java
#classpath目录下的WEB-INF文件夹内容修改不重启
spring.devtools.restart.exclude=WEB-INF/**
SpringBoot整合jsp
使用外部Servlet容器
1、SpringBootServletInitializer
- 重写configure
2、SpringApplicationBuilder
- builder.source(@SpringBootApplication类)
3、启动原理
- Servlet3.0标准ServletContainerInitializer扫描所有jar包中META-INF/services/javax.servlet.ServletContainerInitializer文件指定的类并加载
- 加载spring web包下的SpringServletContainerInitializer
- 扫描@HandleType(WebApplicationInitializer)
- 加载SpringBootServletInitializer并运行onStartup方法
- 加载@SpringBootApplication主类,启动容器等
1、配置maven依赖
<dependencies>
<!-- web项目启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 最需注意的如下这个依赖,少了这一个不能使用jsp -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<!-- tomcat启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- JSTL标签 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<!-- springboot测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2、主程序入口
@SpringBootApplication
@EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
3、通过SpringBootServletInitializer加载servlet容器
public class ServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}
4、配置application.properties文件
# 端口号
server.port=7070
# 视图解析器必须以"/"结尾,否则找不到对应的jsp文件
spring.view.prefix=/WEB-INF/views/
spring.view.suffix=.jsp
## springboot 新版本对应的配置改为:
#spring.mvc.view.prefix=/WEB-INF/views/
#spring.mvc.view.suffix=.jsp
5、编写springmvc控制器
@Controller
public class WelcomeController {
@RequestMapping("/welcome")
public String test(Model model) {
model.addAttribute("msg", "你好");
return "success";
}
}
6、在WEB-INF目录下创建views文件夹
<body>
<h2>SUCCESS</h2>
${msg}
</body>
SpringBoot整合MyBatis
1、添加mybatis启动器
<!-- jdbc启动器 -->
<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.1</version>
</dependency>
<!-- mysql 驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--引入druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.8</version>
</dependency>
2、配置application.properties文件
# jdbc配置
spring.datasource.url=jdbc:mysql://192.168.41.10:3306/test
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=znsd_test
spring.datasource.password=123456
#mybatis.config-locations=classpath:mybatis/mybatis-config.xml
mybatis.mapper-locations=classpath:mybatis-mapping/*.xml
mybatis.type-aliases-package=com.znsd.springboot.mybatis.entity
3、创建UserDao接口
//通过@Mapper注解或者@MapperScan("com.znsd.springboot.mybatis.dao")
public interface UserDao {
public List<User> select(User user);
}
4、在mybatis-mapping目录下创建UserDao.xml配置文件
<mapper namespace="com.znsd.springboot.mybatis.dao.UserDao">
<select id="select" resultType="com.znsd.springboot.mybatis.entity.User" parameterType="com.znsd.springboot.mybatis.entity.User">
select * from t_user
</select>
</mapper>
5、springboot入口程序
@SpringBootApplication
@EnableAutoConfiguration
// mybatis接口扫描
@MapperScan("com.znsd.springboot.mybatis.dao")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
6、测试获取数据
Spring Boot 整合 Eureka + Feign
Eureka简介
Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务。Spring Cloud将它集成在其子项目springcloud-
netflix中,以实现Spring Cloud的服务发现功能。可用于定位运行在AWS域中的中间层服务,以达到负载均
衡和中间层服务故障转移的目的。
创建Eureka服务端
步骤
- 创建maven项目
- 配置依赖
- 写程序入口
- 配置application.properties文件
- 启动服务
创建maven项目加入Eureka依赖
1、配置Spring Cloud依赖
<!-- Spring Cloud支撑包 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>Brixton.SR3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
2、配置Eureka依赖
<!-- Eureka依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<!-- eureka服务依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
3、配置web依赖
<!--web项目依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
4、插件配置
<build>
<!-- 打包项目名称 -->
<finalName>springboot-eureka-server</finalName>
<!-- 打包插件 -->
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
主程序入口
1、编写主程序
// 开启eureka服务注册中心
@EnableEurekaServer
// 表示为springboot应用程序
@SpringBootApplication
public class EurekaRegisterCenterApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaRegisterCenterApplication.class, args);
}
}
2、配置application.properties文件
#端口
server.port=7070
#应用名称
spring.application.name= server‐01
#实例所在地址
eureka.instance.hostname=localhost
#是设置eureka服务器所在的地址,查询服务和注册服务都需要依赖这个地址
eureka.client.serviceUrl.defaultZone=http://localhost:7070/eureka/
#registerWithEureka表示是否注册自身到eureka服务器,因为当前这个应用就是eureka服务器,没必要注册自身,所以这里是false
eureka.client.registerWithEureka=false
#fetchRegistry表示是否从eureka服务器获取注册信息
eureka.client.fetchRegistry=false
3、启动Eureka服务,Eureka启动方式和Spring Boot一致,直接运行EurekaRegisterCenterApplication中的main方法即可启动Eureka服务,在浏览器输入http:// IP地址:端口/,可以访问Eureka服务页面,我这里是ip地址是localhost,端口号配置的是7070,所以访问地址为http://127.0.0.1:7070/
创建Eureka服务提供者客户端
创建Eureka服务提供方
步骤
- 创建maven项目
- 配置依赖
- 写客户端入口
- 配置application.properties文件
- 启动服务提供者客户端
创建maven项目加入Eureka依赖
1、配置Spring Cloud依赖
<!-- Spring Cloud支撑包 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>Brixton.SR3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
2、配置Eureka依赖
<!-- 配置Eureka依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
3、配置web依赖
<!-- 配置web依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
4、插件配置
<!-- 插件包 -->
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
编写服务提供者主程序
1、主程序入口
//开启Spring Boot
@SpringBootApplication
//开启Eureka配置,将此服务注册到eureka注册中心
@EnableEurekaClient
// rest控制器
@RestController
public class UserServiceApplication {
@RequestMapping("/say")
public String say() {
return "hello world!!";
}
public static void main(String[] args) {
new SpringApplicationBuilder(UserServiceApplication.class).web(true).run(args);
}
}
2、配置application.properties文件
#端口
server.port=7071
## 项目名称
server.context-path=/userServer
#服务名称
spring.application.name=userserver
#是设置Eureka地址,服务启动将注册到这个Eureka上面
eureka.client.serviceUrl.defaultZone=http://localhost:7070/eureka/
#实例名称在Eureka上面可以看到
eureka.instance.appname=userServer
3、启动Eureka服务提供者客户端
Eureka客户端启动方式和Spring Boot一致,启动后客户端服务就可以注册到Eureka上。可以参考服务端图片。注意:
起客户端之前先启动Eureka服务
Feign简介
Feign是简化Java HTTP客户端开发的工具(java-to-httpclient-binder),它的灵感来自于Retrofit、JAXRS-2.0和
WebSocket。Feign的初衷是降低统一绑定Denominator到HTTP API的复杂度,不区分是否为restful。
创建Feign客户端消费者步骤
- 创建maven项目
- 配置依赖
- 写客户端入口
- 写服务接口
- 写接口调用类
- 配置application.properties文件
- 启动Feign客户端
创建maven项目配置依赖
1、在Eureka客户端的基础上加上Feign依赖即可
<!-- Feign依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
2、服务接口调用定义
// 交给spring ioc容器
@Component
// springboot-eureka-server-provider项目中的application.properties文件中spring.application.name的值
//参数根据被调用的“spring.application.name=userserver”配置而来
@FeignClient("userserver")
public interface ConsumerService {
/**
* /userServer=服务器共者项目中定义的项目名称(server.context-path)
* /say=服务提供者项目中的UserServiceApplication类中的@RequestMapping("/say")值
* 注意:接口申明必须和被调用接口保持一致(地址、接口名、参数、 返回值)
* @return
*/
@RequestMapping("/userServer/say")
public String say();
}
3、将ConsumerService注入给UserController通过feign调用服务提供者的接口方法
@RestController
public class UserController {
@Autowired
private ConsumerService consumerService;
@RequestMapping("/testCallProviderByFeign")
public String testCallProviderByFeign() {
System.out.println("UserController.testCallProviderByFeign()");
// 调用服务提供者的方法获取结果
String result = this.consumerService.say();
System.out.println("获取服务提供者的结果:" + result);
return result;
}
}
4、配置application.properties文件
#端口
server.port=7072
#服务地址
server.contextPath=/consumer
#服务名称
spring.application.name=consumerserver
#是设置Eureka地址,服务启动将注册到这个Eureka上
eureka.client.serviceUrl.defaultZone=http://localhost:7070/eureka/
#实例名称在Eureka上面可以看到
eureka.instance.appname=consumerserver
编写客户端启动程序入口
//开启Spring Boot
@SpringBootApplication
//开启Eureka配置
@EnableEurekaClient
//开启Feign
@EnableFeignClients
//rest控制器
@RestController
public class ConsumerApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(ConsumerApplication.class).web(true).run(args);
}
}
启动Feign客户端
Eureka客户端启动方式和Spring Boot一致,启动后Feign客户端服务就可以注册到Eureka上。
测试发送请求
消费项目中的application.properties配置文件中的端口号=7072项目名=/consumer,所以请求地址为http://127.0.0.1:7072/consumer/testCallProviderByFeign