1. 程式人生 > 其它 >springboot原始碼(二)

springboot原始碼(二)

springboot自動裝配原理分析

  1. 何為自動裝配?

     基於springboot原始碼(一)的內容後,spring一直都在致力於解決一個問題,就是如何讓bean的管理變得更簡單,讓開發者儘可能的少關注一些基礎化bean的配置,多關注業務程式碼。所以實現自動裝配。

          自動裝配就是如何自動將bean裝載到IOC容器中。

          實際上,在Enablexxxx模組驅動的出現已經有了自動裝配的雛形,真正能夠實現這一機制,還是spring4.0版本中的@Conditional註解的出現。

          接下來就聊一下自動裝配到底是個什麼玩應兒......

         2.自動裝配的演示(以Redis為類)

         新增依賴:     

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency> 

 

         新增配置:

spring:
    redis:
      host: 127.0.0.1 
      port: 6379

 

          使用:

@Autowired
private
StringRedisTemplate stringRedisTemplate;

 

           按照上面的順序新增,就可以使用redisTemplate了。所以就會想redisTemplate為什麼可以被直接注入?什麼時候注入的?

            這就是自動裝配,可以把classpath下依賴包的相關的bean,自動裝載到Spring IOC 容器中。怎麼做到的呢??????

來吧上原始碼

          3.自動裝配原始碼分析

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters 
= { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) 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";

/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
Class<?>[] exclude() default {};

/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
String[] excludeName() default {};

}

 

引入了一個AutoConfigurationImportSelector.class   根據上一篇內容會聯想到@import註解,實現ImportSelector的方式   可以把需要納入IOC管理的bean放到一個String[]中。

看一下AutoConfigurationImportSelector這個類

 

 

 實現了ImportSelector這個介面,來看一下selectImports()方法

public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        }
        AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
//把autoConfigurationEntry.getConfigurations()轉換成一個String[],雖然現在還不知道返回的內容是什麼
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); }

 

//搞清楚autoConfigurationEntry是什麼。
protected
AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } AnnotationAttributes attributes = getAttributes(annotationMetadata);
//從META-INF/spring.factories中獲取EnableAutoConfiguration型別的全類路徑名 List
<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); configurations = removeDuplicates(configurations); Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions);
//從META-INF/spring-autoconfigure-metadata.properties中找到自動裝載的條件,類似於@Conditional註解的作用 configurations
= getConfigurationClassFilter().filter(configurations); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); }

 

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//getSpringFactoriesLoaderFactoryClass()-->EnableAutoConfiguration.class 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; }

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
//只獲得key為EnableAutoConfiguration的
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下獲取所有的url 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); } }

 

得到EnableAutoConfiguration的已經知道,接下來看過濾

private ConfigurationClassFilter getConfigurationClassFilter() {
        if (this.configurationClassFilter == null) {
//從META-INF/spring.factories中得到key為AutoConfigurationImportFilter的 List
<AutoConfigurationImportFilter> filters = getAutoConfigurationImportFilters(); for (AutoConfigurationImportFilter filter : filters) { invokeAwareMethods(filter); }
//從META-INF/spring-autoconfigure-metadata.properties中獲取自動裝載的條件xxxx.conditionalOnBean、conditionalOnClass等
this.configurationClassFilter = new ConfigurationClassFilter(this.beanClassLoader, filters); } return this.configurationClassFilter; }

接下來就是filter()方法,根據configurations  、autoConfigurationMetadata 根據過濾器的條件進行過濾就ok了。

 

到這springboot的自動裝配機制的主要流程就大致說完了。