视频&交流平台:
http://study.163.com/course/introduction.htm?courseId=1004329008
http://412887952-qq-com.iteye.com/blog/2321532
问题的提出:Spring Boot不像spring需要定义xml文件文件,那么spring boot是如何在没有配置文件的情况下为我们启动一个完整的WEB工程的呢。我们先@SpringBootApplication开始分析下这个启动流程,源代码取自:1.4.1.RELEASE。
我们先看下@SpringBootApplication的代码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class))
public @interface SpringBootApplication {}
可以看到这里是一个复合注解,如:@Target,@Document,@Retention是我们常见的注解,这里重点说下@SpringBootConfiguration注解:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {}
这个注解重要的就是@Configuration:这是标注当前类为Java Config类。
在@SpringBootApplication中另外一个重要的注解就是@EnableAutoConfiguration:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}
这个注解上@Import(EnableAutoConfigurationImportSelector.class)代表引入其它的Spring的JavaConfig接着进入EnableAutoConfigurationImportSelector.class。
关注一下以下的方法:
@Override
public String[] selectImports(AnnotationMetadata metadata) {
if (!isEnabled(metadata)) {
returnNO_IMPORTS;
}
try {
AnnotationAttributes attributes = getAttributes(metadata);
List<String> configurations = getCandidateConfigurations(metadata,
attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(metadata, attributes);
configurations.removeAll(exclusions);
configurations = sort(configurations);
recordWithConditionEvaluationReport(configurations, exclusions);
return configurations.toArray(new String[configurations.size()]);
}
catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
进入:List configurations = getCandidateConfigurations(metadata,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;
}
在进入:List configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
代码如下:
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
try {
Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
List<String> result = new ArrayList<String>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
String factoryClassNames = properties.getProperty(factoryClassName);
result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
}
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
"] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
在上面的代码可以看到自动配置器会跟根据传入的factoryClass.getName()到spring.factories的文件中找到相应的key,从而加载里面的类但我们打开spring-boot-autoconfigure-1.4.1.RELEASE.jar里面的spring.factories可以发现很多key。查看spring.factories文件:
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
这里以org.springframework.boot.autoconfigure.data.Redis.RedisAutoConfiguration为例查看代码如下:
@Configuration
@ConditionalOnClass({ JedisConnection.class, RedisOperations.class, Jedis.class })
@EnableConfigurationProperties
public class RedisAutoConfiguration {
@Bean(name = "org.springframework.autoconfigure.redis.RedisProperties")
@ConditionalOnMissingBean
public RedisProperties redisProperties() {
return new RedisProperties();
}
/**
* Redis connection configuration.
*/
@Configuration
@ConditionalOnMissingClass("org.apache.commons.pool2.impl.GenericObjectPool")
protected static class RedisConnectionConfiguration
extends AbstractRedisConfiguration {
@Bean
@ConditionalOnMissingBean(RedisConnectionFactory.class)
public JedisConnectionFactory redisConnectionFactory()
throws UnknownHostException {
return applyProperties(new JedisConnectionFactory(getSentinelConfig()));
}
}
//省略部分代码…
/**
* Standard Redis configuration.
*/
@Configuration
protected static class RedisConfiguration {
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(
RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
}
把类简化一下基本上就可以看出这就是一个Spring的注解版的配置
(1)@ConditionalOnClass({ JedisConnection.class, RedisOperations.class, Jedis.class })这个注解的意思是:当存在JedisConnection.class, RedisOperations.class, Jedis.class三个类时才解析RedisAutoConfiguration配置类,否则不解析这一个配置类
(2)@ConditionalOnMissingBean(name = “redisTemplate”)这个注解的意思是如果容器中不存在name指定的bean则创建bean注入,否则不执行
(3)内部代码可以看出里面又定义了两个带@Configuration注解的配置类,这两个配置类会向SpringIOC容器注入可能3个bean:
首先当类路径下存在(GenericObjectPool.class)时则注入JedisConnectionFactory 的实例如果Spring容器中不存在name = “redisTemplate”的实体,则创建RedisTemplate和StringRedisTemplate实例注入容器,这样在Spring的项目中,就可以用在任意的Spring管理的bean中注册用RedisTemplate和StringRedisTemplate的实例来对redis进入操作了。
通过以上分析的过程我们可以发现只要一个基于SpringBoot项目的类路径下存在JedisConnection.class, RedisOperations.class, Jedis.class就可以触发自动化配置,意思说我们只要在maven的项目中依赖了spring-data-redis-1.7.2.RELEASE.jar和C:jedis-2.8.2.jar就可以触发自动配置,但这样不是每集成一个功能都要去分析里其自动化配置类,那就代不到开箱即用的效果了。所以Spring-boot为我提供了统一的starter可以直接配置好相关触发自动配置的所有的类的依赖集如redis的start如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
因为maven依赖的传递性,我们只要依赖starter就可以看在类路径下配置好所有的触发自动配置的所有类,实现开箱即用的功能。
视频&交流平台:
http://study.163.com/course/introduction.htm?courseId=1004329008
http://412887952-qq-com.iteye.com/blog/2321532
相关推荐
从零开始学Spring Boot.pdf从零开始学Spring Boot.pdf从零开始学Spring Boot.pdf从零开始学Spring Boot.pdf从零开始学Spring Boot.pdf从零开始学Spring Boot.pdf从零开始学Spring Boot.pdf从零开始学Spring Boot.pdf...
关于标签"源码",我们可以进一步讨论Spring Boot启动过程的源码分析。Spring Boot的启动流程涉及多个组件,包括`SpringApplication`、`ApplicationContext`等。在启动过程中,`SpringApplication.run()`方法是主要...
Spring Boot Junit单元测试【从零开始学Spring Boot】"的主题,深入探讨Spring Boot中Junit单元测试的使用方法和最佳实践。 首先,我们要了解什么是单元测试。单元测试是一种针对软件中的最小可测试单元(如方法)...
Spring Boot普通类调用bean【从零开始学Spring Boot】”旨在指导初学者如何在非Spring管理的类中访问和使用Spring容器中的bean。下面将详细讲解这个主题。 首先,了解Spring Boot的基础概念是必要的。Spring Boot...
在本篇【从零开始学Spring Boot】系列教程中,我们将深入探讨如何在Spring Boot项目中导入并使用XML配置。Spring Boot以其简化Spring应用的初始搭建以及开发过程而闻名,通常推崇的是Java配置而非XML配置。然而,在...
3. **启用Spring Session**: 在Spring Boot的配置类中,启用Spring Session并指定使用Redis作为存储策略: ```java @Configuration public class SessionConfig { @Bean public RedisConnectionFactory ...
从零开始学Spring Boot,没有积分的可以...(1)spring boot起步之Hello World【从零开始学Spring Boot】: http://412887952-qq-com.iteye.com/blog/2291500 (2)Spring Boot返回json数据【从零开始学Spring Boot】 ...
Spring Boot通过内置的Tomcat服务器和自动配置机制,简化了Web应用的搭建过程。而Velocity则提供了一种模板语言,允许开发者将业务逻辑与视图呈现分离,使得页面设计更加独立。在Spring Boot中集成Velocity,可以...
Spring Boot是由Pivotal团队开发的一个框架,它旨在简化Spring应用程序的初始搭建以及开发过程,通过预设默认配置,极大地提高了开发效率。 1. **Spring Boot简介** Spring Boot的核心理念是“约定优于配置”。它...
Spring Boot的拦截器基于`org.springframework.web.servlet.HandlerInterceptor`接口,该接口包含三个方法: 1. `preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)`:这个...
在本篇博文中,我们将深入探讨如何使用Spring Boot发送电子邮件,这是Spring Boot框架的一个非常实用的功能,可以帮助开发者轻松实现企业级应用中的邮件服务。通过学习本文,你可以掌握Spring Boot集成...
在本篇【从零开始学Spring Boot】系列中,我们将探讨如何在Spring Boot项目中集成并配置Druid数据源以及其监控功能。Druid是一个强大的数据库连接池,它提供了丰富的监控、扩展性以及性能优化特性。Spring Boot简化...
3. **性能监控**:记录请求处理的时间,用于性能分析。 4. **缓存管理**:控制静态资源的缓存策略。 创建一个自定义过滤器,需要实现`javax.servlet.Filter`接口,并重写`doFilter`方法。然后在Spring Boot的配置类...
在本篇【从零开始学Spring Boot】系列中,我们将探讨如何在Spring Boot项目中使用Druid数据源进行编程注入。Druid是一个优秀的数据库连接池,它提供了强大的监控和扩展功能,是许多企业级应用首选的数据源解决方案。...
Spring Boot简化了配置过程,使得我们可以快速地将EHCache引入到我们的应用中,从而提高应用程序的性能,减少对数据库或其他资源的重复访问。下面,我们将会详细讲解相关知识点。 首先,了解**Spring Boot**。...
从零开始学Spring Boot。是学习spring Boot的起步资料!!
在本教程中,我们将深入探讨如何使用Spring Boot与Apache Shiro进行权限管理。Spring Boot以其简洁的配置和快速的应用开发而闻名,而Shiro则是一个轻量级的安全框架,适用于身份验证、授权、会话管理和安全性相关的...