从main函数说起
一切的开始要从SpringbootApplication注解说起。
@SpringBootApplication public class MyBootApplication { public static void main(String[] args) { SpringApplication.run(MyBootApplication.class); } } @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan public @interface SpringBootApplication { }
其中最重要的就是EnableAutoConfiguration注解,开启自动配置。
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({AutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class<?>[] exclude() default {}; String[] excludeName() default {}; }
通过Import注解导入AutoConfigurationImportSelector。在这个类中加载/META-INF/spring.factories文件的信息,然后筛选出以EnableAutoConfiguration为key的数据,加载到IOC容器中,实现自动配置功能。
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import(AutoConfigurationPackages.Registrar.class) public @interface AutoConfigurationPackage { }
从表面看就是自动配置包,主要使用了Import注解,导入了Registrar类。这里Registrar类的registerBeanDefinitions方法导包,也就是导入当前main函数所在路径的包地址,我这里是com.zhangfei。
怎么自动装配其他N个类
Import({AutoConfigurationImportSelector.class})该注解给当前配置类导入另外N个自动配置类。
这里既然导入N个自动配置类,那么都导入哪些类呢?
//AutoConfigurationImportSelector实现DeferredImportSelector接口,而DeferredImportSelector接口又继承了ImportSelector public interface ImportSelector { String[] selectImports(AnnotationMetadata var1); }
AutoConfigurationImportSelector通过实现接口ImportSelector的selectImports方法返回需要导入的组件,selectImports方法返回一个全类名字符串数组。
主角上场
//AutoConfigurationImportSelector.java @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader); AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } AnnotationAttributes attributes = getAttributes(annotationMetadata); List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); configurations = removeDuplicates(configurations); Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = filter(configurations, autoConfigurationMetadata); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); } protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader()); return configurations; }
这里又开始调用SpringFactoriesLoader.loadFactoryNames。
SpringFactoriesLoader.loadFactoryNames方法中关键的三步:
(1)从当前项目的类路径中获取所有 META-INF/spring.factories 这个文件下的信息.
(2)将上面获取到的信息封装成一个 Map 返回,EnableAutoConfiguration为key。
(3)从返回的Map中通过刚才传入的 EnableAutoConfiguration.class参数,获取该 key 下的所有值。
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList()); } private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) { MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader); if (result != null) { return result; } else { try { Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories"); LinkedMultiValueMap result = new LinkedMultiValueMap(); while(urls.hasMoreElements()) { URL url = (URL)urls.nextElement(); UrlResource resource = new UrlResource(url); Properties properties = PropertiesLoaderUtils.loadProperties(resource); Iterator var6 = properties.entrySet().iterator(); while(var6.hasNext()) { Entry<?, ?> entry = (Entry)var6.next(); String factoryClassName = ((String)entry.getKey()).trim(); String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue()); int var10 = var9.length; for(int var11 = 0; var11 < var10; ++var11) { String factoryName = var9[var11]; result.add(factoryClassName, factoryName.trim()); } } } cache.put(classLoader, result); return result; } catch (IOException var13) { throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13); } } }
自动配置都有哪些内容呢?
# 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.batch.BatchAutoConfiguration,\ org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\ ...其他省略
XXXAutoConfiguration和XXProperties
在spring.factories文件中看到的都是自动配置类,那么自动配置用到的属性值在那里呢?我们拿出redis为例
@Configuration @ConditionalOnClass(RedisOperations.class) //判断当前项目有没有这个类RedisOperations.class @EnableConfigurationProperties(RedisProperties.class) //启用配置属性,这里看到了熟悉的XXXProperties @Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class }) //导入这两个类 public class RedisAutoConfiguration { @Bean @ConditionalOnMissingBean(name = "redisTemplate") public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { RedisTemplate<Object, Object> template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory); return template; } @Bean @ConditionalOnMissingBean public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { StringRedisTemplate template = new StringRedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; } } //这里则保存redis初始化时的属性 @ConfigurationProperties(prefix = "spring.redis") public class RedisProperties { private int database = 0; private String url; private String host = "localhost"; private String password; private int port = 6379; private boolean ssl; }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
主要内容:1.SpringBoot自动装配原理,2.BeanFactory和ApplicationContext的区别,3.Spring容器是什么1.SpringBoot自动装配原理 BFPP:BeanFactoryPostProcessor BPP:BeanPostProcessor BDRPP:BeanDefinitionRegistryPostProsessor 1.当启动SpringBoot程序时候,创建SpringApplication的对象,在对象的构造方法中进行对某些参数的初始化工
4.1 根据条件的自动配置 @conditional是基于条件的自动配置,一般配合Condition接口一起使用,只有接口实现类返回true,才装配,否则不装配. 用实现了Condition接口的类传入@Conditional中 @Conditional可以标记在配置类的方法中,也可以标记在配置类上.标记的位置不同,作用域不同. @Conditional可以传入多个实现了condition接口的类
本文向大家介绍SpringBoot自动装配原理详解,包括了SpringBoot自动装配原理详解的使用技巧和注意事项,需要的朋友参考一下 首先对于一个SpringBoot工程来说,最明显的标志的就是 @SpringBootApplication它标记了这是一个SpringBoot工程,所以今天的 SpringBoot自动装配原理也就是从它开始说起。 自动装配流程 首先我们来看下@SpringBoot
本文向大家介绍浅谈IIS安全配置,包括了浅谈IIS安全配置的使用技巧和注意事项,需要的朋友参考一下 1.VPS或者服务器分区要是NTFS的原因不说了,说多了也没用 2.禁止TCP/IP的NETBIOS 通过网络属性的绑定选项,废止NetBIOS与TCP/IP之间的绑定 3.网站右键权限user(最好一个网站建立一个用户,尽可能不要相同)中权限 写入 执行等权限慎用,写入之后有可能会sql注入 坑爹
本文向大家介绍全面解析SpringBoot自动配置的实现原理,包括了全面解析SpringBoot自动配置的实现原理的使用技巧和注意事项,需要的朋友参考一下 之前一直在用SpringBoot框架,一直感觉SpringBoot框架自动配置的功能很强大,但是并没有明白它是怎么实现自动配置的,现在有空研究了一下,大概明白了SpringBoot框架是怎么实现自动配置的功能,我们编写一个最简单的自动配置功能,
本文向大家介绍浅谈SpringBoot集成Quartz动态定时任务,包括了浅谈SpringBoot集成Quartz动态定时任务的使用技巧和注意事项,需要的朋友参考一下 SpringBoot自带schedule 沿用的springboot少xml配置的优良传统,本身支持表达式等多种定时任务 注意在程序启动的时候加上@EnableScheduling 为什么要使用Quartz 多任务情况下,quart