springboot自動配置原理

1.java configuration及WebApplicationInitializer

The following example of the Java configuration registers and initializes the DispatcherServlet, which is auto-detected by the Servlet container (see Servlet Config)--來自spring官網html

//首先實現WebApplicationInitializer接口中onStartUp()方法,容器啓動時候會調用該方法
public class MyWebApplicationInitializer implements WebApplicationInitializer {

    //容器爲何會調用onStartup()方法
    //servlet 3.0 提出了spi規範,一個項目自定義的WebApplicationInitializer若是想被容器調用(tomcat),
    //只須要在項目中meta-inf/service目錄下定義一個文件,
    //文件名必須爲javax.servlet.ServletContainerInitializer,
    //該名字爲一個接口,文件內容爲實現該接口的類,
    //Spring實現該接口的類的名稱爲org.springframework.web.SpringServletContainerInitializer,spring項目中該文件內容也爲該實現類的全路徑。
    //該接口爲servlet中定義的,容器實現該接口,Spring也實現該接口,以此達到容器(tomcat)啓動,
    //可以調用到自定義的WebApplicationInitializer
    

    @Override
    public void onStartup(ServletContext servletCxt) {
        
        // Load Spring web application configuration
        //spring 容器對象
        AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
        //AppConfig類爲配置
        ac.register(AppConfig.class);
        ac.refresh();
        //spring容器配置完成
        

        // Create and register the DispatcherServlet
        //設置spring mvc
        DispatcherServlet servlet = new DispatcherServlet(ac);
        ServletRegistration.Dynamic registration = servletCxt.addServlet("app", servlet);
        //設置爲優先啓動
        registration.setLoadOnStartup(1);
        registration.addMapping("/app/*");
    }
}

spring實現servlet3.0規範中,meta-inf/services目錄下的文件java

image.png

實現的接口web

image.png

spring 對servlet3.0規範中onStartup()方法的實現spring

@HandlesTypes(WebApplicationInitializer.class)
//該註解將保證容器(tomcat)首先掃描WebApplicationInitializer接口(該接口能夠自定義,spring使用的是WebApplicationInitializer接口)的全部實現類,而後賦值到onStartup()方法參數的webAppInitializerClasses set集合中。
public class SpringServletContainerInitializer implements ServletContainerInitializer {
    @Override
    public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
            throws ServletException {

        List<WebApplicationInitializer> initializers = new LinkedList<>();
        //存放new 出來的對象

        if (webAppInitializerClasses != null) {
            for (Class<?> waiClass : webAppInitializerClasses) {
                // Be defensive: Some servlet containers provide us with invalid classes,
                // no matter what @HandlesTypes says...
                if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
                        WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
                    try {
                        initializers.add((WebApplicationInitializer)
                                ReflectionUtils.accessibleConstructor(waiClass).newInstance());
                    }
                    catch (Throwable ex) {
                        throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
                    }
                }
            }
        }

        if (initializers.isEmpty()) {
            servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
            return;
        }

        servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
        AnnotationAwareOrderComparator.sort(initializers);
        
        //for循環,依次調用new 出來的對象,調用其onStartup()方法
        for (WebApplicationInitializer initializer : initializers) {
            initializer.onStartup(servletContext);
        }
    }

}

2.Springboot自動配置原理

Springboot項目啓動applicationtomcat

package com.xiayu;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

@SpringBootApplication//Springboot項目啓動註解
@EnableConfigurationProperties
public class XiayuRoutingDatasourceApplication {
    public static void main(String[] args) {
        SpringApplication.run(XiayuRoutingDatasourceApplication.class);
    }
}

@SpringbootApplication註解springboot

@Target(ElementType.TYPE)//定義該註解做用於什麼上面,是類,接口,方法,方法參數等等上面,ElementType.TYPE定義在類和接口上面
@Retention(RetentionPolicy.RUNTIME)//註解在運行時生效
@Documented 聲明該註解會被在javadoc文檔信息中展現
@Inherited 該註解保證註解聲明在一個父類上後,子類也會有相同的屬性
//上述都是java自帶的註解
@SpringBootConfiguration//該註解僅僅聲明配置類
@EnableAutoConfiguration//Springboot的核心配置註解
@ComponentScan(excludeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

@EnableAutoConfiguration註解mvc

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
//配置自動掃描包,掃描當前註解所在的目錄,若是當前配置在com.xiayu包下,就至關於
//配置了@ComponentScan("com.xiayu")
//這也是爲何Springboot項目啓動類與各個模塊同級
@Import(AutoConfigurationImportSelector.class)
//真正的核心自動配置類,加載AutoConfigurationImportSelector類到spring容器中,並做爲bean管理
public @interface EnableAutoConfiguration {

 
    典型的Springboot項目目錄結構
 
image.pngapp

@Import加載的類:AutoConfigurationImportSelector,其實現了DeferredImportSelector接口ide

public class AutoConfigurationImportSelector
        implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
        BeanFactoryAware, EnvironmentAware, Ordered {

DeferredImportSelector接口this

package org.springframework.context.annotation;

public interface DeferredImportSelector extends ImportSelector {
}

package org.springframework.context.annotation;
-------------------------------------------------------
import org.springframework.core.type.AnnotationMetadata;

public interface ImportSelector {
    String[] selectImports(AnnotationMetadata var1);
    //該接口在AutoConfigurationImportSelector類中有具體的實現
}

AutoConfigurationImportSelector類中 selectImports方法的具體實現

//返回自動配置類的路徑,交由spring管理,完成整個bean生命週期
@Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        }
        try {
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
            AnnotationAttributes attributes = getAttributes(annotationMetadata);
            //從meta-inf/spring.factories文件中加載已經定義的配置類的全路徑
            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 StringUtils.toStringArray(configurations);
        }
        catch (IOException ex) {
            throw new IllegalStateException(ex);
        }
    }

getCandidateConfigurations方法

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
            AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
                getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
                //返回List<String>,list中包含自動配置類的全路徑
        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;
    }

在SpringFactoriesLoader類中定義了自動配置類全路徑保存的文件

public abstract class SpringFactoriesLoader {
    public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
    private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);
    private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap();

meta-inf/spring.factories文件,若是存在多個該文件,也會被掃描到,掃描到後就會將這些類經過@Import註解加載到spring容器中,被Spring進行管理。

image.png

3.以rabbitmq舉例

springboot中Rabbitmq的配置文件路徑爲:org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration

image.png

RabbitAutoConfiguration類

image.png

RabbitProperties類

@ConfigurationProperties(prefix = "spring.rabbitmq")
//獲取配置文件中spring.rabbitmq開頭的全部配置,
//映射到RabbitProperties類中的屬性中
public class RabbitProperties {

    /**
     * RabbitMQ host.
     */
    private String host = "localhost"; //默認的host

    /**
     * RabbitMQ port.
     */
    private int port = 5672; //默認的port

    /**
     * Login user to authenticate to the broker.
     */
    private String username = "guest"; //默認的用戶名

    /**
     * Login to authenticate against the broker.
     */
    private String password = "guest";//默認的密碼

    /**
     * SSL configuration.
     */
    private final Ssl ssl = new Ssl();

    /**
     * Virtual host to use when connecting to the broker.
     */
    private String virtualHost;

    /**
     * Comma-separated list of addresses to which the client should connect.
     */
    private String addresses;

    /**
     * Requested heartbeat timeout; zero for none. If a duration suffix is not specified,
     * seconds will be used.
     */
    @DurationUnit(ChronoUnit.SECONDS)
    private Duration requestedHeartbeat;

    /**
     * Whether to enable publisher confirms.
     */
    private boolean publisherConfirms;

    /**
     * Whether to enable publisher returns.
     */
    private boolean publisherReturns;

    /**
     * Connection timeout. Set it to zero to wait forever.
     */
    private Duration connectionTimeout;

    /**
     * Cache configuration.
     */
    private final Cache cache = new Cache();

    /**
     * Listener container configuration.
     */
    private final Listener listener = new Listener();

    private final Template template = new Template();

    private List<Address> parsedAddresses;

    public String getHost() {
        return this.host;
    }
}
相關文章
相關標籤/搜索