微服务阶段
我们的学习历程
javase:oop
mysql:持久化
html+css+js+jquery+框架:视图,框架不熟练,css不好
javaweb:独立开发MVC架构的网站:原始
ssm:框架:简化了我们的开发流程
打包出来是:war:tomcat运行
Spring再简化:SpringBoot-jar:内嵌tomcat; 微服务架构!
服务越来越多:SpringCloud;
问题总结
- org.springframework.core.annotation.AnnotationConfigurationException: Attribute proxyBeanMethods in annotation 应该是jar包的版本与其他依赖包版本不一致,解决方法是更换版本号
- java类必须要有无参构造函数才能实现自动装配,否则会报错运行不了。
- 问题:src外的config文件夹没有加载到target目录下所以下面的配置文件无法被识别
解决:项目要作为单独的project,而不能作为一个module - springboot版本问题,旧的favicon头像设置方式不生效
将favicon.ico放入资源文件夹中,然后在index欢迎页面引入下列语句
link rel=icon href=favicon.ico type=image/x-icon/ - 用自定义的视图解析器,自定义的国际化视图解析器的方法名必须是 localeResolver。
- 关于restful风格传参
th:href=@{/emp/{id}(id={emp.getId()})}
th:href=@{/emp/+${emp.getId()}}
SpringBoot
Spring视为了解决企业级应用开发的复杂性而创建的,简化开发,
Spring如何简化java开发
为了降低java开发的复杂性,Spring采用了四种关键策略;
- 基于实体类的轻量级,最小入侵性变成;
- 通过ioc,依赖注入和面向接口实现松耦合
- 基于切面(AOP)和管理进行声明式变成;
- 通过切面和模版减少样式代码
什么是SpringBoot?
javaweb:Servlet+tomcat,后来是Struts,再后来是SpringMVC 到了现在的SpringBoot,过一两年还会出现新的前端框架,技术快速迭代,程序员需要不断学习,
新服务架构:服务网格,可能会干掉SpringBoot来完成新的微服务架构
老师,领导,项目经理:
- 培训讲师:
- 面向面试培训,教你如何使用,快速上手!
- 做教育的
- 如何学习新东西,如何持续学习,如何关注这个行业!
- 教你历史,来龙去脉,理论;积累谈资
30,经理
30:程序猿:淘汰!
java框架的迭代
SpringBoot其实就是javaweb开发框架,于SpringMVC类似,对比其他开发框架的 好处就是简化开发,约定大于配置,你只管训醒:you can just run 能够快速开发web应用,几行代码实现一个http接口
所有的技术框架的发展,都遵循这一个条主线规律,从复杂的应用场景,衍生出规范框架。人们在实际生产应用情况不断的精简,吸收设计精华,重构新的,更轻量级的框架,逐渐提升开发效率,之后开始提倡约定大于配置进而衍生一些一站式的解决方案,
j2EE --------> spring-------->springboot
随着发展,Spring涉及的领域越来越多,项目的整合开发需要配置大量的配置文件妈妈那么难的变得不那么易用简单,违背了最初的理念,甚至被人称为配置地狱,SpringBoot正是这样一个背景下被抽象出来的开发框架,目的就是为了让大家容易的使用Spring,更容易集合中间件和开源软件
Spring boot 基于Spring开发,boot本身并不提供Spring的核心特性以及拓展功能,只是用于快速的开发新一个基于SPRING框架的应用程序,也就是说,他并不是代替Spring的解决方案,而是和Spring框架紧密结合用于提升,Spring开发者的体验工具。Springboot**约定大于配置的核心思想,默认帮我们进行了很多的设置,多数的SpringBoot应用很少的Spring配置,同时集成了大量常用的第三方库配置,几乎所有的第三方库都是开箱即用。
**SpringBoot主要优点:
- 为了所有Spring开发这更快入门
- 开箱即用,提供各种默认配置简化项目配置
- 内嵌式容器简化web项目
- 没有冗余代码和xml的配置要求
约定大于配置:maven------>spring------->springMVC---->SpringBoot
正常的程序=数据结构+算法==》程序员---》i创造性角色
机构的程序=面向对象+框架 ==》码农--》会用别人的东西,干事
微服务
什么是微服务?
微服务是一个中架构风格,它要求我们在开发一个应用的时候,这个应用必须构建成一个系列小小服务的组合;可以通过http的方法进行互通。要说为微服务架构,先得说说我们以前的单体引用架构。
架构:MVC三层架构, MVVM ,微服务架构
业务:service:userService ===>模块!
SpringMVC,controller ===>提供接口!
单体应用架构
所谓单体引用(all in one)是指,我们将一个应用的中的所有应用的中的所有应用服务封装在一个应用中,无论是erp。crm或是其他系统,都吧数据库访问,web访问,等等功能方到一个war包内
- 好处是:易于开发测试,,部署起来十分方便,当需要拓展的时候,只需要将war复制多份,然后放在多个服务器上,在做负载均衡就可以
- 缺点是:单体应用架构的缺点是,哪怕我要修改非常小的地方,我都需要停掉整个服务,重新打包,部署这个应用war包,特别是对于一个大型应用,我们不可能吧所有的内容都放在一个应用里,我们如何维护,如何分工都是问题
微服务架构
all in one 的架构方式没我们把所有的功能单元放在一个应用里面。整个应用部署在服务器上,如果负载能力不行,我们将整个应用水平赋值,进行扩展,之后负载均衡
所谓微服务架构,就是打破之前的all in one的架构方式,把每个功能元素独立出来,把独立出来的功能元素动态组合,需要的功能元素才组合在一起,需要时间多一些,可以整合多个功能的元素。所以微服务架构是对功能元素进行复制,
好处:
- 节省,调用资源
- 每个功能元素的服务都是一个可替换的可独立升级的软件代码,
详细阐述了什么是微服务:https://www.martinfowler.com/articles/microservices.html
中文版:https://www.cnblogs.com/liuning8023/p/4493156.html
http: rpc
用户下单: controller! 1000ms
消息队列:
仓库冻结:资金冻结,验证,购买成功,仓库数量减少,仓库解冻,资金解冻 10 s
如何构建微服务
一个大型系统的微服务架构,就像一个复杂交织,神经网络,每一个神经元就像是一个功能元素,它们各自完成自己的功能,然后通过http相互请求调用。比如一个电商系统,查缓存,连数据库,浏览页面,结账,支付等服务都是一个一个独立的功能服务,都被微化了,他们作为一个个微服务共同构建了一个庞大的系统,如果修改其中的一个功能,只需要更新升级其中一个功能服务单元即可。
但是这种庞大的系统架构给部署和运维带来很大的难度。于是,spring为我们带来了构建大型分布式微服务的全套、全程产品:
- 构建一个个功能独立的微服务应用单元,可以使用SpringBoot,可以帮助我们快速的构建一个应用;
- 大型分布式网络服务的调用,这部分由Springcloud来完成,实现分布式;
- 在分布式中间,进行流式数据计算,批处理,我们有spring cloud data flow。
- spring 为我们想清楚了整个从开始构建应用到大型分布式应用全流程方案
高内聚,低耦合,
面试:
8k-13k:软实力:聊天+举止+谈吐+见解
你主导面试官:13k:聊天30分钟
面试官主导你:8k
第一个SpringBoot程序
环境:
- jdk1.8
- maven 3.6.2
- SpringBoot最新版
- idea
官方提供了一个快速生成网站!idea集成了这个网站!
- 可以在官网直接下载,导入idea开发(官网在哪里)
- 直接使用idea创建一个SpringBoot项目(常用)
简单编写个controller类来看看如何运行的
package com.hyc.spring01helloworld.Controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller @RequestMapping("/hello") public class helloController { @GetMapping("/hello") @ResponseBody public String hello(){ return "hello"; } }
maven打包注意事项
utf-8报错:
<project.build.sourceEncoding> UTF-8 </project.build.sourceEncoding>
原理初探
自动装配:
pom.xml:
- Spring-boot-dependencies:核心依赖在父项目
- 我们在写或者引入一些Springboot依赖的时候,不需要指定版本,就应为这些版本仓库
启动器
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency>
- 启动器:就是Springboot的启动场景
- 比如:spring-boot-starter-web,他就会帮我们自动当如相关依赖
- springboot会将所有的功能场景,都变成一个个的启动器
- 我们要使用什么功能,就只需要找到对应的启动器就可以了
主程序:
@SpringBootApplication public class Spring01HelloworldApplication { public static void main(String[] args) { SpringApplication.run(Spring01HelloworldApplication.class, args); } }
注解:
@SpringBootConfiguration springboot的 配置 @Configuration spring配置类 @Component spring组件 @EnableAutoConfiguration 自动装配 @AutoConfigurationPackage:spring自动配置包 @Import({AutoConfigurationImportSelector.class}) 自动装配包 注册 @Import({Registrar.class}) 配置导入选择 //获取所有的配置 List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
获取候选的配置
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct."); return configurations; }
加载项目自动装配文件
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) { Map<String, List<String>> result = (Map)cache.get(classLoader); if (result != null) { return result; } else { HashMap result = new HashMap(); try { Enumeration urls = classLoader.getResources("META-INF/spring.factories"); while(urls.hasMoreElements()) { URL url = (URL)urls.nextElement(); UrlResource resource = new UrlResource(url); Properties properties = PropertiesLoaderUtils.loadProperties(resource); Iterator var6 = properties.entrySet().iterator(); while(var6.hasNext()) { Entry<?, ?> entry = (Entry)var6.next(); String factoryTypeName = ((String)entry.getKey()).trim(); String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue()); String[] var10 = factoryImplementationNames; int var11 = factoryImplementationNames.length; for(int var12 = 0; var12 < var11; ++var12) { String factoryImplementationName = var10[var12]; ((List)result.computeIfAbsent(factoryTypeName, (key) -> { return new ArrayList(); })).add(factoryImplementationName.trim()); } } } result.replaceAll((factoryType, implementations) -> { return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)); }); cache.put(classLoader, result); return result; } catch (IOException var14) { throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14); } } }
自动配置的核心文件
META-INF/spring.factories
加载到properties 中:
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
判断条件成立才自动装配
@ConditionalOnClass(Advice.class)
结论:springboot所有的自动配置都是在启动的时候扫描并加载:META-INF/spring.factories
所有的自动配置类都在这里面,但是不一定生效,判断条件是否成立,只要导入了对应的start,就有对应的启动器,有了启动器我们自动装配就会生效,然后就配置成功了!
执行原理图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TAuyWXVl-1648917634750)(https://gitee.com/cold-abyss_admin/my-image-host/raw/master/img/未命名文件 (1)].png)
- Springboot在启动的时候,从类路径下的META-INF/
spring.factories
获取指定的值; - 将这些自动配置的类导入容器,自动配置类就会生效,帮我们进行自动配置
- 以前我们需要自动配置的东西,现在只要符合条件Springboot帮我们做了
- 整合javaEE的解决方案和自动配置的东西都在spring-boot-autoconfigure-2.5.1.jar这个包下
- 它会把所有需要导入的组件,以类名的方式返回,这些组件就会被添加到容器;
- 容器中也会存在非常多的XXXXautoconfiguration的文件,就是这些类容器中导入了这个场景需要的所有组件并且自动配置,@Configuration
- 有了自动配置类,就免去了我们手动编写配置文件的工作,远离配置地狱!!!
run执行原理
run
开启服务
package com.hyc.spring01helloworld; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; //@SpringBootApplication 标注这个类是一个springboot的应用:启动类下的资源全部被导入 @SpringBootApplication public class Spring01HelloworldApplication { public static void main(String[] args) { SpringApplication.run(Spring01HelloworldApplication.class, args); } }
SpringBootApplication.run分析
主要是两个部分,一个是SpringBootApplication实例化,一个是run的执行
SpringBootApplication
执行的步骤:
- 推断应用类型是普通的java项目还是web项目
- 查找并加载所有可用的初始化器,设置到initializers实行中
- 找出所有的应用程序监听器,设置到listeners属性中
- 推断并且设置main方法定义类,找到运行的主类
查看构造器
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.sources = new LinkedHashSet(); this.bannerMode = Mode.CONSOLE; this.logStartupInfo = true; this.addCommandLineProperties = true; this.addConversionService = true; this.headless = true; this.registerShutdownHook = true; this.additionalProfiles = Collections.emptySet(); this.isCustomEnvironment = false; this.lazyInitialization = false; this.applicationContextFactory = ApplicationContextFactory.DEFAULT; this.applicationStartup = ApplicationStartup.DEFAULT; this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet(Arrays.asList(primarySources)); this.webApplicationType = WebApplicationType.deduceFromClasspath(); this.bootstrapRegistryInitializers = this.getBootstrapRegistryInitializersFromSpringFactories(); this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = this.deduceMainApplicationClass(); }
SpringBoot配置
- 官方配置太多,
- 如何配置tml
- 学习原理,一通百通
yml是什么?
YAML是"YAML Ain't a Markup Language"(YAML不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:"Yet Another Markup Language"(仍是一种标记语言),但为了强调这种语言以数据做为中心,而不是以标记语言为重点,而用反向缩略语重命名。
标记语言:
以前的配置文件,大多数都是用xml来配置,比如一个简单的端口配置,我们来对比下yaml和xml的区别
yml:
server: port: 8080
xml:
<server> <port>8080</port> </server>
yml:特点
- K:V
- 对空格的要求十分高
- 普通的key-value
- 可以注入到我们的配置类中
两种赋值方式
1.注解赋值
@Component public class Dog { @Value("郑文杰") private String name; @Value("3") private Integer age;
2.YML注入
实体类:
@Component @ConfigurationProperties(prefix = "person") public class person { private String name; private Integer age; private Boolean happy; private Date birth; private Map<String,Object> maps; private List<Object> lists; private Dog dog;
YML:
person: name: hyc age : 3 happy: false birth: 2019/11/02 maps: {k1: 123, k2: 456} lists: -code -music -girl dog: name: 旺财 age: 3
@ConfigurationProperties()作用:
将配置文件中每个属性的值,映射这个组件中;
告诉SpringBoot将奔雷所有的属性和配置文件中相关的配置进行绑定
参数perfix = “person” 将person组件(类)和yml中person的值对应绑定
@PropertySource
指定配置文件:properties文件
@PropertySource(value = "classpath:application.properties")
用@value
赋值
SpringBoot推荐我们用yml
对比:
应为yml十分灵活:
person: name: hyc age : ${random.int} happy: false birth: 2019/11/02 maps: {k1: 123, k2: 456} lists: -code -music -girl dog: name: 旺财 age: 3
java类
package com.hyc.pojo; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.PropertySource; import org.springframework.stereotype.Component; import org.springframework.validation.annotation.Validated; import javax.validation.constraints.Email; import java.util.Date; import java.util.List; import java.util.Map; @Component @ConfigurationProperties(prefix = "person") @Validated //数据校验 public class person { @Email(message = "邮箱格式错误") private String name; private Integer age; private Boolean happy; private Date birth; private Map<String,Object> maps; private List<Object> lists; private Dog dog; @Override public String toString() { return "person{" + "name='" + name + '\'' + ", age=" + age + ", happy=" + happy + ", birth=" + birth + ", maps=" + maps + ", lists=" + lists + ", dog=" + dog + '}'; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Boolean getHappy() { return happy; } public void setHappy(Boolean happy) { this.happy = happy; } public Date getBirth() { return birth; } public void setBirth(Date birth) { this.birth = birth; } public Map<String, Object> getMaps() { return maps; } public void setMaps(Map<String, Object> maps) { this.maps = maps; } public List<Object> getLists() { return lists; } public void setLists(List<Object> lists) { this.lists = lists; } public Dog getDog() { return dog; } public void setDog(Dog dog) { this.dog = dog; } }
jsr303校验注解:
@Validated //数据校验
校验示例:
java类:
@Component @ConfigurationProperties(prefix = "person") @Validated //数据校验 public class person { @Email(message = "邮箱格式错误") private String name; private Integer age; private Boolean happy; private Date birth; private Map<String,Object> maps; private List<Object> lists; private Dog dog;
YML:此时我们的name并不是邮箱格式
person: name: hyc age : ${random.int} happy: false birth: 2019/11/02 maps: {k1: 123, k2: 456} lists: -code -music -girl dog: name: 旺财 age: 3
执行效果:
使用了@Validated //数据校验注解的类可以对自己的属性设置格式数据校验
全部注解:
常用注解:
正则表达式:相对核心
源码位置:
小结:
学会找到源码位置,尝试自己阅读源码,探索过程才是成功学习的关键
SpringBoot配置文件优先级
官方给的执行优先级
多环境配置:
在真实工作中,我们会有很多配置文件,比如test,dev,等等,
格式:application-{什么类型的配置}.yml/properties
使用的:spring.profiles.active
properties:
主文件
#Springboot多环境配置,可以选择激活那个配置文件 spring.profiles.active=dev
可以有多个配置文件,从主文件选择使用什么开发环境
application-dev.properties 开发项目环境:
server.port=8081
application-test.properties 测试开发环境
server.port=8082
yml:
server: port: 8080 spring: profiles: active: dev --- server: port: 8081 spring: profiles:dev --- server: port: 8082 spring: profiles:test #配置文件到底可以写什么
再理解自动装配
SpringBoot使用一个全局配置文件,配置文件名字是固定的
- application.properties
- 语法结构:key=value
- application.yml
- 语法结构:key:空格 value
分析自动装配的原理:
- 启动的时候加载住配置类,开启了自动装配功能,
@EnableAutoConfiguration
@EnableAutoConfiguration
的作用:
- 利用AutoConfigurationImportSelector给容器导入组件,导入什么组件呢?
- 查看selectImports()方法的内容,他返回了一个autoConfigurationEntry,
getAutoConfigurationEntry
获取组件实体, - 通过
getCandidateConfigurations()
方法来加载候选配置, loadFactoryNames()
获取配置名字,从META-INF/spring.factories
这个配置文件中,加载全部配置存放到Properties中;返回封装好的结果,其中的加载参数就是EnableAutoConfiguration;
protected Class<?> getSpringFactoriesLoaderFactoryClass() { return EnableAutoConfiguration.class; }
- 过程描述就是,把
META-INF/spring.factories
把里面所有的EnableAutoConfiguration值加入到容器中
@ConditionalOn
SpringBoot有大量的配置,有的生效有的不生效,他通过这个注解来判断是否符合调减,符合条件就生效这个配置,我们可以通过自动装配注解来实现对应的自动装配。
如何配置的
在我们的配置文件中,能配置的东西都存在一个规律
他们一定会有个文件叫xxxProperties ,
- xxxProperties:绑定配置文件,@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
- xxxAutoConfiguration:自动装配默认值
- 我们就可以自定义配置了
如何看看我们的自动配置类是否生效
debug:true,在我们启动类之后会看到那些生效那些没生效,会以类似日志的方式输出
Positive matches:
已经自动装配并且生效的
negative matches:
没有生效的
总结:
- SpringBoot启动会加载大量的配置类,用来自动装配
- 如果我们要使用功能,要去查看功能是否在SpringBoot默认写好的自动装配类中
- 自动装配类中配置了很多组件,只要我们用的组件存在就不需要手动配置了
- 容器中自动配置类添加属性的时候,会从properties类中获取某些属性,我们只需要在配置文件中指定这些属性的值即可
- xxxProperties:绑定配置文件,封装配置文件中的相关属性
- xxxAutoConfiguration:自动装配类,给容器添加组件
SpringBoot 企业级简化开发(二)https://developer.aliyun.com/article/1469560