Part1:SpringBoot原理(本质上就是Spring,通过自己的特性帮我们简化了Spring的开发(或者说帮我们简化了ssm下的配置文件))三个核心特性(要是面试等让谈一下springboot的理解,就从自动装配和run()方法两个方面谈
)
springboot所有的自动配置都在启动类中启动的时候被扫描并加载
,加载进来其实指的就是扫描了一个META-INF下的spring.factories(所有的自动配置类都在这里面)
。
但是不一定被扫面进来的都生效,生不生效要看条件@ConditionalOnXxx里面的条件是否成立,只要导入了对应的start(中的坐标)就有对应的启动器了,有了启动器对应的自动装配就会生效,然后就配置成功了
//通过@SpringBootApplication这个写在类上的注解开启组件扫描和自动配置。标记这个类是一个springboot应用
//@SpringBootApplication(呼应到SSM中)是SSM中三个注解的结合体
@SpringBootApplication
public class XXXXXApplication {
public static void main(String[] args) {
//通过SpringApplication.run(......)引导应用程序启动,**启动run()方法相当于开启了一个服务**
SpringApplication.run(XXXXXApplication.class, args);//:run()方法有两个参数,命令行参数以及当前这个类
}
}
SpringBoot的自动配置就是通过注解或者一些简单的配置就能在 Spring Boot 的帮助下实现某块功能
SpringBoot 定义了一套接口规范,这套规范规定:SpringBoot 在启动时会扫描外部引用 jar 包中的META-INF/spring.factories文件,将文件中配置的类型信息加载到 Spring 容器,并执行类中定义的各种操作。对于外部 jar 来说,只需要按照 SpringBoot 定义的标准,就能将自己的功能装置进 SpringBoot
。】,@SpringBootConfiguration
:组合了或者说底层就是 @Configuration 注解,实现配置文件的功能【你点进@SpringBootConfiguration的源码,里面其实就是@Configuration】。表示这个被@SpringBootConfiguration注解的类是一个配置类,这个类里面是可以直接写bean的。@bean...
@EnableAutoConfiguration的底层包含@AutoConfigurationPackage和@Import注解两部分。@Import注解用来导入一些会被Spring创建并加载到IOC容器中的配置类,也就是动态启动或者说某些功能【打开自动配置的功能,也可以关闭某个自动配置的选项**,如**关闭数据源自动配置功能: @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })**】,实际上@Import注解就加载导入了一个AutoConfigurationImportSelector.class ,然后调用这个类的的 selectImports方法获取一个全面的常用 BeanConfiguration 列表
。【打开自动配置的功能,也可以关闭某个自动配置的选项,如关闭数据源自动配置功能: @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
。】EnableAutoConfiguration 只是一个简单地注解,自动装配核心功能的实现实际是通过 AutoConfigurationImportSelector类
。】:点进这个AutoConfigurationImportSelector.class就可以看到下面几部分:selectImports方法主要用于获取所有符合条件的类的全限定类名,这些所有符合条件的类的全限定类名对应的类需要被加载到 IoC 容器中
。】:private static final String[] NO_IMPORTS = new String[0];
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// <1>.判断自动装配开关是否打开
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
//<2>.获取所有需要装配的bean
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
getAutoConfigurationEntry()方法主要负责加载自动配置类的
。获取需要自动装配的所有配置类,读取META-INF/spring.factories
:spring-boot/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories所有 Spring Boot Starter 下的META-INF/spring.factories都会被读取到
。不是每次启动都要全部加载
。因为,这一步有经历了一遍筛选,@ConditionalOnXXX 中的所有条件都满足,该类才会生效
。@Configuration
// 检查相关的类:RabbitTemplate 和 Channel是否存在
// 存在才会加载
@ConditionalOnClass({ RabbitTemplate.class, Channel.class })
@EnableConfigurationProperties(RabbitProperties.class)
@Import(RabbitAnnotationDrivenConfiguration.class)
public class RabbitAutoConfiguration {
}
spring-boot-autoconfigure.jar 下面的spring.factories
,获取到所有的 Spring 相关的 Bean 的全限定名 ClassName
SpringBoot是如何知道要创建哪个Bean的?比如SpringBoot是如何知道要创RedisTemplate的?咱们学了启动器后知道是咱们导入了redis的start启动依赖,然后springboot就帮咱们创建了RedisTemplate。如果我不导入这个redis的start启动依赖,springboot会不会帮咱们创建了RedisTemplate,springboot怎么知道导没导这些启动依赖呢
//通过@SpringBootApplication这个写在类上的注解开启组件扫描和自动配置,标记这个类是一个springboot应用
@SpringBootApplication
public class XXXXXApplication {
public static void main(String[] args) {
//通过SpringApplication.run(......)引导应用程序启动
SpringApplication.run(XXXXXApplication.class, args);
}
}
里面的SpringApplication.run(XXXXXApplication.class, args);方法如下:
<dependencies>
<!--SpringBoot整合Web功能依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--SpringBoot整合Actuator功能依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--SpringBoot整合AOP功能依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!--SpringBoot整合测试功能依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--SpringBoot整合注解处理功能依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!--SpringBoot整合Spring Security安全功能依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--SpringBoot整合Redis数据存储功能依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--SpringBoot整合Elasticsearch数据存储功能依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<!--SpringBoot整合MongoDB数据存储功能依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<!--SpringBoot整合AMQP消息队列功能依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!--SpringBoot整合Quartz定时任务功能依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<!--SpringBoot整合JPA数据存储功能依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!--SpringBoot整合邮件发送功能依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
</dependencies>
第三方起步依赖:
<dependencies>
<!--SpringBoot整合MyBatis数据存储功能依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-version.version}</version>
</dependency>
<!--SpringBoot整合PageHelper分页功能依赖-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>${pagehelper-starter.version}</version>
</dependency>
<!--SpringBoot整合Druid数据库连接池功能依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
</dependency>
<!--SpringBoot整合Springfox的Swagger API文档功能依赖-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>${springfox-version}</version>
</dependency>
<!--SpringBoot整合MyBatis-Plus数据存储功能依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus-version}</version>
</dependency>
<!--SpringBoot整合Knife4j API文档功能依赖-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>${knife4j-version}</version>
</dependency>
</dependencies>
比如要使用Mysql数据库进行存储,用Swagger生成API文档,添加如下起步依赖即可
<dependencies>
<!--SpringBoot Web功能起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--MyBatis分页插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.10</version>
</dependency>
<!--集成druid连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!--Mysql数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>
<!--springfox swagger官方Starter-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
</dependencies>
也可以用Maven的方式来排除不想要的依赖。比如不想使用tomcat容器、想使用undertow容器
<dependencies>
<!--SpringBoot Web功能起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!--排除tomcat依赖-->
<exclusion>
<artifactId>spring-boot-starter-tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<!--undertow容器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
</dependencies>
即使在前端对数据进行校验的情况下,我们还是要对传入后端的数据再进行一遍校验,避免用户绕过浏览器直接通过一些 HTTP 工具直接向后端请求一些违法数据
。JSR(Java Specification Requests) 是一套 JavaBean 参数校验的标准
,它定义了很多常用的校验注解【所有的注解,推荐使用 JSR 注解,即javax.validation.constraints,而不是org.hibernate.validator.constraints】,我们可以直接将这些注解加在我们 JavaBean 的属性上面,这样就可以在需要校验的时候进行校验了,非常方便!
我们在需要验证的参数上加上了@Valid注解
,如果验证失败,它将抛出MethodArgumentNotValidException。不要忘记在类上加上 @Validated 注解了,这个参数可以告诉 Spring 去校验方法参数。
合法名称:logback.xml 、logback-spring.xml
//...
private Logger logger = LoggerFactory.getLogger(TestController.class);
...
logger,info(....);
SpringBoot自带监控功能Actuator
,可以帮助实现对程序内部运行情况监控,比如监控状况、Bean加载情况、配置属性日志信息等。【相较传统的 Spring 框架,Spring Boot 的一大亮点是引入了内置的监控机制,这是通过 Actuator 组件(常见的包括内存信息、JVM 信息、垃圾回收信息等)来实现的
。基于 Actuator 组件,一方面我们可以查看包含自动配置在内的应用程序详细信息,另一方面可以实时监控该应用程序的运行时健康状态。】SpringBoot提供了两个接口来实现Spring容器启动完成后执行的功能,两个接口分别为CommandLineRunner和ApplicationRunner【Spring应用启动过程中,肯定是要自动扫描有@Component那四个兄弟注解的类,加载类并初始化对象进行自动注入。加载类时首先要执行static静态代码块中的代码,之后再初始化对象时会执行构造方法。在对象注入完成后,调用带有@PostConstruct注解的方法。当容器启动成功后,再根据@Order注解的顺序调用CommandLineRunner和ApplicationRunner接口类中的run方法。】
可以去实现Spring的ApplicationRunner与CommandLineRunner接口去实现启动后运行的功能
。
这个被PostConstruct注解的方法在对象依赖注入初始化之后执行
。SpringBoot提供了两个接口来实现Spring容器启动完成后执行的功能,两个接口分别为CommandLineRunner和ApplicationRunner【这两个接口需要实现一个run方法,将代码在run中实现即可。这两个接口功能基本一致,其区别在于run方法的入参。ApplicationRunner的run方法入参为ApplicationArguments,而CommandLineRunner的run方法入参为String数组。】
当有多个类实现了CommandLineRunner和ApplicationRunner接口时,可以通过在类上添加@Order注解来设定运行顺序
。PART2:SpringBoot实战
WebMvcAutoConfiguration.java配置类中的这个方法:private void addResourceHandler(…)//这个方法不就是关于添加静态资源的
@Override
public void addResourcesHandlers(ResourceHandlerRegistry registry){
//如果静态资源已经被自定义(自定义就是指咱们在yml重新配置了spring.factories中的写的xxxAutoConfiguration配置类中的利用注解@EnableConfigurationProperties加载进来的xxxProperties配置文件中的属性们),那么在日志中打印这样一句话,然后直接return,如果你重新在yml说明默认值失效,这整个过程在日志中记录下来
if(!this.resourceProperties.isAddMappings()){
logger.debug("Default resource handling disabled");
return;
}
//导入静态资源的方式1
addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");//只要是/webjars/***这种形状的信息,都去classpath/......下面去找;这是啥意思呢,就是原来咱们是导jar的方式(导maven坐标)的方式,现在springboot帮咱们通过webjars的方式帮咱们导入
//导入静态资源的方式2
addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocation());//添加注册
if(this.servletContext != null){
ServletContextResource resource = new ServletContextResource(this.servletContext, SERVLET_LOCATION);
registration.addResourceLocations(resource);
}
});
}
this.resourceProperties.getStaticLocation()//静态资源的目录
在之前SSM中我们整合Redis,要先导入对应Redis对应的依赖坐标,然后要写一大堆配置,比如Redis的连接信息参数,还得需要在配置里面提供一个RedisTemplate模板对象。【我感觉和之前咱们写的工具类差不多】我们需要操作Redis时就先注入RedisTemplate模板对象,然后调用里面封装好的方法直接进行操作就行
。但是,Spring Boot 中,我们直接引入一个 starter 即可。比如你想要在项目中使用 redis 的话,直接在项目中引入对应的 starter 即可。引入 starter 之后,我们通过少量注解和一些简单的配置就能使用第三方组件提供的功能了
。】
支持两种方式部署到服务器
:
是基于SpringBoot的一套微服务解决方案(包含很多东西服务注册与发现、配置中心、服务网关等)(用于将springboot开发的一个又一个单体(也就是jar包)微服务整合并管理起来,为各个微服务直接提供解决那四个问题的集成服务)
。它利用 Spring Boot 的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用 Spring Boot 的开发风格做到一键启动和部署。Spring Cloud 是为了解决微服务架构中服务治理而提供的一系列功能的开发框架,并且 Spring Cloud 是完全基于 Spring Boot 而开发,Spring Cloud 利用 Spring Boot 特性整合了开源行业中优秀的组件,整体对外提供了一套在微服务架构中服务治理的解决方案。巨人的肩膀:
https://www.bilibili.com/video/BV1PE411i7CV?p=60
https://www.javalearn.cn/
moon聊技术
苏三说技术(有一个很好的自定义starter的例子,可以关注,然后搜搜看)
Java基基老师的关于Jenkins+docker+springboot 一键自动化部署 SpringBoot 项目,步骤很齐全