2021-07-22

SpringBoot自动装配-自定义Start

SpringBoot自动装配原理和自定义start

SpringBoot自动装配

在没有使用SpringBoot之前,使用ssm时配置redis需要在

SpringBootApplication注解

什么是自动装配,也就是说帮你把需要的类自动添加到Spring容器中

只要是一个SpringBoot项目肯定有这样一个类

@SpringBootApplicationpublic class MyApplication { public static void main(String[] args) {  SpringApplication.run(TokenApplication.class, args); }}			

而自动装配是在@SpringBootApplication这个注解中实现的,点进去首先能看到这个注解上还有三个类

@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })public @interface SpringBootApplication {}

其中SpringBootConfiguration上还有一个注解@Configuration也就是说明其实SpringBootApplication也是一个配置类

@ComponentScan用于扫描需要被Spring管理的类,这也就是为什么写的类需要在SpringBoot启动类同级或在同级下的子包中

@EnableAutoConfiguration点进去发现它上面有一个特殊的注解@Import(AutoConfigurationImportSelector.class)

@Import注解的作用是将指定类添加到Spring容器中成为一个Bean

而在AutoConfigurationSelector类中有自动装配的实现

	@Override	public String[] selectImports(AnnotationMetadata annotationMetadata) {		if (!isEnabled(annotationMetadata)) {			return NO_IMPORTS;		}		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());	}
protected AutoConfigurationEntry getAutoConfigurationEntry(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 = getConfigurationClassFilter().filter(configurations); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions);}protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) { //获取注解的名称作为key String name = getAnnotationClass().getName(); AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true)); Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName()     + " annotated with " + ClassUtils.getShortName(name) + "?"); return attributes;}

其中我们关注与返回值相关的代码,也就是getCandidateConfigurations这个方法

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;}

继续查看loadFactoryNames方法

public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) { String factoryTypeName = factoryType.getName(); return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());}private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) { MultiValueMap<String, String> result = cache.get(classLoader); if (result != null) {  return result; } try {  //从META-INF/spring.factories中获取配置文件  Enumeration<URL> urls = (classLoader != null ?         classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :         ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));  result = new LinkedMultiValueMap<>();  while (urls.hasMoreElements()) {   URL url = urls.nextElement();   UrlResource resource = new UrlResource(url);   Properties properties = PropertiesLoaderUtils.loadProperties(resource);   for (Map.Entry<?, ?> entry : properties.entrySet()) {    String factoryTypeName = ((String) entry.getKey()).trim();    for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {     result.add(factoryTypeName, factoryImplementationName.trim());    }   }  }  cache.put(classLoader, result);  return result; } catch (IOException ex) {  throw new IllegalArgumentException("Unable to load factories from location [" +           FACTORIES_RESOURCE_LOCATION + "]", ex); }}

其中需要解释一下的是:MultiValueMap[接口],它是一个特殊的Map,由SpringBoot自己写的,查看它的实现类LinkedMultiValueMap

private final Map<K, List<V>> targetMap;

通常我们使用的Map是一个<K,V>结构的,而它这个Map是一个<K,V V V ...>结构的

首先SpringBoot会从缓存中尝试获取(其实也就是个map,不过有点特殊),如果获取不到,那就一次将全部内容读取出来,然后以K V V V...的形式存放到类中

那么META-INF/spring.factories这个文件在哪呢?

它里面的内容是这样的

以类的全限定名作为Key,其他类的全限定名作为Value

那到现在还是一头雾水,读到了这个有什么用呢?我们拿常见的Redis来看看

点进RedisAutoConfiguration看看

发现里面全是报错,因为我还没有导入Redis的start,当我在pom文件中添加redis的依赖后

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-redis</artifactId> <version>1.4.1.RELEASE</version></dependency>

发现不报错了,使用RedisTemplate存取值也可以了,这里就不再演示存取值

上面这个类主要看类上面的注解,主要的两个为:ConditionalOnClassEnableConfigurationProperties

ConditionalOnClass

@ConditionalOnClass的作用是当前项目的classpath中存在某个类在会实例化这个类为bean,Spring还提供了其他类似的注解

那么毫无疑问pom中导入的那个依赖中肯定有一个类或接口叫做RedisOperations,点进去查看它的包路径

package org.springframework.data.redis.core;

我们去导入的包中找一找

EnableConfigurationProperties

@EnableConfigurationProperties注解是使@ConfigurationProperties 注解的类生效,点进注解上的类

@ConfigurationProperties注解的作用是可以将参数的配置设置在application配置文件中,我们在application配置文件中配置的参数都配置类中的字段,要不然这些参数那来的?

那么现在SpringBoot自动装配的大致流程就完成了

  1. 读取META-INF/spring.factories文件
  2. 将扫描出的类进行判断
  3. 如果符合类上的@ConditionalOnxxxx注解就将类添加到Spring容器中

如何自定义一个Start

现在知道了SpringBoot是如何自动装配的,扫描MEAT-INF下spring.factories文件,key为:EnableAutoConfiguration,为什么key为EnableAutoConfiguration呢?在上面的代码中,扫描的以@EnableAutoConfiguration注解获取名称作为key

首先创建一个Maven项目,导入依赖

<dependencies> <dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-bo......

原文转载:http://www.shaoqun.com/a/892105.html

跨境电商:https://www.ikjzd.com/

lithium:https://www.ikjzd.com/w/2505

跨境通电子商务平台:https://www.ikjzd.com/w/1329.html

拍拍:https://www.ikjzd.com/w/2205


SpringBoot自动装配原理和自定义startSpringBoot自动装配在没有使用SpringBoot之前,使用ssm时配置redis需要在SpringBootApplication注解什么是自动装配,也就是说帮你把需要的类自动添加到Spring容器中只要是一个SpringBoot项目肯定有这样一个类@SpringBootApplicationpublicclassMyApplication
天津应季旅游时间表 给爱旅游的你:http://www.30bags.com/a/416589.html
天津优联投资集团精心筹划 柬埔寨七星海与桂林旅游学院合作云签约成功举行:http://www.30bags.com/a/230917.html
天津有什么风味小吃?:http://www.30bags.com/a/415839.html
天津有什么好玩的地方 天津游玩必去的地方排名:http://www.30bags.com/a/433753.html
我在做饭他在下添私密 我配合的张开双腿好深:http://lady.shaoqun.com/a/248130.html
扒开女人下面添 宝贝你那里的水好甜:http://lady.shaoqun.com/a/247978.html
黑人下面好大好爽 和黑人高潮了10次:http://lady.shaoqun.com/m/a/248391.html
男朋友在车里㖭比过程 放在里面一整天:http://www.30bags.com/m/a/249824.html
男女出轨都为了什么?婚姻出轨的7个动机你知道吗 :http://lady.shaoqun.com/a/428396.html
如果一个女人堕胎了,她身上通常会有几个明显的痕迹,仔细观察就能发现:http://lady.shaoqun.com/a/428397.html
男生第一次谈恋爱的方式:http://lady.shaoqun.com/a/428398.html
一个生过孩子的女人身上有这三个明显的痕迹。医生直言:没办法:http://lady.shaoqun.com/a/428399.html

No comments:

Post a Comment