1. 程式人生 > >SpringBoot啟動的主入口註解SpringBootApplication分析

SpringBoot啟動的主入口註解SpringBootApplication分析

主入口程式碼

@SpringBootApplication
public class HelloWorldMainApplication {

    public static void main(String[] args) {

        // 讓Spring應用啟動起來,這個原理就是啟動spring的主入口
        SpringApplication.run(HelloWorldMainApplication.class,args);
    }
}

[email protected]:

設定:這個類是SpringBoot的主配置類(HelloWorldMainApplication ),SpringBoot就應該執行這個類的main方法來啟動SpringBoot應用;

SpringApplication.run(主配置類的類物件,main方法的引數);這個功能就像很久以前Java的啟動類,args就是啟動類引數。

@SpringBootApplication類

[email protected]

容器初始化的時候會讀取配置類資訊到容器中,相當於配置web.xml讀取配置檔案

@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 {

Spring Boot的配置類,標註在某個類上,表示這是一個Spring Boot的配置類;

  • @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Configuration//配置類上來標註這個註解,初始化配置類的資訊到容器中
    public @interface SpringBootConfiguration {
    }

1.11@Configuration

用於定義配置類,可替換xml配置檔案,被註解的類內部包含有一個或多個被@Bean註解的方法,這些方法將會被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext類進行掃描,並用於構建bean定義,初始化Spring容器。

換句話說:使用這個註解將將某個包下的配置類初始化到容器中。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
    String value() default "";
}

1.12@EnableAutoConfiguration:

開啟自動配置功能,打個比方說,專案中整合redis,那麼一定要有redis.xml的配置。當我們開啟這個註解後,它會去自動配置redis的配置資訊。

@SuppressWarnings("deprecation")
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

1.121@AutoConfigurationPackage

自動配置包,相當於spring掃描包的功能(

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)//將主配置類(@SpringBootApplication標註的類)的所在包及下面所有子包裡面的所有元件掃描到Spring容器;
public @interface AutoConfigurationPackage {

}

@Import(AutoConfigurationPackages.Registrar.class)//將主配置類(@SpringBootApplication標註的類)的所在包及下面所有子包裡面的所有元件掃描到Spring容器;

@Order(Ordered.HIGHEST_PRECEDENCE)
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

   @Override
   public void registerBeanDefinitions(AnnotationMetadata metadata,
         BeanDefinitionRegistry registry) {
//註冊主入口類的包名
      register(registry, new PackageImport(metadata).getPackageName());
   }

1.122@Import(EnableAutoConfigurationImportSelector.class)

給容器中匯入選擇器中的元件。
EnableAutoConfigurationImportSelector:匯入的元件選擇器;
將所有需要匯入的元件以全類名的方式返回;這些元件就會被新增到容器中;
會給容器中匯入非常多的自動配置類(xxxAutoConfiguration);就是給容器中匯入這個場景需要的所有元件,並配置好這些元件。

換句話說:當我們需要redis元件的時候,使用這個註解,redis的所有配置就會匯入進來。

@Deprecated
public class EnableAutoConfigurationImportSelector
      extends AutoConfigurationImportSelector {

   @Override
   protected boolean isEnabled(AnnotationMetadata metadata) {
      if (getClass().equals(EnableAutoConfigurationImportSelector.class)) {
         return getEnvironment().getProperty(
               EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class,
               true);
      }
      return true;
   }
}

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;
}
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
    String factoryClassName = factoryClass.getName();

    try {
        Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
        ArrayList result = new ArrayList();

        while(urls.hasMoreElements()) {
            URL url = (URL)urls.nextElement();
            Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
            String factoryClassNames = properties.getProperty(factoryClassName);
            result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
        }

        retur

META-INF/spring.factories

這些值作為自動配置類匯入到容器中,自動配置類就生效,幫我們進行自動配置工作;

比如說:這裡面有redis配置。

@Configuration
@ConditionalOnClass({ JedisConnection.class, RedisOperations.class, Jedis.class })
@EnableConfigurationProperties(RedisProperties.class)
public class RedisAutoConfiguration {

   /**
    * Redis connection configuration.
    */
   @Configuration
   @ConditionalOnClass(GenericObjectPool.class)
   protected static class RedisConnectionConfiguration {

      private final RedisProperties properties;

      private final RedisSentinelConfiguration sentinelConfiguration;

      private final RedisClusterConfiguration clusterConfiguration;

      public RedisConnectionConfiguration(RedisProperties properties,
            ObjectProvider<RedisSentinelConfiguration> sentinelConfiguration,
            ObjectProvider<RedisClusterConfiguration> clusterConfiguration) {
         this.properties = properties;
         this.sentinelConfiguration = sentinelConfiguration.getIfAvailable();
         this.clusterConfiguration = clusterConfiguration.getIfAvailable();
      }

      @Bean
      @ConditionalOnMissingBean(RedisConnectionFactory.class)
      public JedisConnectionFactory redisConnectionFactory()
            throws UnknownHostException {
         return applyProperties(createJedisConnectionFactory());
      }

RedisProperties.class

@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {

   /**
    * Database index used by the connection factory.
    */
   private int database = 0;

   /**
    * Redis url, which will overrule host, port and password if set.
    */
   private String url;

   /**
    * Redis server host.
    */
   private String host = "localhost";

   /**
    * Login password of the redis server.
    */
   private String password;