Spring Boot有一个全局配置文件:application.properties或application.yml。各种属性都可以在这个文件中进行配置,最常配置的比如:server.port、logging.level.* 等等,当然这些属性都可以在官方文档中查找到的https://docs.spring.io/spring-boot/docs/2.1.0.RELEASE/reference/htmlsingle/#common-application-properties
接下来介绍下Spring自动配置工作原理或者叫实现方式吧
Spring Boot关于自动配置的源码在spring-boot-autoconfigure-x.x.x.x.jar中:
@Configuration
@Import(value = {TulingSelector.class})
public class TulingConfig {
}
②:在@Import注解的value值 写自己需要导入的组件
在selectImports方法中 就是你需要导入组件的全类名
public class TulingSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{"com.tuling.service.TulingServiceImpl"};
}
}
核心代码:
@RestController
public class TulingController {
//自动注入 tulingServiceImpl
@Autowired
private TulingServiceImpl tulingServiceImpl;
@RequestMapping("testTuling")
public String testTuling() {
tulingServiceImpl.testService();
return "tulingOk";
}
}
这里是没有标注其他注解提供给spring包扫描的
public class TulingServiceImpl {
public void testService() {
System.out.println("我是通过importSelector导入进来的service");
}
}
先看看SpringBoot的主配置类:
里面有一个main方法运行了一个run()方法,在run方法中必须要传入一个被@SpringBootApplication注解的类。
@SpringBootApplication
SpringBoot应用标注在某个类上说明这个类是SpringBoot的主配置类,SpringBoot就会运行这个类的main方法来启动SpringBoot项目。
那@SpringBootApplication注解到底是什么呢,点进去看看:
发现@SpringBootApplication是一个组合注解。
@SpringBootConfiguration
先看看@SpringBootConfiguration注解:
这个注解很简单,表明该类是一个Spring的配置类。
再进去看看@Configuration:
说明Spring的配置类也是Spring的一个组件。
@EnableAutoConfiguration
这个注解是开启自动配置的功能。
先看看@AutoConfigurationPackage注解:
这个注解是自动配置包,主要是使用的@Import来给Spring容器中导入一个组件 ,这里导入的是Registrar.class。
来看下这个Registrar:
就是通过这个方法获取扫描的包路径,可以debug看看:
在这行代码上打了一个断点:
启动项目:
进入断点处:
看看能否获取扫描的包路径:
已经获取到了包路径:
那那个metadata是什么呢:
可以看到是标注在@SpringBootApplication注解上的DemosbApplication,也就是我们的主配置类:
说白了就是将主配置类(即@SpringBootApplication标注的类)的所在包及子包里面所有组件扫描加载到Spring容器。所以包名一定要注意。
现在包扫描路径获取到了,那具体加载哪些组件呢,看看下面这个注解。
@Import({AutoConfigurationImportSelector.class})
@Import注解就是给Spring容器中导入一些组件,这里传入了一个组件的选择器:AutoConfigurationImportSelector。
里面有一个selectImports方法,将所有需要导入的组件以全类名的方式返回;这些组件就会被添加到容器中。
debug运行看看:
会给容器中导入非常多的自动配置类(xxxAutoConfiguration);就是给容器中导入这个场景需要的所有组件,并配置好这些组件:
有了自动配置类,免去了我们手动编写配置注入功能组件等的工作。
那他是如何获取到这些配置类的呢,看看上面这个方法:
会从META-INF/spring.factories中获取资源,然后通过Properties加载资源:
Spring Boot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作。以前我们需要自己配置的东西,自动配置类都帮我们完成了。
J2EE的整体整合解决方案和自动配置都在spring-boot-autoconfigure-2.0.3.RELEASE.jar:
比如看看WebMvcAutoConfiguration:
都已经帮我们配置好了,我们不用再单独配置了:
先看看SpringBoot的主配置类:
里面有一个main方法运行了一个run()方法,在run方法中必须要传入一个被@SpringBootApplication注解的类。
@SpringBootApplication
SpringBoot应用标注在某个类上说明这个类是SpringBoot的主配置类,SpringBoot就会运行这个类的main方法来启动SpringBoot项目。
那@SpringBootApplication注解到底是什么呢,点进去看看:
发现@SpringBootApplication是一个组合注解。
@SpringBootConfiguration
先看看@SpringBootConfiguration注解:
这个注解很简单,表明该类是一个Spring的配置类。
再进去看看@Configuration:
说明Spring的配置类也是Spring的一个组件。
@EnableAutoConfiguration
这个注解是开启自动配置的功能。
先看看@AutoConfigurationPackage注解:
这个注解是自动配置包,主要是使用的@Import来给Spring容器中导入一个组件 ,这里导入的是Registrar.class。
来看下这个Registrar:
就是通过这个方法获取扫描的包路径,可以debug看看:
在这行代码上打了一个断点:
启动项目:
进入断点处:
看看能否获取扫描的包路径:
已经获取到了包路径:
那那个metadata是什么呢:
可以看到是标注在@SpringBootApplication注解上的DemosbApplication,也就是我们的主配置类:
说白了就是将主配置类(即@SpringBootApplication标注的类)的所在包及子包里面所有组件扫描加载到Spring容器。所以包名一定要注意。
现在包扫描路径获取到了,那具体加载哪些组件呢,看看下面这个注解。
@Import({AutoConfigurationImportSelector.class})
@Import注解就是给Spring容器中导入一些组件,这里传入了一个组件的选择器:AutoConfigurationImportSelector。
里面有一个selectImports方法,将所有需要导入的组件以全类名的方式返回;这些组件就会被添加到容器中。
debug运行看看:
会给容器中导入非常多的自动配置类(xxxAutoConfiguration);就是给容器中导入这个场景需要的所有组件,并配置好这些组件:
有了自动配置类,免去了我们手动编写配置注入功能组件等的工作。
那他是如何获取到这些配置类的呢,看看上面这个方法:
会从META-INF/spring.factories中获取资源,然后通过Properties加载资源:
Spring Boot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作。以前我们需要自己配置的东西,自动配置类都帮我们完成了。
J2EE的整体整合解决方案和自动配置都在spring-boot-autoconfigure-2.0.3.RELEASE.jar:
比如看看WebMvcAutoConfiguration:
都已经帮我们配置好了,我们不用再单独配置了:
自动配置原理
1).SpringBoot启动的时候加载主配置类,开启了自动配置功能@EnableAutoConfiguration
2).@EnableAutoConfiguration作用:
@Configuration
@ConditionalOnWebApplication(
type = Type.SERVLET
)
public class ServletEndpointManagementContextConfiguration {
public ServletEndpointManagementContextConfiguration() {
}
@Bean
public ExposeExcludePropertyEndpointFilter servletExposeExcludePropertyEndpointFilter(WebEndpointProperties properties) {
Exposure exposure = properties.getExposure();
return new ExposeExcludePropertyEndpointFilter(ExposableServletEndpoint.class, exposure.getInclude(), exposure.getExclude(), new String[0]);
}
@Configuration
@ConditionalOnClass({ResourceConfig.class})
@ConditionalOnMissingClass({"org.springframework.web.servlet.DispatcherServlet"})
public class JerseyServletEndpointManagementContextConfiguration {
public JerseyServletEndpointManagementContextConfiguration() {
}
@Bean
public ServletEndpointRegistrar servletEndpointRegistrar(WebEndpointProperties properties, ServletEndpointsSupplier servletEndpointsSupplier) {
return new ServletEndpointRegistrar(properties.getBasePath(), servletEndpointsSupplier.getEndpoints());
}
}
@Configuration
@ConditionalOnClass({DispatcherServlet.class})
public class WebMvcServletEndpointManagementContextConfiguration {
private final ApplicationContext context;
public WebMvcServletEndpointManagementContextConfiguration(ApplicationContext context) {
this.context = context;
}
@Bean
public ServletEndpointRegistrar servletEndpointRegistrar(WebEndpointProperties properties, ServletEndpointsSupplier servletEndpointsSupplier) {
DispatcherServletPathProvider servletPathProvider = (DispatcherServletPathProvider)this.context.getBean(DispatcherServletPathProvider.class);
String servletPath = servletPathProvider.getServletPath();
if (servletPath.equals("/")) {
servletPath = "";
}
return new ServletEndpointRegistrar(servletPath + properties.getBasePath(), servletEndpointsSupplier.getEndpoints());
}
}
}
自上而下观察整个类的代码,你会发现这些自动装配的套路都是一样的
1、如果当前是Servlet环境则装配这个bean
2、当存在类
ResourceConfig
以及不存在类DispatcherServlet
时装配JerseyServletEndpointManagementContextConfiguration
3、当存在
DispatcherServlet
类时装配WebMvcServletEndpointManagementContextConfiguration
Spring Boot有一个全局配置文件:application.properties或application.yml。各种属性都可以在这个文件中进行配置,最常配置的比如:server.port、logging.level.* 等等,当然这些属性都可以在官方文档中查找到的https://docs.spring.io/spring-boot/docs/2.1.0.RELEASE/reference/htmlsingle/#common-application-properties
接下来介绍下Spring自动配置工作原理或者叫实现方式吧
Spring Boot关于自动配置的源码在spring-boot-autoconfigure-x.x.x.x.jar中:
当然,自动配置原理的相关描述,官方文档貌似是没有提及。不过我们不难猜出,Spring Boot的启动类上有一个@SpringBootApplication注解,这个注解是Spring Boot项目必不可少的注解。那么自动配置原理一定和这个注解有着千丝万缕的联系!
@EnableAutoConfiguration
@SpringBootApplication是一个复合注解或派生注解,在@SpringBootApplication中有一个注解@EnableAutoConfiguration,翻译成人话就是开启自动配置,其定义如下:
而这个注解也是一个派生注解,其中的关键功能由@Import提供,其导入的AutoConfigurationImportSelector的selectImports()方法通过SpringFactoriesLoader.loadFactoryNames()扫描所有具有META-INF/spring.factories的jar包。spring-boot-autoconfigure-x.x.x.x.jar里就有一个这样的spring.factories文件。
这个spring.factories文件也是一组一组的key=value的形式,其中一个key是EnableAutoConfiguration类的全类名,而它的value是一个xxxxAutoConfiguration的类名的列表,这些类名以逗号分隔,如下图所示:
这个@EnableAutoConfiguration注解通过@SpringBootApplication被间接的标记在了Spring Boot的启动类上。在SpringApplication.run(...)的内部就会执行selectImports()方法,找到所有JavaConfig自动配置类的全限定名对应的class,然后将所有自动配置类加载到Spring容器中。
自动配置生效
每一个XxxxAutoConfiguration自动配置类都是在某些条件之下才会生效的,这些条件的限制在Spring Boot中以注解的形式体现,常见的条件注解有如下几项:
以ServletWebServerFactoryAutoConfiguration配置类为例,解释一下全局配置文件中的属性如何生效,比如:server.port=8081,是如何生效的(当然不配置也会有默认值,这个默认值来自于org.apache.catalina.startup.Tomcat)。
在ServletWebServerFactoryAutoConfiguration类上,有一个@EnableConfigurationProperties注解:开启配置属性,而它后面的参数是一个ServerProperties类,这就是习惯优于配置的最终落地点。
在这个类上,我们看到了一个非常熟悉的注解:@ConfigurationProperties,它的作用就是从配置文件中绑定属性到对应的bean上,而@EnableConfigurationProperties负责导入这个已经绑定了属性的bean到spring容器中(见上面截图)。那么所有其他的和这个类相关的属性都可以在全局配置文件中定义,也就是说,真正“限制”我们可以在全局配置文件中配置哪些属性的类就是这些XxxxProperties类,它与配置文件中定义的prefix关键字开头的一组属性是唯一对应的。
至此,我们大致可以了解。在全局配置的属性如:server.port等,通过@ConfigurationProperties注解,绑定到对应的XxxxProperties配置实体类上封装为一个bean,然后再通过@EnableConfigurationProperties注解导入到Spring容器中。
而诸多的XxxxAutoConfiguration自动配置类,就是Spring容器的JavaConfig形式,作用就是为Spring 容器导入bean,而所有导入的bean所需要的属性都通过xxxxProperties的bean来获得。
可能到目前为止还是有所疑惑,但面试的时候,其实远远不需要回答的这么具体,你只需要这样回答:
通过一张图标来理解一下这一繁复的流程:
总结
综上是对自动配置原理的讲解。当然,在浏览源码的时候一定要记得不要太过拘泥与代码的实现,而是应该抓住重点脉络。
一定要记得XxxxProperties类的含义是:封装配置文件中相关属性;XxxxAutoConfiguration类的含义是:自动配置类,目的是给容器中添加组件。
而其他的主方法启动,则是为了加载这些五花八门的XxxxAutoConfiguration类
1)传统ssm整合redis的时候 需要在xml的配置文件中 进行大量的配置Bean
我们在这里使用springboot来代替ssm的整合,只是通过xml的形式来整合redis
第一步:加入配置
第二步: 配置xml的bean的配置
第三步:导入配置
@ImportResource(locations = "classpath:beans.xml") 可以导入xml的配置文件
2)综上所述 我们发现,若整合redis的时候通过传统的整合,进行了大量的配置,那么我们来看下通过springboot自动装配整合的对比
导入依赖:
修改yml配置文件
直接使用(下述代码可以不要配置,为了解决保存使用jdk的序列方式才配置的)
3)传统整合和springboot自动装配 优劣势分析。。。。。。。。。。。。
4)自动装配原理前的不得不说的几个注解
4.1)通过@Import注解来导入ImportSelector组件
①:写一个配置类在配置类上标注一个@Import的注解,
②:在@Import注解的value值 写自己需要导入的组件
在selectImports方法中 就是你需要导入组件的全类名
核心代码:
1.2)通过@Import导入ImportBeanDefinitionRegistrar 从而进来导入组件
核心代码:
测试结果:
1.3)spring底层条件装配的原理@Conditional
应用要求:比如我有二个组件,一个是TulingLog 一个是TulingAspect
而TulingLog 是依赖TulingAspect的 只有容器中有TulingAspect组件才会加载TulingLog
①:自定义条件组件条件
自动装配原理分析 从@SpringbootApplication入手分析
那我们仔细分析
org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#selectImports
然后我们分析RedisAutoConfiguration类
导入了三个组件 RedisTemplate StringRedisTemplate
JedisConnectionConfiguration
(1)引导类上开启@duEnableAutoConfiguration
(2)dao部通zhuan过@import注解引入ImporttSelector
(3)查找工程jar包中META-INF/spring.factories文件
(4)装载shu部的对象到容器
先看看SpringBoot的主配置类:
里面有一个main方法运行了一个run()方法,在run方法中必须要传入一个被@SpringBootApplication注解的类。
@SpringBootApplication
SpringBoot应用标注在某个类上说明这个类是SpringBoot的主配置类,SpringBoot就会运行这个类的main方法来启动SpringBoot项目。
那@SpringBootApplication注解到底是什么呢,点进去看看:
相关问题推荐
最近看了一些spring书籍,主要都是工作需要,实话说,没有必要买这么多书,每个主题一本就足够了,其他的补充可以通过项目实战和上网看官网或者博客补充。说是推荐,其实只是一些简单读后感想而已,每本书都有它的价值,即使有些写得不好,也很难否定作者的努...
org.springframework.boot spring-boot-starter-parent 1.3.2.RELEASE 2.10.4 1.6.2 ...
spring-boot-starter-web 嵌入tomcat和web开发需要servlet与jsp支持spring-boot-starter-data-jpa 数据库支持spring-boot-starter-data-redis redis数据库支持spring-boot-starter-data-solr solr支持mybatis-spring-boot-starter 第三方的myba......
应该说是过时了。我们起初的微服务架构是符合当时的情况的,也解决了当时的性能问题还有目的地之间孤立实现。尽管如此,我们没有准备好服务激增的改变准备。当需要批量更新时,我们缺乏适当的工具来测试和部署微服务。结果就是,我们的研发效率因此出现了滑坡...
springboot的学习思路是首先掌握spring和springmvc,有了这两个框架作为基础,springboot的学习是非常简单的。springboot是spring族系中具有革命性变革的一门技术,springboot的主要设计目的是为了让开发者快速构建spirng环境,并且封装了大量的模板化配置。让...