• SpringBoot 源码分析(二) 自动装配过程分析


    一、自动装配原理前置知识

    自动装配就是自动将bean装载到Ioc容器中。实际上在spring 3.x版本中,Enable模块驱动注解的出现,已经有了一定的自动装配的雏形,而真正能够实现这一机制,还是在spirng 4.x版本中,conditional条件注解的出现。

    @EnableAutoConfiguration注解的实现原理

    该注解其中真正实现自动配置功能的核心实现者 AutoConfigurationImportSelector,
    @EnableAutoConfiguration它会通过import导入第三方提供的bean的配置类:AutoConfigurationImportSelector,该类实现的接口如下所示,其中两个关键的接口ImportSelector和DeferredImportSelector。都是干嘛的? 这个AutoConfigurationImportSelector又是什么?
    在这里插入图片描述

    @Import注解干嘛的?

    第一该注解是用来导入类到容器中的。
    @Import注解可以配置三种不同的class,
    @Import可以根据添加的不同类型做出不同的操作

    导入类型注入方式
    实现了ImportSelector接口不注入该类型的对象,调用selectImports方法,将返回的数据注入到容器中
    实现了ImportBeanDefinitionRegistrar接口不注入该类型的对象,调用registerBeanDefinitions方法,通过注册器注入
    普通类型直接注入该类型的对象

    1. ImportSelector 接口

    @Import注解的许多功能其实是需要 ImportSelector 接口来实现,ImportSelector 接口决定可引入哪些 @Configuration。

    /**
     * 实现了确定基于给定选择条件应该导入哪些 @Configuration 类的类型的接口,
     * 通常是一个或多个注解属性。
     * 
     * 一个 ImportSelector 可以实现以下任意一个 Aware 接口,并在调用 selectImports 
     * 方法之前调用其对应的方法:
     *    EnvironmentAware
     *    BeanFactoryAware
     *    BeanClassLoaderAware
     *    ResourceLoaderAware
     * 
     * 另外,该类也可以提供一个带有以下支持的参数类型的单个构造函数:
     *    Environment
     *    BeanFactory
     *    ClassLoader
     *    ResourceLoader
     * 
     * ImportSelector 实现通常与普通的 @Import 注解一样进行处理。
     * 然而,还可以推迟选择要导入的内容,直到所有 @Configuration 
     * 类都被处理完毕(详见 DeferredImportSelector)。
     *
     */
    public interface ImportSelector {
    
    	/**
    	 * 根据导入的 @Configuration 类的 AnnotationMetadata(注解元数据),
    	 * 选择并返回应该导入的类名称。
    	 * 
    	 * @return 返回类名的数组,如果没有则返回空数组。
    	 */
    	String[] selectImports(AnnotationMetadata importingClassMetadata);
    
    	/**
    	 * 返回一个用于从导入的候选类中排除类的断言函数,
    	 * 该函数会递归地应用于通过此选择器的导入项找到的所有类。
    	 * 
    	 * 如果对于给定的完全限定类名,该断言函数返回 true,
    	 * 则该类将不被视为被导入的配置类,从而跳过类文件加载和元数据检查。
    	 * 
    	 * @return 返回一个用于完全限定的候选类名的筛选断言函数,该函数适用于递归导入的配置类。
    	 * 如果没有筛选断言函数,则返回 null。
    	 * @since 5.2.4
    	 */
    	@Nullable
    	default Predicate<String> getExclusionFilter() {
    		return null;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    2. DeferredImportSelector 接口

    DeferredImportSelector接口本身也有ImportSelector接口的功能,如果我们仅仅是实现了DeferredImportSelector接口,重写了selectImports方法,那么selectImports方法还是会被执行的.
    AutoConfigurationImportSelector 为啥不直接实现 ImportSelector 接口,而是实现了 DeferredImportSelector 接口呢?有什么区别?

    /**
     * 一种在所有 @Configuration bean 处理完毕后运行的 ImportSelector 变体。
     * 这种类型的选择器在所选的导入项带有条件时特别有用。
     * 
     * 实现类可以扩展 org.springframework.core.Ordered 接口或使用 
     * org.springframework.core.annotation.Order 注解来指定与
     * 其他 DeferredImportSelectors 的优先级。
     * 
     * 实现类还可以提供一个导入组(import group),
     * 它可以在不同的选择器之间提供额外的排序和过滤逻辑。
     */
    public interface DeferredImportSelector extends ImportSelector {
    
    	/**
    	 * 返回一个特定的导入组。
    	 * 默认实现会在不需要分组的情况下返回 null。
    	 * 
    	 * @return 导入组的类,如果没有则返回 null。
    	 * @since 5.0
    	 */
    	@Nullable
    	default Class<? extends Group> getImportGroup() {
    		return null;
    	}
    
    
    	/**
    	 * 用于将来自不同导入选择器的结果进行分组的接口。
    	 */
    	interface Group {
    
    		/**
    		 * 使用指定的 DeferredImportSelector 处理导入的 @Configuration 类的 AnnotationMetadata。
    		 */
    		void process(AnnotationMetadata metadata, DeferredImportSelector selector);
    
    		Iterable<Entry> selectImports();
    
    		class Entry {
    
    			private final AnnotationMetadata metadata;
    
    			private final String importClassName;
    
    			public Entry(AnnotationMetadata metadata, String importClassName) {
    				this.metadata = metadata;
    				this.importClassName = importClassName;
    			}
    
    			/**
    			 * 返回导入的配置类的 AnnotationMetadata【注解元数据】
    			 */
    			public AnnotationMetadata getMetadata() {
    				return this.metadata;
    			}
    
    			/**
    			 * 返回要导入的类的完全限定名称。
    			 */
    			public String getImportClassName() {
    				return this.importClassName;
    			}
    			// 省
    		}
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    区别:
    ImportSelector:实例的selectImports方法的执行时机,是在@Configguration注解中的其他逻辑被处理之前,所谓的其他逻辑,包括对@ImportResource、@Bean这些注解的处理(注意,这里只是对@Bean修饰的方法的处理,并不是立即调用@Bean修饰的方法,这个区别很重要!)

    DeferredImportSelector:实例的selectImports方法的执行时机,是在@Configguration注解中的其他逻辑被处理完毕之后,所谓的其他逻辑,包括对@ImportResource、@Bean这些注解的处理.

    上述源码注释中,也说明了 DeferredImportSelector 的加载顺序可以通过 @Order 注解 或 实现 Ordered 接口来指定。它还可以提供一个导入组,实现在不同的选择器之间提供额外的排序和过滤逻辑,从而实现自定义 Configuration 的加载顺序。

    但是如果我们重写了DeferredImportSelector中的Group接口,并重写了getImportGroup,那么容器在启动的时候就不会执行selectImports方法了,而是执行getImportGroup方法。进而执行Group中重写的方法。

    3. 核心类AutoConfigurationImportSelector

    它是基于ImportSelector来实现基于动态bean的加载功能。通过selectImports()返回的数组(类的全类名)都会被纳入到spring容器中。
    在selectImports()中会执行getAutoConfigurationEntry(),
    但是 什么时候会进入到当前的方法中,入口在哪里 什么时候进来的?

    	@Override
    	public String[] selectImports(AnnotationMetadata annotationMetadata) {
    		// 检查自动配置功能是否开启,默认为开启
    		if (!isEnabled(annotationMetadata)) {
    			return NO_IMPORTS;
    		}
    		// 封装将被引入的自动配置信息
    		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
    		// 返回符合条件的配置类的全限定名数组
    		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    	}
    	
    	/**
    	 * 根据导入@Configuration类的AnnotationMetadata返回AutoConfigurationImportSelector.AutoConfigurationEntry。
    	 * @param 配置类的注解元数据。
    	 * @return 应该导入的自动配置。
    	 */
    	protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    		if (!isEnabled(annotationMetadata)) {
    			return EMPTY_ENTRY;
    		}
    		// 从AnnotationMetadata返回适当的AnnotationAttributes。默认情况下,此方法将返回getAnnotationClass()的属性。
    		AnnotationAttributes attributes = getAttributes(annotationMetadata);
    		// 通过 SpringFactoriesLoader 类提供的方法加载类路径中META-INF目录下的
    		// spring.factories文件中针对 EnableAutoConfiguration 的注解配置类
    		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    		// 对获得的注解配置类集合进行去重处理,防止多个项目引入同样的配置类
    		configurations = removeDuplicates(configurations);
    		// 获得注解中被 exclude 或 excludeName 所排除的类的集合
    		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    		// 检查被排除类是否可实例化,是否被自动注册配置所使用,不符合条件则抛出异常
    		checkExcludedClasses(configurations, exclusions);
    		// 从自动配置类集合中去除被排除的类
    		configurations.removeAll(exclusions);
    		// 检查配置类的注解是否符合 spring.factories 文件中 AutoConfigurationImportFilter 指定的注解检查条件
    		configurations = getConfigurationClassFilter().filter(configurations);
    		// 将筛选完成的配置类和排除的配置类构建为事件类,并传入监听器。监听器的配置在于 spring.factories 文件中,通过 AutoConfigurationImportListener 指定
    		fireAutoConfigurationImportEvents(configurations, exclusions);
    		// 创建并返回一个条目,其中包含了筛选完成的配置类和排除的配置
    		return new AutoConfigurationEntry(configurations, exclusions);
    	}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    二、自动装配代码分析

    在上面讲过了关键的两个方法selectImports()和getAutoConfigurationEntry(),这两个方法是什么时候调用的?

    1、SpringApplication#run() 方法

    prepareContext()此处完成自动装配的过程

    public ConfigurableApplicationContext run(String... args) {
    		StopWatch stopWatch = new StopWatch();
    		stopWatch.start();
    		ConfigurableApplicationContext context = null;
    		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    		configureHeadlessProperty();
    		SpringApplicationRunListeners listeners = getRunListeners(args);
    		listeners.starting();
    		try {
    			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
    			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
    			configureIgnoreBeanInfo(environment);
    			Banner printedBanner = printBanner(environment);
    			context = createApplicationContext();
    			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
    					new Class[] { ConfigurableApplicationContext.class }, context);
                //此处完成自动装配的过程
    			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
    			refreshContext(context);
    			afterRefresh(context, applicationArguments);
    			stopWatch.stop();
    			if (this.logStartupInfo) {
    				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
    			}
    			listeners.started(context);
    			callRunners(context, applicationArguments);
    		}
    		catch (Throwable ex) {
    			handleRunFailure(context, ex, exceptionReporters, listeners);
    			throw new IllegalStateException(ex);
    		}
    
    		try {
    			listeners.running(context);
    		}
    		catch (Throwable ex) {
    			handleRunFailure(context, ex, exceptionReporters, null);
    			throw new IllegalStateException(ex);
    		}
    		return context;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    2、SpringApplication#prepareContext()

    方法中查找load方法,一层一层向内点击,找到最终的load方法

    //prepareContext方法
    	private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
    			SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
    		context.setEnvironment(environment);
    		postProcessApplicationContext(context);
    		applyInitializers(context);
    		listeners.contextPrepared(context);
    		if (this.logStartupInfo) {
    			logStartupInfo(context.getParent() == null);
    			logStartupProfileInfo(context);
    		}
    		// Add boot specific singleton beans
    		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
    		if (printedBanner != null) {
    			beanFactory.registerSingleton("springBootBanner", printedBanner);
    		}
    		if (beanFactory instanceof DefaultListableBeanFactory) {
    			((DefaultListableBeanFactory) beanFactory)
    					.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
    		}
    		if (this.lazyInitialization) {
    			context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
    		}
    		// Load the sources
    		Set<Object> sources = getAllSources();
    		Assert.notEmpty(sources, "Sources must not be empty");
            //load方法完成该功能
    		load(context, sources.toArray(new Object[0]));
    		listeners.contextLoaded(context);
    	}
    
    
    	/**
    	 * Load beans into the application context.
    	 * @param context the context to load beans into
    	 * @param sources the sources to load
    	 * 加载bean对象到context中
    	 */
    	protected void load(ApplicationContext context, Object[] sources) {
    		if (logger.isDebugEnabled()) {
    			logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
    		}
            //获取bean对象定义的加载器
    		BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
    		if (this.beanNameGenerator != null) {
    			loader.setBeanNameGenerator(this.beanNameGenerator);
    		}
    		if (this.resourceLoader != null) {
    			loader.setResourceLoader(this.resourceLoader);
    		}
    		if (this.environment != null) {
    			loader.setEnvironment(this.environment);
    		}
    		loader.load();
    	}
    
    	/**
    	 * Load the sources into the reader.
    	 * @return the number of loaded beans
    	 */
    	int load() {
    		int count = 0;
    		for (Object source : this.sources) {
    			count += load(source);
    		}
    		return count;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    3、BeanDefinitionLoader#load()

    实际执行load的是BeanDefinitionLoader中的load方法,如下:

    	//实际记载bean的方法
    	private int load(Object source) {
    		Assert.notNull(source, "Source must not be null");
            //如果是class类型,启用注解类型
    		if (source instanceof Class<?>) {
    			return load((Class<?>) source);
    		}
            //如果是resource类型,启动xml解析
    		if (source instanceof Resource) {
    			return load((Resource) source);
    		}
            //如果是package类型,启用扫描包,例如@ComponentScan
    		if (source instanceof Package) {
    			return load((Package) source);
    		}
            //如果是字符串类型,直接加载
    		if (source instanceof CharSequence) {
    			return load((CharSequence) source);
    		}
    		throw new IllegalArgumentException("Invalid source type " + source.getClass());
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    4、load()

    下面方法将用来判断是否资源的类型,是使用groovy加载还是使用注解的方式

    	private int load(Class<?> source) {
            //判断使用groovy脚本
    		if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
    			// Any GroovyLoaders added in beans{} DSL can contribute beans here
    			GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
    			load(loader);
    		}
            //使用注解加载
    		if (isComponent(source)) {
    			this.annotatedReader.register(source);
    			return 1;
    		}
    		return 0;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    5、isComponent()

    判断启动类中是否包含@Component注解,但是会神奇的发现我们的启动类中并没有该注解,继续更进发现MergedAnnotations类传入了一个参数SearchStrategy.TYPE_HIERARCHY,会查找继承关系中是否包含这个注解,@SpringBootApplication–>@SpringBootConfiguration–>@Configuration–>@Component,当找到@Component注解之后,会把该对象注册到AnnotatedBeanDefinitionReader对象中

    private boolean isComponent(Class<?> type) {
       // This has to be a bit of a guess. The only way to be sure that this type is
       // eligible is to make a bean definition out of it and try to instantiate it.
       if (MergedAnnotations.from(type, SearchStrategy.TYPE_HIERARCHY).isPresent(Component.class)) {
          return true;
       }
       // Nested anonymous classes are not eligible for registration, nor are groovy
       // closures
       return !type.getName().matches(".*\\$_.*closure.*") && !type.isAnonymousClass()
             && type.getConstructors() != null && type.getConstructors().length != 0;
    }
    
    	/**
    	 * Register a bean from the given bean class, deriving its metadata from
    	 * class-declared annotations.
    	 * 从给定的bean class中注册一个bean对象,从注解中找到相关的元数据
    	 */
    	private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
    			@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
    			@Nullable BeanDefinitionCustomizer[] customizers) {
    
    		AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
    		if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
    			return;
    		}
    
    		abd.setInstanceSupplier(supplier);
    		ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
    		abd.setScope(scopeMetadata.getScopeName());
    		String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
    
    		AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
    		if (qualifiers != null) {
    			for (Class<? extends Annotation> qualifier : qualifiers) {
    				if (Primary.class == qualifier) {
    					abd.setPrimary(true);
    				}
    				else if (Lazy.class == qualifier) {
    					abd.setLazyInit(true);
    				}
    				else {
    					abd.addQualifier(new AutowireCandidateQualifier(qualifier));
    				}
    			}
    		}
    		if (customizers != null) {
    			for (BeanDefinitionCustomizer customizer : customizers) {
    				customizer.customize(abd);
    			}
    		}
    
    		BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
    		definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
    		BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
    	}
    
    	/**
    	 * Register the given bean definition with the given bean factory.
    	 * 注册主类,如果有别名可以设置别名
    	 */
    	public static void registerBeanDefinition(
    			BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
    			throws BeanDefinitionStoreException {
    
    		// Register bean definition under primary name.
    		String beanName = definitionHolder.getBeanName();
    		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    
    		// Register aliases for bean name, if any.
    		String[] aliases = definitionHolder.getAliases();
    		if (aliases != null) {
    			for (String alias : aliases) {
    				registry.registerAlias(beanName, alias);
    			}
    		}
    	}
    
    //@SpringBootApplication
    @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 {}
    
    //@SpringBootConfiguration
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Configuration
    public @interface SpringBootConfiguration {}
    
    //@Configuration
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Component
    public @interface Configuration {}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101

    分割线:当看完上述代码之后,只是完成了启动对象的注入,自动装配还没有开始,下面开始进入到自动装配。

    自动装配入口,从刷新容器开始

    6、SpringApplication#refreshContext()

    7、AbstractApplicationContext#refresh()

    @Override
    	public void refresh() throws BeansException, IllegalStateException {
    		synchronized (this.startupShutdownMonitor) {
    			// Prepare this context for refreshing.
    			prepareRefresh();
    
    			// Tell the subclass to refresh the internal bean factory.
    			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
    			// Prepare the bean factory for use in this context.
    			prepareBeanFactory(beanFactory);
    
    			try {
    				// Allows post-processing of the bean factory in context subclasses.
    				postProcessBeanFactory(beanFactory);
    
    				// Invoke factory processors registered as beans in the context.
                    // 此处是自动装配的入口
    				invokeBeanFactoryPostProcessors(beanFactory);
                }
                //省略其他代码,重点代码在invokeBeanFactoryPostProcessors()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    7、invokeBeanFactoryPostProcessors()中完成bean的实例化和执行

    /**
    	 * Instantiate and invoke all registered BeanFactoryPostProcessor beans,
    	 * respecting explicit order if given.
    	 * 

    Must be called before singleton instantiation. */ protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { //开始执行beanFactoryPostProcessor对应实现类,需要知道的是beanFactoryPostProcessor是spring的扩展接口,在刷新容器之前,该接口可以用来修改bean元数据信息 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor) if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    8、invokeBeanFactoryPostProcessors()

    查看invokeBeanFactoryPostProcessors()的具体执行方法

    	public static void invokeBeanFactoryPostProcessors(
    			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
    
    		// Invoke BeanDefinitionRegistryPostProcessors first, if any.
    		Set<String> processedBeans = new HashSet<>();
    
    		if (beanFactory instanceof BeanDefinitionRegistry) {
    			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
    			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
    			List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
    			//开始遍历三个内部类,如果属于BeanDefinitionRegistryPostProcessor子类,加入到bean注册的集合,否则加入到regularPostProcessors
    			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
    				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
    					BeanDefinitionRegistryPostProcessor registryProcessor =
    							(BeanDefinitionRegistryPostProcessor) postProcessor;
    					registryProcessor.postProcessBeanDefinitionRegistry(registry);
    					registryProcessors.add(registryProcessor);
    				}
    				else {
    					regularPostProcessors.add(postProcessor);
    				}
    			}
    
    			// Do not initialize FactoryBeans here: We need to leave all regular beans
    			// uninitialized to let the bean factory post-processors apply to them!
    			// Separate between BeanDefinitionRegistryPostProcessors that implement
    			// PriorityOrdered, Ordered, and the rest.
    			List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
    
    			// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
                //通过BeanDefinitionRegistryPostProcessor获取到对应的处理类“org.springframework.context.annotation.internalConfigurationAnnotationProcessor”,但是需要注意的是这个类在springboot中搜索不到,这个类的完全限定名在AnnotationConfigEmbeddedWebApplicationContext中,在进行初始化的时候会装配几个类,在创建AnnotatedBeanDefinitionReader对象的时候会将该类注册到bean对象中,此处可以看到internalConfigurationAnnotationProcessor为bean名称,容器中真正的类是ConfigurationClassPostProcessor
    			String[] postProcessorNames =
    					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
                //首先执行类型为PriorityOrdered的BeanDefinitionRegistryPostProcessor
                //PriorityOrdered类型表明为优先执行
    			for (String ppName : postProcessorNames) {
    				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                        //获取对应的bean
    					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                        //用来存储已经执行过的BeanDefinitionRegistryPostProcessor
    					processedBeans.add(ppName);
    				}
    			}
    			sortPostProcessors(currentRegistryProcessors, beanFactory);
    			registryProcessors.addAll(currentRegistryProcessors);
                //开始执行装配逻辑
    			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
    			currentRegistryProcessors.clear();
    
    			// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
                //其次执行类型为Ordered的BeanDefinitionRegistryPostProcessor
                //Ordered表明按顺序执行
    			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
    			for (String ppName : postProcessorNames) {
    				if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
    					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
    					processedBeans.add(ppName);
    				}
    			}
    			sortPostProcessors(currentRegistryProcessors, beanFactory);
    			registryProcessors.addAll(currentRegistryProcessors);
    			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
    			currentRegistryProcessors.clear();
    
    			// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
                //循环中执行类型不为PriorityOrdered,Ordered类型的BeanDefinitionRegistryPostProcessor
    			boolean reiterate = true;
    			while (reiterate) {
    				reiterate = false;
    				postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
    				for (String ppName : postProcessorNames) {
    					if (!processedBeans.contains(ppName)) {
    						currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
    						processedBeans.add(ppName);
    						reiterate = true;
    					}
    				}
    				sortPostProcessors(currentRegistryProcessors, beanFactory);
    				registryProcessors.addAll(currentRegistryProcessors);
    				invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
    				currentRegistryProcessors.clear();
    			}
    
    			// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
                //执行父类方法,优先执行注册处理类
    			invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
                //执行有规则处理类
    			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
    		}
    
    		else {
    			// Invoke factory processors registered with the context instance.
    			invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
    		}
    
    		// Do not initialize FactoryBeans here: We need to leave all regular beans
    		// uninitialized to let the bean factory post-processors apply to them!
    		String[] postProcessorNames =
    				beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
    
    		// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
    		// Ordered, and the rest.
    		List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
    		List<String> orderedPostProcessorNames = new ArrayList<>();
    		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
    		for (String ppName : postProcessorNames) {
    			if (processedBeans.contains(ppName)) {
    				// skip - already processed in first phase above
    			}
    			else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
    				priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
    			}
    			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
    				orderedPostProcessorNames.add(ppName);
    			}
    			else {
    				nonOrderedPostProcessorNames.add(ppName);
    			}
    		}
    
    		// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
    		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    		invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
    
    		// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
    		List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
    		for (String postProcessorName : orderedPostProcessorNames) {
    			orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    		}
    		sortPostProcessors(orderedPostProcessors, beanFactory);
    		invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
    
    		// Finally, invoke all other BeanFactoryPostProcessors.
    		List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
    		for (String postProcessorName : nonOrderedPostProcessorNames) {
    			nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    		}
    		invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
    
    		// Clear cached merged bean definitions since the post-processors might have
    		// modified the original metadata, e.g. replacing placeholders in values...
    		beanFactory.clearMetadataCache();
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143

    9、ConfigurationClassParser#parse()

    这里是Spring的知识,可以看之前的Spring的分析,最终会走到这个方法里面,可以通过debug的方式一层层向里进行查找,最终会在ConfigurationClassParser类中,此类是所有配置类的解析类,所有的解析逻辑在parser.parse(candidates)中

    public void parse(Set<BeanDefinitionHolder> configCandidates) {
    		for (BeanDefinitionHolder holder : configCandidates) {
    			BeanDefinition bd = holder.getBeanDefinition();
    			try {
                    //是否是注解类
    				if (bd instanceof AnnotatedBeanDefinition) {
    					parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
    				}
    				else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
    					parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
    				}
    				else {
    					parse(bd.getBeanClassName(), holder.getBeanName());
    				}
    			}
    			catch (BeanDefinitionStoreException ex) {
    				throw ex;
    			}
    			catch (Throwable ex) {
    				throw new BeanDefinitionStoreException(
    						"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
    			}
    		}
        	//执行配置类
    		this.deferredImportSelectorHandler.process();
    	}
    -------------------
        	protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
    		processConfigurationClass(new ConfigurationClass(metadata, beanName));
    	}
    -------------------
        protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
    		if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
    			return;
    		}
    
    		ConfigurationClass existingClass = this.configurationClasses.get(configClass);
    		if (existingClass != null) {
    			if (configClass.isImported()) {
    				if (existingClass.isImported()) {
    					existingClass.mergeImportedBy(configClass);
    				}
    				// Otherwise ignore new imported config class; existing non-imported class overrides it.
    				return;
    			}
    			else {
    				// Explicit bean definition found, probably replacing an import.
    				// Let's remove the old one and go with the new one.
    				this.configurationClasses.remove(configClass);
    				this.knownSuperclasses.values().removeIf(configClass::equals);
    			}
    		}
    
    		// Recursively process the configuration class and its superclass hierarchy.
    		SourceClass sourceClass = asSourceClass(configClass);
    		do {
                //循环处理bean,如果有父类,则处理父类,直至结束
    			sourceClass = doProcessConfigurationClass(configClass, sourceClass);
    		}
    		while (sourceClass != null);
    
    		this.configurationClasses.put(configClass, configClass);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    10、doProcessConfigurationClass()

    继续跟进doProcessConfigurationClass方法,此方式是支持注解配置的核心逻辑

    /**
    	 * Apply processing and build a complete {@link ConfigurationClass} by reading the
    	 * annotations, members and methods from the source class. This method can be called
    	 * multiple times as relevant sources are discovered.
    	 * @param configClass the configuration class being build
    	 * @param sourceClass a source class
    	 * @return the superclass, or {@code null} if none found or previously processed
    	 */
    	@Nullable
    	protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
    			throws IOException {
    
            //处理内部类逻辑,由于传来的参数是启动类,并不包含内部类,所以跳过
    		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
    			// Recursively process any member (nested) classes first
    			processMemberClasses(configClass, sourceClass);
    		}
    
    		// Process any @PropertySource annotations
            //针对属性配置的解析
    		for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
    				sourceClass.getMetadata(), PropertySources.class,
    				org.springframework.context.annotation.PropertySource.class)) {
    			if (this.environment instanceof ConfigurableEnvironment) {
    				processPropertySource(propertySource);
    			}
    			else {
    				logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
    						"]. Reason: Environment must implement ConfigurableEnvironment");
    			}
    		}
    
    		// Process any @ComponentScan annotations
            // 这里是根据启动类@ComponentScan注解来扫描项目中的bean
    		Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
    				sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
    		if (!componentScans.isEmpty() &&
    				!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
            
    			for (AnnotationAttributes componentScan : componentScans) {
    				// The config class is annotated with @ComponentScan -> perform the scan immediately
                    //遍历项目中的bean,如果是注解定义的bean,则进一步解析
    				Set<BeanDefinitionHolder> scannedBeanDefinitions =
    						this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
    				// Check the set of scanned definitions for any further config classes and parse recursively if needed
    				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
    					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
    					if (bdCand == null) {
    						bdCand = holder.getBeanDefinition();
    					}
    					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                            //递归解析,所有的bean,如果有注解,会进一步解析注解中包含的bean
    						parse(bdCand.getBeanClassName(), holder.getBeanName());
    					}
    				}
    			}
    		}
    
    		// Process any @Import annotations
            //递归解析,获取导入的配置类,很多情况下,导入的配置类中会同样包含导入类注解
    		processImports(configClass, sourceClass, getImports(sourceClass), true);
    
    		// Process any @ImportResource annotations
            //解析@ImportResource配置类
    		AnnotationAttributes importResource =
    				AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
    		if (importResource != null) {
    			String[] resources = importResource.getStringArray("locations");
    			Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
    			for (String resource : resources) {
    				String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
    				configClass.addImportedResource(resolvedResource, readerClass);
    			}
    		}
    
    		// Process individual @Bean methods
            //处理@Bean注解修饰的类
    		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
    		for (MethodMetadata methodMetadata : beanMethods) {
    			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
    		}
    
    		// Process default methods on interfaces
            // 处理接口中的默认方法
    		processInterfaces(configClass, sourceClass);
    
    		// Process superclass, if any
            //如果该类有父类,则继续返回,上层方法判断不为空,则继续递归执行
    		if (sourceClass.getMetadata().hasSuperClass()) {
    			String superclass = sourceClass.getMetadata().getSuperClassName();
    			if (superclass != null && !superclass.startsWith("java") &&
    					!this.knownSuperclasses.containsKey(superclass)) {
    				this.knownSuperclasses.put(superclass, configClass);
    				// Superclass found, return its annotation metadata and recurse
    				return sourceClass.getSuperClass();
    			}
    		}
    
    		// No superclass -> processing is complete
    		return null;
    	}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102

    11、doProcessConfigurationClass()->processImports()

    查看获取配置类的逻辑

    processImports(configClass, sourceClass, getImports(sourceClass), true);
    
    	/**
    	 * Returns {@code @Import} class, considering all meta-annotations.
    	 */
    	private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
    		Set<SourceClass> imports = new LinkedHashSet<>();
    		Set<SourceClass> visited = new LinkedHashSet<>();
    		collectImports(sourceClass, imports, visited);
    		return imports;
    	}
    ------------------
        	/**
    	 * Recursively collect all declared {@code @Import} values. Unlike most
    	 * meta-annotations it is valid to have several {@code @Import}s declared with
    	 * different values; the usual process of returning values from the first
    	 * meta-annotation on a class is not sufficient.
    	 * 

    For example, it is common for a {@code @Configuration} class to declare direct * {@code @Import}s in addition to meta-imports originating from an {@code @Enable} * annotation. * 看到所有的bean都以导入的方式被加载进去 */ private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited) throws IOException { if (visited.add(sourceClass)) { for (SourceClass annotation : sourceClass.getAnnotations()) { String annName = annotation.getMetadata().getClassName(); if (!annName.equals(Import.class.getName())) { collectImports(annotation, imports, visited); } } imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value")); } }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    12、回到第9步ConfigurationClassParser#parse()

    看该方法中的最后一行,继续跟进该方法:

    public void parse(Set<BeanDefinitionHolder> configCandidates) {
    		for (BeanDefinitionHolder holder : configCandidates) {
    			BeanDefinition bd = holder.getBeanDefinition();
    			try {
    				if (bd instanceof AnnotatedBeanDefinition) {
    					parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
    				}
    				else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
    					parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
    				}
    				else {
    					parse(bd.getBeanClassName(), holder.getBeanName());
    				}
    			}
    			catch (BeanDefinitionStoreException ex) {
    				throw ex;
    			}
    			catch (Throwable ex) {
    				throw new BeanDefinitionStoreException(
    						"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
    			}
    		}
    
    		this.deferredImportSelectorHandler.process();
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    public void process() {
    			List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
    			this.deferredImportSelectors = null;
    			try {
    				if (deferredImports != null) {
    					DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
    					deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
    					deferredImports.forEach(handler::register);
    					handler.processGroupImports();
    				}
    			}
    			finally {
    				this.deferredImportSelectors = new ArrayList<>();
    			}
    		}
    ---------------
      public void processGroupImports() {
    			for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
    				grouping.getImports().forEach(entry -> {
    					ConfigurationClass configurationClass = this.configurationClasses.get(
    							entry.getMetadata());
    					try {
    						processImports(configurationClass, asSourceClass(configurationClass),
    								asSourceClasses(entry.getImportClassName()), false);
    					}
    					catch (BeanDefinitionStoreException ex) {
    						throw ex;
    					}
    					catch (Throwable ex) {
    						throw new BeanDefinitionStoreException(
    								"Failed to process import candidates for configuration class [" +
    										configurationClass.getMetadata().getClassName() + "]", ex);
    					}
    				});
    			}
    		}
    ------------
        /**
    		 * Return the imports defined by the group.
    		 * @return each import with its associated configuration class
    		 */
    		public Iterable<Group.Entry> getImports() {
    			for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
    				this.group.process(deferredImport.getConfigurationClass().getMetadata(),
    						deferredImport.getImportSelector());
    			}
    			return this.group.selectImports();
    		}
    	}
    ------------
        public DeferredImportSelector getImportSelector() {
    			return this.importSelector;
    		}
    ------------
        @Override
    		public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
    			Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
    					() -> String.format("Only %s implementations are supported, got %s",
    							AutoConfigurationImportSelector.class.getSimpleName(),
    							deferredImportSelector.getClass().getName()));
    			AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
    					.getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);
    			this.autoConfigurationEntries.add(autoConfigurationEntry);
    			for (String importClassName : autoConfigurationEntry.getConfigurations()) {
    				this.entries.putIfAbsent(importClassName, annotationMetadata);
    			}
    		}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    总结:到这边算是完成了 自动装配的过程

    三、手写Starter

    通过手写Starter来加深对于自动装配的理解

    1.创建一个Maven项目,quick-starter

    定义相关的依赖

    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starterartifactId>
        <version>2.1.6.RELEASEversion>
    dependency>
    <dependency>
        <groupId>com.alibabagroupId>
        <artifactId>fastjsonartifactId>
        <version>1.2.56version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2.定义Formate接口

    定义的格式转换的接口,并且定义两个实现类

    public interface FormatProcessor {
        /**
         * 定义一个格式化的方法
         * @param obj
         * @param 
         * @return
         */
         String formate(T obj);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    public class JsonFormatProcessor implements FormatProcessor {
        @Override
        public  String formate(T obj) {
            return "JsonFormatProcessor:" + JSON.toJSONString(obj);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    public class StringFormatProcessor implements FormatProcessor {
        @Override
        public  String formate(T obj) {
            return "StringFormatProcessor:" + obj.toString();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.定义相关的配置类

    3.1 首先定义格式化加载的Java配置类

    @Configuration
    public class FormatAutoConfiguration {
    
        @ConditionalOnMissingClass("com.alibaba.fastjson.JSON")
        @Bean
        @Primary // 优先加载
        public FormatProcessor stringFormatProcessor(){
            return new StringFormatProcessor();
        }
    
        @ConditionalOnClass(name="com.alibaba.fastjson.JSON")
        @Bean
        public FormatProcessor jsonFormatProcessor(){
            return new JsonFormatProcessor();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    3.2 定义一个模板工具类

    public class HelloFormatTemplate {
    
        private FormatProcessor formatProcessor;
    
    
        public HelloFormatTemplate(FormatProcessor processor){
            this.formatProcessor = processor;
        }
    
        public  String doFormat(T obj){
            StringBuilder builder = new StringBuilder();
            builder.append("Execute format : ").append("
    "); builder.append("Object format result:" ).append(formatProcessor.formate(obj)); return builder.toString(); } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    3.3 整合到SpringBoot中去的Java配置类

    @Configuration
    @Import(FormatAutoConfiguration.class)
    public class HelloAutoConfiguration {
    
        @Bean
        public HelloFormatTemplate helloFormatTemplate(FormatProcessor formatProcessor){
            return new HelloFormatTemplate(formatProcessor);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    4.创建spring.factories文件

    在resources下创建META-INF目录,再在其下创建spring.factories文件

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
      org.mashibingedu.autoconfiguration.HelloAutoConfiguration
    
    • 1
    • 2

    install 打包,然后就可以在SpringBoot项目中依赖改项目来操作了。

    5.测试

    5.1 在SpringBoot中引入依赖

    
        org.example
        format-spring-boot-starter
        1.0-SNAPSHOT
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5.2 在controller中使用

    @RestController
    public class UserController {
    
        @Autowired
        private HelloFormatTemplate helloFormatTemplate;
    
        @GetMapping("/format")
        public String format(){
            User user = new User();
            user.setName("BoBo");
            user.setAge(18);
            return helloFormatTemplate.doFormat(user);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    6.自定义Starter关联配置信息

    有些情况下我们可以需要用户在使用的时候动态的传递相关的配置信息,比如Redis的Ip,端口等等,这些信息显然是不能直接写到代码中的,这时我们就可以通过SpringBoot的配置类来实现。

    6.1 首先引入依赖支持

    
        org.springframework.boot
        spring-boot-configuration-processor
        2.2.6.RELEASE
        true
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    6.2 创建对应的属性类

    @ConfigurationProperties(prefix = HelloProperties.HELLO_FORMAT_PREFIX)
    public class HelloProperties {
    
        public static final String HELLO_FORMAT_PREFIX="mashibing.hello.format";
    
        private String name;
    
        private Integer age;
    
        private Map info;
    
        public Map getInfo() {
            return info;
        }
    
        public void setInfo(Map info) {
            this.info = info;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    6.3 在Java配置类中关联

    @Configuration
    @Import(FormatAutoConfiguration.class)
    @EnableConfigurationProperties(HelloProperties.class)
    public class HelloAutoConfiguration {
    
        @Bean
        public HelloFormatTemplate helloFormatTemplate(HelloProperties helloProperties,FormatProcessor formatProcessor){
            return new HelloFormatTemplate(helloProperties,formatProcessor);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    调整模板方法

    public class HelloFormatTemplate {
    
        private FormatProcessor formatProcessor;
    
        private HelloProperties helloProperties;
    
        public HelloFormatTemplate(HelloProperties helloProperties,FormatProcessor processor){
            this.helloProperties = helloProperties;
            this.formatProcessor = processor;
        }
    
        public  String doFormat(T obj){
            StringBuilder builder = new StringBuilder();
            builder.append("Execute format : ").append("
    "); builder.append("HelloProperties:").append(formatProcessor.formate(helloProperties.getInfo())).append("
    "); builder.append("Object format result:" ).append(formatProcessor.formate(obj)); return builder.toString(); } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    6.4 增加提示

    在这个工程的META-INF/下创建一个additional-spring-configuration-metadata.json,这个是设置属性的提示类型

    {
      "properties": [
        {
          "name": "mashibing.hello.format.name",
          "type": "java.lang.String",
          "description": "账号信息",
          "defaultValue": "root"
        },{
          "name": "mashibing.hello.format.age",
          "type": "java.lang.Integer",
          "description": "年龄",
          "defaultValue": 18
        }
      ]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    	protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    		if (!isEnabled(annotationMetadata)) {
    			return EMPTY_ENTRY;
    		}
    		AnnotationAttributes attributes = getAttributes(annotationMetadata);
            // 加载当前系统下 META-INF/spring.factories 文件中声明的配置类
    		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);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
  • 相关阅读:
    详解python淘宝秒杀抢购脚本程序实现
    从0到一开发微信小程序(2)——开发第一个小程序
    Java GUI——Java图形用户界面
    JavaScript进阶之路(一)初学者的开始
    电影售票系统遇到的问题
    03JVM_类加载
    LeetCode25:K个一组翻转链表
    蓝牙音视频远程控制协议(AVRCP)介绍
    51单片机毕业设计开题报告建议
    怎么理解flink的异步检查点机制
  • 原文地址:https://blog.csdn.net/springsdl/article/details/133996366