亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > Java > 正文

深入淺析SpringBoot中的自動裝配

2024-07-14 08:40:48
字體:
來源:轉載
供稿:網友

SpringBoot的自動裝配是拆箱即用的基礎,也是微服務化的前提。這次主要的議題是,來看看它是怎么樣實現的,我們透過源代碼來把握自動裝配的來龍去脈。

一、自動裝配過程分析

1.1、關于@SpringBootApplication

  我們在編寫SpringBoot項目時,@SpringBootApplication是最常見的注解了,我們可以看一下源代碼:

/* * Copyright 2012-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.springframework.boot.autoconfigure;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Inherited;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import org.springframework.boot.SpringBootConfiguration;import org.springframework.boot.context.TypeExcludeFilter;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.ComponentScan.Filter;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.FilterType;import org.springframework.core.annotation.AliasFor;/** * Indicates a {@link Configuration configuration} class that declares one or more * {@link Bean @Bean} methods and also triggers {@link EnableAutoConfiguration * auto-configuration} and {@link ComponentScan component scanning}. This is a convenience * annotation that is equivalent to declaring {@code @Configuration}, * {@code @EnableAutoConfiguration} and {@code @ComponentScan}. * * @author Phillip Webb * @author Stephane Nicoll * @since 1.2.0 */@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 { /** * Exclude specific auto-configuration classes such that they will never be applied. * @return the classes to exclude */ @AliasFor(annotation = EnableAutoConfiguration.class, attribute = "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 */ @AliasFor(annotation = EnableAutoConfiguration.class, attribute = "excludeName") String[] excludeName() default {}; /** * Base packages to scan for annotated components. Use {@link #scanBasePackageClasses} * for a type-safe alternative to String-based package names. * @return base packages to scan * @since 1.3.0 */ @AliasFor(annotation = ComponentScan.class, attribute = "basePackages") String[] scanBasePackages() default {}; /** * Type-safe alternative to {@link #scanBasePackages} for specifying the packages to * scan for annotated components. The package of each class specified will be scanned. * <p> * Consider creating a special no-op marker class or interface in each package that * serves no purpose other than being referenced by this attribute. * @return base packages to scan * @since 1.3.0 */ @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses") Class<?>[] scanBasePackageClasses() default {};}

  這里面包含了@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan,此處@ComponentScan由于沒有指定掃描包,因此它默認掃描的是與該類同級的類或者同級包下的所有類,另外@SpringBootConfiguration,通過源碼得知它是一個@Configuration:

/* * Copyright 2012-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.springframework.boot;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import org.springframework.context.annotation.Configuration;/** * Indicates that a class provides Spring Boot application * {@link Configuration @Configuration}. Can be used as an alternative to the Spring's * standard {@code @Configuration} annotation so that configuration can be found * automatically (for example in tests). * <p> * Application should only ever include <em>one</em> {@code @SpringBootConfiguration} and * most idiomatic Spring Boot applications will inherit it from * {@code @SpringBootApplication}. * * @author Phillip Webb * @since 1.4.0 */@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Configurationpublic @interface SpringBootConfiguration {}

  由此我們可以推斷出@SpringBootApplication等同于@Configuration @ComponentScan @EnableAutoConfiguration

1.2、@EnableAutoConfiguration

  一旦加上此注解,那么將會開啟自動裝配功能,簡單點講,Spring會試圖在你的classpath下找到所有配置的Bean然后進行裝配。當然裝配Bean時,會根據若干個(Conditional)定制規則來進行初始化。我們看一下它的源碼:

/* * Copyright 2012-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.springframework.boot.autoconfigure;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Inherited;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;import org.springframework.context.annotation.Conditional;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Import;import org.springframework.core.io.support.SpringFactoriesLoader;/** * Enable auto-configuration of the Spring Application Context, attempting to guess and * configure beans that you are likely to need. Auto-configuration classes are usually * applied based on your classpath and what beans you have defined. For example, If you * have {@code tomcat-embedded.jar} on your classpath you are likely to want a * {@link TomcatEmbeddedServletContainerFactory} (unless you have defined your own * {@link EmbeddedServletContainerFactory} bean). * <p> * When using {@link SpringBootApplication}, the auto-configuration of the context is * automatically enabled and adding this annotation has therefore no additional effect. * <p> * Auto-configuration tries to be as intelligent as possible and will back-away as you * define more of your own configuration. You can always manually {@link #exclude()} any * configuration that you never want to apply (use {@link #excludeName()} if you don't * have access to them). You can also exclude them via the * {@code spring.autoconfigure.exclude} property. Auto-configuration is always applied * after user-defined beans have been registered. * <p> * The package of the class that is annotated with {@code @EnableAutoConfiguration}, * usually via {@code @SpringBootApplication}, has specific significance and is often used * as a 'default'. For example, it will be used when scanning for {@code @Entity} classes. * It is generally recommended that you place {@code @EnableAutoConfiguration} (if you're * not using {@code @SpringBootApplication}) in a root package so that all sub-packages * and classes can be searched. * <p> * Auto-configuration classes are regular Spring {@link Configuration} beans. They are * located using the {@link SpringFactoriesLoader} mechanism (keyed against this class). * Generally auto-configuration beans are {@link Conditional @Conditional} beans (most * often using {@link ConditionalOnClass @ConditionalOnClass} and * {@link ConditionalOnMissingBean @ConditionalOnMissingBean} annotations). * * @author Phillip Webb * @author Stephane Nicoll * @see ConditionalOnBean * @see ConditionalOnMissingBean * @see ConditionalOnClass * @see AutoConfigureAfter * @see SpringBootApplication */@SuppressWarnings("deprecation")@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage@Import(EnableAutoConfigurationImportSelector.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 {};}

  雖然根據文檔注釋的說明它指點我們去看EnableAutoConfigurationImportSelector。但是該類在SpringBoot1.5.X版本已經過時了,因此我們看一下它的父類AutoConfigurationImportSelector:

/* * Copyright 2012-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.springframework.boot.autoconfigure;import java.io.IOException;import java.util.ArrayList;import java.util.Arrays;import java.util.Collections;import java.util.HashSet;import java.util.LinkedHashSet;import java.util.List;import java.util.Map;import java.util.Set;import java.util.concurrent.TimeUnit;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.springframework.beans.BeansException;import org.springframework.beans.factory.Aware;import org.springframework.beans.factory.BeanClassLoaderAware;import org.springframework.beans.factory.BeanFactory;import org.springframework.beans.factory.BeanFactoryAware;import org.springframework.beans.factory.NoSuchBeanDefinitionException;import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;import org.springframework.boot.bind.RelaxedPropertyResolver;import org.springframework.context.EnvironmentAware;import org.springframework.context.ResourceLoaderAware;import org.springframework.context.annotation.DeferredImportSelector;import org.springframework.core.Ordered;import org.springframework.core.annotation.AnnotationAttributes;import org.springframework.core.env.ConfigurableEnvironment;import org.springframework.core.env.Environment;import org.springframework.core.io.ResourceLoader;import org.springframework.core.io.support.SpringFactoriesLoader;import org.springframework.core.type.AnnotationMetadata;import org.springframework.core.type.classreading.CachingMetadataReaderFactory;import org.springframework.core.type.classreading.MetadataReaderFactory;import org.springframework.util.Assert;import org.springframework.util.ClassUtils;import org.springframework.util.StringUtils;/** * {@link DeferredImportSelector} to handle {@link EnableAutoConfiguration * auto-configuration}. This class can also be subclassed if a custom variant of * {@link EnableAutoConfiguration @EnableAutoConfiguration}. is needed. * * @author Phillip Webb * @author Andy Wilkinson * @author Stephane Nicoll * @author Madhura Bhave * @since 1.3.0 * @see EnableAutoConfiguration */public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered { private static final String[] NO_IMPORTS = {}; private static final Log logger = LogFactory .getLog(AutoConfigurationImportSelector.class); private ConfigurableListableBeanFactory beanFactory; private Environment environment; private ClassLoader beanClassLoader; private ResourceLoader resourceLoader; @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } try { AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader  .loadMetadata(this.beanClassLoader); AnnotationAttributes attributes = getAttributes(annotationMetadata); List<String> configurations = getCandidateConfigurations(annotationMetadata,  attributes); configurations = removeDuplicates(configurations); configurations = sort(configurations, autoConfigurationMetadata); Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = filter(configurations, autoConfigurationMetadata); fireAutoConfigurationImportEvents(configurations, exclusions); return configurations.toArray(new String[configurations.size()]); } catch (IOException ex) { throw new IllegalStateException(ex); } } protected boolean isEnabled(AnnotationMetadata metadata) { return true; } /** * Return the appropriate {@link AnnotationAttributes} from the * {@link AnnotationMetadata}. By default this method will return attributes for * {@link #getAnnotationClass()}. * @param metadata the annotation metadata * @return annotation attributes */ protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) { 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; } /** * Return the source annotation class used by the selector. * @return the annotation class */ protected Class<?> getAnnotationClass() { return EnableAutoConfiguration.class; } /** * Return the auto-configuration class names that should be considered. By default * this method will load candidates using {@link SpringFactoriesLoader} with * {@link #getSpringFactoriesLoaderFactoryClass()}. * @param metadata the source metadata * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation * attributes} * @return a list of candidate configurations */ 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; } /** * Return the class used by {@link SpringFactoriesLoader} to load configuration * candidates. * @return the factory class */ protected Class<?> getSpringFactoriesLoaderFactoryClass() { return EnableAutoConfiguration.class; } private void checkExcludedClasses(List<String> configurations, Set<String> exclusions) { List<String> invalidExcludes = new ArrayList<String>(exclusions.size()); for (String exclusion : exclusions) { if (ClassUtils.isPresent(exclusion, getClass().getClassLoader())  && !configurations.contains(exclusion)) { invalidExcludes.add(exclusion); } } if (!invalidExcludes.isEmpty()) { handleInvalidExcludes(invalidExcludes); } } /** * Handle any invalid excludes that have been specified. * @param invalidExcludes the list of invalid excludes (will always have at least one * element) */ protected void handleInvalidExcludes(List<String> invalidExcludes) { StringBuilder message = new StringBuilder(); for (String exclude : invalidExcludes) { message.append("/t- ").append(exclude).append(String.format("%n")); } throw new IllegalStateException(String .format("The following classes could not be excluded because they are"  + " not auto-configuration classes:%n%s", message)); } /** * Return any exclusions that limit the candidate configurations. * @param metadata the source metadata * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation * attributes} * @return exclusions or an empty set */ protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) { Set<String> excluded = new LinkedHashSet<String>(); excluded.addAll(asList(attributes, "exclude")); excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName"))); excluded.addAll(getExcludeAutoConfigurationsProperty()); return excluded; } private List<String> getExcludeAutoConfigurationsProperty() { if (getEnvironment() instanceof ConfigurableEnvironment) { RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(  this.environment, "spring.autoconfigure."); Map<String, Object> properties = resolver.getSubProperties("exclude"); if (properties.isEmpty()) { return Collections.emptyList(); } List<String> excludes = new ArrayList<String>(); for (Map.Entry<String, Object> entry : properties.entrySet()) { String name = entry.getKey(); Object value = entry.getValue(); if (name.isEmpty() || name.startsWith("[") && value != null) {  excludes.addAll(new HashSet<String>(Arrays.asList(StringUtils  .tokenizeToStringArray(String.valueOf(value), ",")))); } } return excludes; } RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(getEnvironment(), "spring.autoconfigure."); String[] exclude = resolver.getProperty("exclude", String[].class); return (Arrays.asList(exclude == null ? new String[0] : exclude)); } private List<String> sort(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) throws IOException { configurations = new AutoConfigurationSorter(getMetadataReaderFactory(), autoConfigurationMetadata).getInPriorityOrder(configurations); return configurations; } private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) { long startTime = System.nanoTime(); String[] candidates = configurations.toArray(new String[configurations.size()]); boolean[] skip = new boolean[candidates.length]; boolean skipped = false; for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) { invokeAwareMethods(filter); boolean[] match = filter.match(candidates, autoConfigurationMetadata); for (int i = 0; i < match.length; i++) { if (!match[i]) {  skip[i] = true;  skipped = true; } } } if (!skipped) { return configurations; } List<String> result = new ArrayList<String>(candidates.length); for (int i = 0; i < candidates.length; i++) { if (!skip[i]) { result.add(candidates[i]); } } if (logger.isTraceEnabled()) { int numberFiltered = configurations.size() - result.size(); logger.trace("Filtered " + numberFiltered + " auto configuration class in "  + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)  + " ms"); } return new ArrayList<String>(result); } protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() { return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader); } private MetadataReaderFactory getMetadataReaderFactory() { try { return getBeanFactory().getBean(  SharedMetadataReaderFactoryContextInitializer.BEAN_NAME,  MetadataReaderFactory.class); } catch (NoSuchBeanDefinitionException ex) { return new CachingMetadataReaderFactory(this.resourceLoader); } } protected final <T> List<T> removeDuplicates(List<T> list) { return new ArrayList<T>(new LinkedHashSet<T>(list)); } protected final List<String> asList(AnnotationAttributes attributes, String name) { String[] value = attributes.getStringArray(name); return Arrays.asList(value == null ? new String[0] : value); } private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) { List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners(); if (!listeners.isEmpty()) { AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this,  configurations, exclusions); for (AutoConfigurationImportListener listener : listeners) { invokeAwareMethods(listener); listener.onAutoConfigurationImportEvent(event); } } } protected List<AutoConfigurationImportListener> getAutoConfigurationImportListeners() { return SpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class, this.beanClassLoader); } private void invokeAwareMethods(Object instance) { if (instance instanceof Aware) { if (instance instanceof BeanClassLoaderAware) { ((BeanClassLoaderAware) instance)  .setBeanClassLoader(this.beanClassLoader); } if (instance instanceof BeanFactoryAware) { ((BeanFactoryAware) instance).setBeanFactory(this.beanFactory); } if (instance instanceof EnvironmentAware) { ((EnvironmentAware) instance).setEnvironment(this.environment); } if (instance instanceof ResourceLoaderAware) { ((ResourceLoaderAware) instance).setResourceLoader(this.resourceLoader); } } } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { Assert.isInstanceOf(ConfigurableListableBeanFactory.class, beanFactory); this.beanFactory = (ConfigurableListableBeanFactory) beanFactory; } protected final ConfigurableListableBeanFactory getBeanFactory() { return this.beanFactory; } @Override public void setBeanClassLoader(ClassLoader classLoader) { this.beanClassLoader = classLoader; } protected ClassLoader getBeanClassLoader() { return this.beanClassLoader; } @Override public void setEnvironment(Environment environment) { this.environment = environment; } protected final Environment getEnvironment() { return this.environment; } @Override public void setResourceLoader(ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; } protected final ResourceLoader getResourceLoader() { return this.resourceLoader; } @Override public int getOrder() { return Ordered.LOWEST_PRECEDENCE - 1; }}

  首先該類實現了DeferredImportSelector接口,這個接口繼承了ImportSelector:

/* * Copyright 2002-2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.springframework.context.annotation;import org.springframework.core.type.AnnotationMetadata;/** * Interface to be implemented by types that determine which @{@link Configuration} * class(es) should be imported based on a given selection criteria, usually one or more * annotation attributes. * * <p>An {@link ImportSelector} may implement any of the following * {@link org.springframework.beans.factory.Aware Aware} interfaces, and their respective * methods will be called prior to {@link #selectImports}: * <ul> * <li>{@link org.springframework.context.EnvironmentAware EnvironmentAware}</li> * <li>{@link org.springframework.beans.factory.BeanFactoryAware BeanFactoryAware}</li> * <li>{@link org.springframework.beans.factory.BeanClassLoaderAware BeanClassLoaderAware}</li> * <li>{@link org.springframework.context.ResourceLoaderAware ResourceLoaderAware}</li> * </ul> * * <p>ImportSelectors are usually processed in the same way as regular {@code @Import} * annotations, however, it is also possible to defer selection of imports until all * {@code @Configuration} classes have been processed (see {@link DeferredImportSelector} * for details). * * @author Chris Beams * @since 3.1 * @see DeferredImportSelector * @see Import * @see ImportBeanDefinitionRegistrar * @see Configuration */public interface ImportSelector { /** * Select and return the names of which class(es) should be imported based on * the {@link AnnotationMetadata} of the importing @{@link Configuration} class. */ String[] selectImports(AnnotationMetadata importingClassMetadata);}

 

  該接口主要是為了導入@Configuration的配置項,而DeferredImportSelector是延期導入,當所有的@Configuration都處理過后才會執行。

  回過頭來我們看一下AutoConfigurationImportSelector的selectImport方法:

@Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } try { AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader  .loadMetadata(this.beanClassLoader); AnnotationAttributes attributes = getAttributes(annotationMetadata); List<String> configurations = getCandidateConfigurations(annotationMetadata,  attributes); configurations = removeDuplicates(configurations); configurations = sort(configurations, autoConfigurationMetadata); Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = filter(configurations, autoConfigurationMetadata); fireAutoConfigurationImportEvents(configurations, exclusions); return configurations.toArray(new String[configurations.size()]); } catch (IOException ex) { throw new IllegalStateException(ex); } }


  該方法剛開始會先判斷是否進行自動裝配,而后會從META-INF/spring-autoconfigure-metadata.properties讀取元數據與元數據的相關屬性,緊接著會調用getCandidateConfigurations方法:

 

/** * Return the auto-configuration class names that should be considered. By default * this method will load candidates using {@link SpringFactoriesLoader} with * {@link #getSpringFactoriesLoaderFactoryClass()}. * @param metadata the source metadata * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation * attributes} * @return a list of candidate configurations */ 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; } /** * Return the class used by {@link SpringFactoriesLoader} to load configuration * candidates. * @return the factory class */ protected Class<?> getSpringFactoriesLoaderFactoryClass() { return EnableAutoConfiguration.class; }

  在這里又遇到我們的老熟人了--SpringFactoryiesLoader, 它會讀取META-INF/spring.factories下的EnableAutoConfiguration的配置,緊接著在進行排除與過濾,進而得到需要裝配的類。最后讓所有配置在META-INF/spring.factories下的AutoConfigurationImportListener執行AutoConfigurationImportEvent事件,代碼如下:

 

private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) { List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners(); if (!listeners.isEmpty()) { AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this,  configurations, exclusions); for (AutoConfigurationImportListener listener : listeners) { invokeAwareMethods(listener); listener.onAutoConfigurationImportEvent(event); } } } protected List<AutoConfigurationImportListener> getAutoConfigurationImportListeners() { return SpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class, this.beanClassLoader); }

二、何時進行自動裝配

  在前面的環節里只是最終要確定哪些類需要被裝配,在SpringBoot時何時處理這些自動裝配的類呢?下面我們簡要的分析一下:

2.1、AbstractApplicationContext的refresh方法:

  這個方法老生常談了其中請大家關注一下這個方法:

// Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory);

  在這里是處理BeanFactoryPostProcessor的,那么我們在來看一下這個接口BeanDefinitionRegistryPostProcessor:

/* * Copyright 2002-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.springframework.beans.factory.support;import org.springframework.beans.BeansException;import org.springframework.beans.factory.config.BeanFactoryPostProcessor;/** * Extension to the standard {@link BeanFactoryPostProcessor} SPI, allowing for * the registration of further bean definitions <i>before</i> regular * BeanFactoryPostProcessor detection kicks in. In particular, * BeanDefinitionRegistryPostProcessor may register further bean definitions * which in turn define BeanFactoryPostProcessor instances. * * @author Juergen Hoeller * @since 3.0.1 * @see org.springframework.context.annotation.ConfigurationClassPostProcessor */public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor { /** * Modify the application context's internal bean definition registry after its * standard initialization. All regular bean definitions will have been loaded, * but no beans will have been instantiated yet. This allows for adding further * bean definitions before the next post-processing phase kicks in. * @param registry the bean definition registry used by the application context * @throws org.springframework.beans.BeansException in case of errors */ void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;}

  該接口繼承了BeanFactoryPostProcessor。

2.2、ConfigurationClassPostProcessor 類

  該類主要處理@Configuration注解的,它實現了BeanDefinitionRegistryPostProcessor,  那么也間接實現了BeanFactoryPostProcessor,關鍵代碼如下:

 

@Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { int factoryId = System.identityHashCode(beanFactory); if (this.factoriesPostProcessed.contains(factoryId)) {  throw new IllegalStateException(   "postProcessBeanFactory already called on this post-processor against " + beanFactory); } this.factoriesPostProcessed.add(factoryId); if (!this.registriesPostProcessed.contains(factoryId)) {  // BeanDefinitionRegistryPostProcessor hook apparently not supported...  // Simply call processConfigurationClasses lazily at this point then.  processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory); } enhanceConfigurationClasses(beanFactory); beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory)); }/** * Build and validate a configuration model based on the registry of * {@link Configuration} classes. */ public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { //.....省略部分代碼 // Parse each @Configuration class ConfigurationClassParser parser = new ConfigurationClassParser(  this.metadataReaderFactory, this.problemReporter, this.environment,  this.resourceLoader, this.componentScanBeanNameGenerator, registry); Set<BeanDefinitionHolder> candidates = new LinkedHashSet<BeanDefinitionHolder>(configCandidates); Set<ConfigurationClass> alreadyParsed = new HashSet<ConfigurationClass>(configCandidates.size()); do {  parser.parse(candidates);  parser.validate();  Set<ConfigurationClass> configClasses = new LinkedHashSet<ConfigurationClass>(parser.getConfigurationClasses());  configClasses.removeAll(alreadyParsed);  // Read the model and create bean definitions based on its content  if (this.reader == null) {  this.reader = new ConfigurationClassBeanDefinitionReader(   registry, this.sourceExtractor, this.resourceLoader, this.environment,   this.importBeanNameGenerator, parser.getImportRegistry());  }  this.reader.loadBeanDefinitions(configClasses);  alreadyParsed.addAll(configClasses);  candidates.clear();  if (registry.getBeanDefinitionCount() > candidateNames.length) {  String[] newCandidateNames = registry.getBeanDefinitionNames();  Set<String> oldCandidateNames = new HashSet<String>(Arrays.asList(candidateNames));  Set<String> alreadyParsedClasses = new HashSet<String>();  for (ConfigurationClass configurationClass : alreadyParsed) {   alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());  }  for (String candidateName : newCandidateNames) {   if (!oldCandidateNames.contains(candidateName)) {   BeanDefinition bd = registry.getBeanDefinition(candidateName);   if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&    !alreadyParsedClasses.contains(bd.getBeanClassName())) {    candidates.add(new BeanDefinitionHolder(bd, candidateName));   }   }  }  candidateNames = newCandidateNames;  } } while (!candidates.isEmpty());    // ....省略部分代碼 } 

其實這里注釋已經很清楚了,我們可以清楚的看到解析每一個@ConfigurationClass的關鍵類是:ConfigurationClassParser,那么我們繼續看一看這個類的parse方法:

 

public void parse(Set<BeanDefinitionHolder> configCandidates) { this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>(); 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);  } } processDeferredImportSelectors(); }

  在這里大家留意一下最后一句processDeferredImportSelectors方法,在這里將會對DeferredImportSelector進行處理,這樣我們就和AutoConfigurationSelectImporter結合到一起了:

 

private void processDeferredImportSelectors() { List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors; this.deferredImportSelectors = null; Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR); for (DeferredImportSelectorHolder deferredImport : deferredImports) {  ConfigurationClass configClass = deferredImport.getConfigurationClass();  try {  String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());  processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);  }  catch (BeanDefinitionStoreException ex) {  throw ex;  }  catch (Throwable ex) {  throw new BeanDefinitionStoreException(   "Failed to process import candidates for configuration class [" +   configClass.getMetadata().getClassName() + "]", ex);  } } }

請大家關注這句代碼:String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());在這里deferredImport的類型為DeferredImportSelectorHolder:

 

private static class DeferredImportSelectorHolder { private final ConfigurationClass configurationClass; private final DeferredImportSelector importSelector; public DeferredImportSelectorHolder(ConfigurationClass configClass, DeferredImportSelector selector) {  this.configurationClass = configClass;  this.importSelector = selector; } public ConfigurationClass getConfigurationClass() {  return this.configurationClass; } public DeferredImportSelector getImportSelector() {  return this.importSelector; } }

  在這個內部類里持有了一個DeferredImportSelector的引用,至此將會執行自動裝配的所有操作

三、總結

  1)自動裝配還是利用了SpringFactoriesLoader來加載META-INF/spring.factoires文件里所有配置的EnableAutoConfgruation,它會經過exclude和filter等操作,最終確定要裝配的類

  2)  處理@Configuration的核心還是ConfigurationClassPostProcessor,這個類實現了BeanFactoryPostProcessor, 因此當AbstractApplicationContext執行refresh方法里的invokeBeanFactoryPostProcessors(beanFactory)方法時會執行自動裝配

以上所述是小編給大家介紹的SpringBoot中的自動裝配,希望對大家有所幫助,如果大家有任何疑問歡迎給我留言,小編會及時回復大家的!


注:相關教程知識閱讀請移步到JAVA教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产美女久久久| 日韩精品中文字幕久久臀| 亚洲国产日韩精品在线| 亚洲福利视频二区| 国产精品爱啪在线线免费观看| 国产精品综合网站| 欧美夫妻性生活视频| 国模gogo一区二区大胆私拍| 韩国日本不卡在线| 日韩av在线看| 欧美激情在线观看| 欧美午夜片欧美片在线观看| 日韩精品中文字幕久久臀| 国产精品白嫩美女在线观看| 一本一本久久a久久精品综合小说| 国产极品精品在线观看| 国产精品视频网站| 国产视频丨精品|在线观看| 国产精品视频免费在线观看| 国产成+人+综合+亚洲欧洲| 亚洲新中文字幕| 欧日韩在线观看| 亚洲午夜性刺激影院| 久久久影视精品| 亚洲www视频| 国产精品欧美日韩一区二区| 国产精品久久久久久久久久尿| 日本91av在线播放| 亚洲乱亚洲乱妇无码| 日韩视频欧美视频| 日韩av免费在线看| 久久99久久99精品中文字幕| 日产日韩在线亚洲欧美| 国产午夜精品理论片a级探花| 久久夜色精品国产| 欧美在线免费观看| 国产精品羞羞答答| 中文字幕自拍vr一区二区三区| 国产成人精品在线视频| 视频一区视频二区国产精品| 国产剧情久久久久久| 成人午夜小视频| 久久久久久噜噜噜久久久精品| 伊人久久久久久久久久久| 91大神在线播放精品| 日韩精品在线私人| 欧美性猛交xxxx乱大交| 亚洲偷欧美偷国内偷| 日韩av在线影视| 深夜精品寂寞黄网站在线观看| 日韩精品中文字幕在线| 97国产精品久久| 不卡中文字幕av| 亚洲精品福利在线| 8x海外华人永久免费日韩内陆视频| 国产精品第10页| 久99九色视频在线观看| 亚洲色图第三页| 国产精品99久久久久久久久久久久| 日韩在线免费视频| 孩xxxx性bbbb欧美| 成人精品久久一区二区三区| 国产视频欧美视频| 欧美精品在线网站| 亚洲视频电影图片偷拍一区| 在线免费观看羞羞视频一区二区| 亚洲国产精品久久久| 性色av香蕉一区二区| 97精品国产aⅴ7777| 青青a在线精品免费观看| 69av视频在线播放| 亚洲第一级黄色片| 久久伊人91精品综合网站| 日韩精品免费视频| 亚洲激情久久久| 日韩中文字幕在线精品| 国产精品色视频| 国产亚洲欧美另类中文| 国产亚洲视频中文字幕视频| 精品二区三区线观看| 91久久国产婷婷一区二区| 亚洲网站视频福利| 国产美女精彩久久| 日韩av网址在线| 久久精品视频播放| 国产综合香蕉五月婷在线| 伊人亚洲福利一区二区三区| 日韩av网站在线| 欧美黑人视频一区| 国产一区二区三区在线| 欧美视频中文字幕在线| 国产日韩欧美在线观看| 91精品国产91久久久久久最新| 国产精品女人网站| 亚洲色图17p| 亚洲成人av在线播放| 国产成人精品久久二区二区| 久久好看免费视频| 亚洲男人的天堂网站| 丝袜情趣国产精品| 日韩va亚洲va欧洲va国产| 国产欧美一区二区三区视频| 日韩av在线精品| 中文字幕亚洲综合久久筱田步美| 亚洲精品资源在线| 九九热这里只有在线精品视| 尤物yw午夜国产精品视频| 久久青草福利网站| 日本道色综合久久影院| 欧美激情欧美激情在线五月| 国产91在线播放精品91| 欧美午夜宅男影院在线观看| 日韩av电影手机在线| 7777精品久久久久久| 浅井舞香一区二区| 日韩在线欧美在线| 亚洲美女在线看| 久久久久国产精品一区| 精品久久久久国产| 在线精品91av| 亚洲电影在线观看| 欧美成人中文字幕| 日韩视频第一页| 91在线视频导航| 一本一本久久a久久精品牛牛影视| 日韩一区二区欧美| 久久久久久国产精品三级玉女聊斋| 欧美高跟鞋交xxxxhd| 亚洲国产另类 国产精品国产免费| 色99之美女主播在线视频| 久久精品国产2020观看福利| 日本成人在线视频网址| 欧美自拍大量在线观看| 久久影视电视剧免费网站| 久久91超碰青草是什么| 国产精品扒开腿做爽爽爽视频| 日韩高清电影好看的电视剧电影| 美女黄色丝袜一区| 欧美另类极品videosbest最新版本| 日韩欧美亚洲成人| 91av在线播放| 亚洲视频在线观看免费| 欧美午夜视频一区二区| 久久精品99久久久久久久久| 欧美日韩中文在线观看| 国产一区二区视频在线观看| 一区二区三区四区在线观看视频| 国产一区香蕉久久| 亚洲人成网站999久久久综合| 中文字幕亚洲综合久久筱田步美| 久热99视频在线观看| 亚洲www在线观看| 日韩欧美亚洲范冰冰与中字| 国产v综合ⅴ日韩v欧美大片| 日韩av在线免播放器| 97色伦亚洲国产| 色噜噜狠狠狠综合曰曰曰| 色综合视频网站| 国产在线观看91精品一区| 精品美女永久免费视频| 亚洲女人被黑人巨大进入al| 精品久久久999| 国产精品入口福利| 亚洲日韩中文字幕在线播放|