微服务阶段
javase:OOP
mysql:持久化
html + css + jquery + 框架:视图,框架不熟练,css不好
javaweb:独立开发MVC三层架构的网站了:原始
ssm:框架:- 简化了我们的开发流程,配置也开始较为复杂;
war:tomcat运行
spring再简化:SpringBoot-jar:内嵌tomcat;微服务架构!
服务越来越多:springcloud
spring boot 核心:自动装配
- 是什么
- 配置如何编写yaml
- 自动装配原理:重要:谈资
- 集成web开发:业务的核心
- 集成数据库Druid
- 分布式开发:Dubbo(RPC) + zookeeper
- swagger:接口文档
- 任务调度
- SpringSecurity/shiro
SpringCloud
- 微服务
- spring cloud入门
- Restful
- Eureka
- Ribbon
- Feign
- HyStrix
- Zuul路由网关
- SpringCloud config:git
新服务架构:服务网格!
约定大于配置
第一个Spring boot程序
- jdk1.8
- maven 3.6.1
- springboot:最新版
- IDEA
官方:提供了一个快速生成的网站!IDEA集成了这个网站!
- 可以在官网直接下载后,导入idea开发 https://start.spring.io/
- 直接使用idea创建一个springboot项目(一般开发直接在idea中创建)
彩蛋
-
banner.txt:https://www.bootschool.net/ascii-art/search
-
server.port=8085
原理初探
自动配置:
pom.xml
- spring-boot-dependencies:核心依赖在父工程中
- 我们在写或者引入一些Springboot依赖的时候,不需要指定版本,就因为有这些版本仓库
启动器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
- 启动器:说白了,就是Springboot的启动场景;
- 比如spring-boot-starter-web,就会帮我们自动导入web环境所有依赖!
- springboot会将所有的功能场景,都变成一个个的启动器
- 如果我们要使用什么功能,就只需要找到对应的启动器就可以了 starter
主程序
//@SpringBootApplication 标注这个类是一个springboot的应用: 启动类下的所有资源被导入
@SpringBootApplication
public class Springboot01HelloworldApplication {
public static void main(String[] args) {
//将springboot应用启动
SpringApplication.run(Springboot01HelloworldApplication.class, args);
}
}
-
注解:
@SpringBootConfiguration : springboot的配置 @Configuration: spring配置类 @Component:说明这也是一个spring的注解 @EnableAutoConfiguration:自动配置 @AutoConfigurationPackage:自动配置包 @Import(AutoConfigurationPackages.Registrar.class):导入选择器 @Import(AutoConfigurationImportSelector.class):自动配置导入选择 //获取所有的配置 List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
获取候选的配置
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
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;
}
META-INF/spring.factories:自动配置的核心文件
结论:Springboot所有自动配置都是在启动的时候扫描并加载:spring.factories所有的自动配置类都在这里面,但是不一定生效,要判断条件是否成立,只要导入了对应的start,就有对应的启动器了,有了对应的启动器,我们自动装配就会生效,然后就配置成功!
- springboot在启动的时候,从类路径下META-INF/spring.factories获取指定的值;
- 将这些自动配置的类导入容器,自动配置就会生效,帮我们进行配置!
- 以前我们需要自动配置的东西,现在springboot帮我们做了
- 整合javaEE,解决方案和自动配置的东西都在spring-boot-autoconfigure-2.4.5.jar 这个包下
- 它会把所有需要导入的组件,以类名的方式返回,这些组件就会被添加到容器;
- 容器中也会存在非常多的xxxAutoConfiguration的文件,就是这些类给容器中导入了这个场景需要的所有组件;并自动配置,@Configuration,JavaConfig!
- 有了自动配置类,免去了我们手动编写配置文件的工作!
启动
SpringApplication
这个类主要做了4个事情
1. 推断应用的类型是普通的项目还是Web项目
2. 查找并加载所有可用初始化器,设置到initializers属性中
3. 找出所有的应用程序监听器,设置到listeners属性中
4. 推断并设置main方法的定义类,找到运行的类
执行run方法:
- headless系统属性设置
- 初始化监听器
- 启动已准备好的监听器
- 装配环境参数(yml和properties文件)
- 打印banner图案
- 上下文区域
- 准备上下文异常报告器
- 上下文前置处理
- 上下文刷新
JavaConfig @Configuration @Bean
Docker:进程
关于springboot,谈谈你的理解:
- 自动装配
- run()
全面接管SpringMvc的配置!实操!
SpringBoot的配置
#springboot这个配置文件中到底可以配置那些东西呢?
#
#官方的配置太多了
#
#了解原理:一通百通
-
application.yaml
- 语法结构:key: 空格 value
-
application.properties
- 语法结构:key=value
#普通的key-value
name: pfzhang
#对象
student:
name: pfzhang
age: 13
#行内写法
student1: {name: pfzhang, age: 3}
#数组
pets:
- cat
- dog
- pig
pets1: [cat,dog,pig]
1
Person.java
@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;
}
application.yaml
person:
name: pfzhang
age: 3
happy: false
birth: 2019/11/12
maps: {k1: v1,k2: v2}
lists:
- code
- music
- gitl
dog:
name: pfzhangwang
age: 15
2
Person.java
@Component
//@ConfigurationProperties(prefix = "person")
//加载指定的配置文件
@PropertySource(value = "classpath:pfzhang.properties")
public class Person {
//SPEL表达式取出配置文件的值
@Value("${name}")
private String name;
private Integer age;
private Boolean happy;
private Date birth;
private Map<String, Object> maps;
private List<Object> lists;
private Dog dog;
}
pfzhang.properties
name=pfzhang
占位符:
r a n d o m . u u i d , {random.uuid}, random.uuid,{person.do:www}
松散绑定
yml文件中写last-name,类中lastName是一样的
JSR303校验
在字段增加一层过滤器验证,可以保证数据的合法性
@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;
}
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.7.Final</version>
</dependency>
SpringBoot Web开发
jar: webapp!
自动装配
springboot 到底帮我们配置了什么? 我们能不能进行修改?能修改哪些东西?能不能扩展?
- xxxxAutoConfiguation: 向容器中自动配置组件
- xxxxProperties:自动配置类,装配配置文件自定义的一些内容!
要解决的问题:
- 导入静态资源
- 首页
- jsp,模板引擎 Thymeleaf
- 装配扩展SpringMVC
- 增删改查
- 拦截器
- 国际化
静态资源
WebMvcAutoConfiguration.java
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
ServletContext servletContext = getServletContext();
addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (servletContext != null) {
registration.addResourceLocations(new ServletContextResource(servletContext, SERVLET_LOCATION));
}
});
总结:
- 在Spring boot ,我们可以使用以下方式处理静态资源
- webjars http://localhost:8080/webjars/
- public, static, /** , resources http://localhost:8080/
- 优先级:resources > static(默认) > public
首页如何定制?
模板引擎
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
结论:
只需要使用thymeleaf,导入对应的依赖就可以了!我们将html放在我们的templates目录下即可!
Spring MVC装配
文档地址:https://docs.spring.io/spring-boot/docs/
https://docs.spring.io/spring-boot/docs/2.1.6.RELEASE/reference/html/boot-features-developing-web-applications.html#boot-features-spring-mvc
获取所有的视图解析器
ContentNegotiatingViewResolver
public View resolveViewName(String viewName, Locale locale) throws Exception {
RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes");
List<MediaType> requestedMediaTypes = getMediaTypes(((ServletRequestAttributes) attrs).getRequest());
if (requestedMediaTypes != null) {
List<View> candidateViews = getCandidateViews(viewName, locale, requestedMediaTypes);
View bestView = getBestView(candidateViews, requestedMediaTypes, attrs);
if (bestView != null) {
return bestView;
}
}
String mediaTypeInfo = logger.isDebugEnabled() && requestedMediaTypes != null ?
" given " + requestedMediaTypes.toString() : "";
if (this.useNotAcceptableStatusCode) {
if (logger.isDebugEnabled()) {
logger.debug("Using 406 NOT_ACCEPTABLE" + mediaTypeInfo);
}
return NOT_ACCEPTABLE_VIEW;
}
else {
logger.debug("View remains unresolved" + mediaTypeInfo);
return null;
}
}
public interface ViewResolver {
@Nullable
View resolveViewName(String viewName, Locale locale) throws Exception;
}
private List<View> getCandidateViews(String viewName, Locale locale, List<MediaType> requestedMediaTypes)
throws Exception {
List<View> candidateViews = new ArrayList<>();
if (this.viewResolvers != null) {
Assert.state(this.contentNegotiationManager != null, "No ContentNegotiationManager set");
for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
candidateViews.add(view);
}
for (MediaType requestedMediaType : requestedMediaTypes) {
List<String> extensions = this.contentNegotiationManager.resolveFileExtensions(requestedMediaType);
for (String extension : extensions) {
String viewNameWithExtension = viewName + '.' + extension;
view = viewResolver.resolveViewName(viewNameWithExtension, locale);
if (view != null) {
candidateViews.add(view);
}
}
}
}
}
if (!CollectionUtils.isEmpty(this.defaultViews)) {
candidateViews.addAll(this.defaultViews);
}
return candidateViews;
}
If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own @Configuration
class of type WebMvcConfigurer
but without @EnableWebMvc
. If you wish to provide custom instances of RequestMappingHandlerMapping
, RequestMappingHandlerAdapter
, or ExceptionHandlerExceptionResolver
, you can declare a WebMvcRegistrationsAdapter
instance to provide such components.
//如果,你想自己diy一些定制化的功能,只要写这个组件,然后将它交给springboot ,boot会帮我们自动装配
//如果我们要扩展springmvc,官方建议我们这么做
//扩展spring mvc dispatchservlet
@Configuration
#@EnableWebMvc //导入了一个类:DelegatingWebMvcConfiguration 从容器中获取所有的webmvcconfig;
public class MyMvcConfig implements WebMvcConfigurer {
//public interface ViewResolver 实现了视图解析器接口的类,我们就可以把它看作视图解析器
@Bean
public ViewResolver myViewResolver() {
return new MyViewResolver();
}
//视图跳转
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/pfzhang").setViewName("test");
}
//自定义了一个自己的视图解析器MyViewResolver
public static class MyViewResolver implements ViewResolver {
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
return null;
}
}
}
在springboot中,有非常多的xxxConfiguration帮我们进行扩展配置,只要看见了这个东西,我们就要注意了!
public ViewResolver myViewResolver() {
return new MyViewResolver();
}
//视图跳转
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/pfzhang").setViewName("test");
}
//自定义了一个自己的视图解析器MyViewResolver
public static class MyViewResolver implements ViewResolver {
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
return null;
}
}
}
在springboot中,有非常多的xxxConfiguration帮我们进行扩展配置,只要看见了这个东西,我们就要注意了!