前言
开篇学习了 SpringBoot Helloworld 程序的编写,上手非常的快。现在来了解 SpringBoot 的自动配置特性以及 Configration 注解。
自动配置特性
上篇日志通过导入 spring-boot-web-starter ,它就会自动配置好 SpringMVC 以及相关的常用的组件,当然也包括我们常见的字符编码问题以及文件上传等等,这些都是默认配置好了的。但是只有在导入相关的 starter 的时候才会去加载相关的配置文件。
我们可以做一个测试,来查看 Spring MVC 相关的是如何自动配置的
package top.bestguo.helloworld;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ConfigurableApplicationContext;
@org.springframework.boot.autoconfigure.SpringBootApplication
public class SpringBootApplication {
public static void main(String[] args) {
// Spring IOC容器
ConfigurableApplicationContext run = SpringApplication.run(SpringBootApplication.class, args);
// 获取全部的 Bean 名字
String[] beanDefinitionNames = run.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
}
运行结果比较长。因为配置的加载项还是蛮多的。可以在你的控制台输出时。按下 Ctrl + F 搜索 Spring 整合 SpringMVC 相关的关键字,肯定能够找到相关的关键字。也就意味着这些都是自动配置了的:
- 前端控制器:DispathchServlet
- 视图解析器:ViewResolver
- 静态资源管理器:servlethandler
- 文件上传模块:Multipart
- 编码过滤模块:characterEncodingFilter
……
自动包扫描
SpringBoot 默认有一个自动包的扫描,无需自己配置。那不用配置它是怎么扫描的呢?它是这么规定的,就是只要 SpringBoot 的启动类在哪个目录下,那么和这个启动类的同级目录以及它的子目录,它都会去扫描。
请看下面的项目结构
E:.
└─top
└─bestguo
└─helloworld
| SpringBootApplication.java
│
└─controller
| HelloController.java
| DemoController.java
SpringBoot 下有一个同级的文件夹 controller,那么这个 controller 下的所有类都会被扫描到。前提是这些类中必须有标记 @Controller、@Service、@Repository 等这种可被 Spring 识别到的注解。
如果是这种目录结构,SpringBoot 主程序能够扫描到 WorldController 吗?显然这是扫描不到的。
E:.
└─top
└─bestguo
│ WorldController.java
│
└─helloworld
│ SpringBootApplication.java
│
└─controller
| HelloController.java
| DemoController.java
WorldController.java 代码如下
package top.bestguo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("/world")
public class WorldController {
@RequestMapping("/springboot2")
@ResponseBody
public String hello() {
return "你好, SpringBoot2!";
}
}
我们可以访问一下这个页面 http://localhost:8080/world/springboot2 ,发现报错了。
报错了就意味着,SpringBoot 主程序是扫描不到它的父文件夹里的内容的。如果要想然 SpringBoot 去让他直接访问父文件夹是行不通的,只能通过重新配置包扫描路径。
包扫描路径可以自己手动的来指定!
包扫描的路径设置成 “top.bestguo” 它就从这个位置开始扫描,扫描其子目录和孙目录即可,只需要在 SpringBootApplication 注解中传入一个参数,这个参数就是包扫描路径,即
@SpringBootApplication(scanBasePackages = “top.bestguo”)
package top.bestguo.helloworld;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ConfigurableApplicationContext;
@org.springframework.boot.autoconfigure.SpringBootApplication(scanBasePackages = "top.bestguo")
public class SpringBootApplication {
public static void main(String[] args) {
// Spring IOC容器
ConfigurableApplicationContext run = SpringApplication.run(SpringBootApplication.class, args);
// 获取全部的 Bean 名字
String[] beanDefinitionNames = run.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
}
然后我们重新访问一下看看,发现页面是可以正常访问了。
默认值
SpringBoot 中,这些配置文件中的绝大多数都有默认的设置。你可以使用默认的设置,也可以通过 application.properties 来对默认配置的值进行修改。
比如我们修改内嵌 Tomcat 的端口号,通过提示可以看到默认是 8080。我们可以将其设置成 8081。
还有上传文件大小,默认是 1MB ,我们可以设置成 100 MB
以上的这些配置都是在 application.properties 文件中进行配置的
server.port=8081
spring.servlet.multipart.max-file-size=100MB
默认配置最终都是映射到 MultipartProperties,配置文件的值最终会绑定到每个类上,这个类会在 Spring 容器中创建对象。
spring-boot-autoconfigure
SpringBoot 所有的自动配置功能都在 spring-boot-autoconfigure 包里面,在这个包下面我们可以看到很多。比如 jdbc、aop、jackson、web 等等自动配置类。
自动配置原理
在 SpringBoot 的主程序中,有一个 SpringBootApplication 注解,这个注解用于标记 SpringBoot 的主程序的入口。有它,才能够正常的启动该程序。
SpringBootApplication 是一个合成的注解,这个注解包含着三个注解,它们分别是 SpringBootConfiguration
、EnableAutoConfiguration
和 ComponentScan
三个注解。
SpringBootConfiguration 注解
其中 SpringBootConfiguration 这个注解,它本质上就是一个 Configuration 注解。也就是说,SpringBoot 的主程序类它也是一个配置类。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
ComponentScan 注解
就是普通的包扫描注解,指定哪一个扫描的包路径。
EnableAutoConfiguration 注解
该注解是 SpringBootConfiguration 注解中非常重要的一个注解,通过它就可以找到 SpringBoot 的主程序类是在哪个包路径下,以及……
该注解的代码如下
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
//主体省略......
}
其中 AutoConfigurationPackage 注解就是找到 SpringBoot 的主程序类是在哪个包路径下。Import 注解也说过,它也是将组件注册到容器中。
Import 注解的详细使用可以看看 “SpringBoot注解的学习” 这篇日志
它需要导入的 AutoConfigurationImportSelector 这个类的目的是加载那些自动配置类,也就是那些 xxxxxAutoConfiguration.java。
AutoConfigurationPackage 注解
该注解的代码如下
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
//主体省略......
}
其中,Register 类就是把包下面的一系列组件给导入进来,它并不是仅仅导入一个
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
/**
* 一系列组件导入的方法
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
}
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImports(metadata));
}
}
通过该注解的元信息获取到主程序所在的包路径,然后再调用 register 方法,将一系列的包给导入进来。这也就能够解释。启动类的同级目录以及它的子目录下的组件给导入进来。
AutoConfigurationImportSelector
未完待续……
请勿发布违反中国大陆地区法律的言论,请勿人身攻击、谩骂、侮辱和煽动式的语言。