SpringBoot_入门-HelloWorld细节-自动配置

前面分析了pom文件的父依赖,以及starter场景启动器,下面说一下helloworld主程序,这个主程序我们只要运行main方法就行了,但是运行main方法要注意,我们spring应用run的时候,要传入一个类,一定是SpringBootApplication来标注的类,如果我把这个注解注掉,然后我来运行一下,这个就报错了,这个注解是非常重要的,SpringBootApplication,我们来说一下这个主程序类,主程序类,也是我们的主入口类,他的这段代码呢,里面有一个核心注解,叫SpringBootApplication,我们翻译过来就是SpringBoot应用,那么这个类我们标注在哪一个类上,这个注解我们标注在哪个类上,说明这个类,是SpringBoot的主配置类,Springboot就应该运行,这个类的main方法,来启动Springboot应用,我们有一个非常重要的注解,SpringBootApplication,这个SpringBootApplication,到底是什么呢,打开可以看一下,其实它是一个组合注解/*** 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 {他有这么多的注解来组成的,我们来看一下,复合注解里面呢,第一个注解叫做SpringBootConfiguration,按照我们注解的名字,翻译过来,就叫SpringBoot配置,我们也叫配置类,那么这个注解,他标注在某个类上,表示这是Springboot的一个配置类,这个注解点进来看一下,我们会非常熟悉/*** 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).* 

* Application should only ever include one {@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 @Configuration public @interface SpringBootConfiguration {}它上面有一个注解叫Configuration,Spring里面定义的一个注解,他标在某一个类上,配置类上来标注这个注解,我们一直在说这个配置类,所谓的配置类呢,就是和我们的配置文件是一样的,我们以前开发Spring应用,需要编写非常多的配置文件,这文件一多太麻烦了,那接下来怎么办呢,把一个个配置文件替换成一个个的配置类,当然Springboot怎么知道这个类是做配置的,比如可以给容器中,注入组件等等,以前配置文件的功能她都能够做,那么我们要让Springboot知道,这是一个配置类,标注@Configuration注解,Spring就知道了,包括你标注@SpringBootConfiguration,效果都是一样的,只不过这个注解是Spring定义的注解,这个是Springboot定义的注解,而我们这个配置类呢,其实他就是一个组件@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Configuration {/*** Explicitly specify the name of the Spring bean definition associated* with this Configuration class. If left unspecified (the common case),* a bean name will be automatically generated.*

The custom name applies only if the Configuration class is picked up via* component scanning or supplied directly to a {@link AnnotationConfigApplicationContext}.* If the Configuration class is registered as a traditional XML bean definition,* the name/id of the bean element will take precedence.* @return the suggested component name, if any (or empty String otherwise)* @see org.springframework.beans.factory.support.DefaultBeanNameGenerator*/String value() default "";}我们记住配置类也是容器中的一个组件,这是我们说的第一个注解,叫做SpringBootApplication

然后他的第二个注解,叫做@EnableAutoConfiguration,开启启用的意思,开启自动配置功能,我们整个SpringBoot里面没有做任何配置,我们SpringMVC也启动起来了,我们整个应用也能用了,包扫描也扫进去了,这些功能都是怎么做的呢,就是我们这个注解,叫做@EnableAutoConfiguration,开启自动配置,以前我们需要配置的东西,我们现在都不需要配置了,然后是SpringBoot帮我们配置,要帮我们自动配置,就得需要加上这个注解,这个注解告诉SpringBoot,开启自动配置功能,这样我们整个自动配置,这样自动配置功能才能够生效,而自动配置是一个什么样的原理,我们还是打开来看一下,EnableAutoConfiguration点进来@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 {};}它里面首先有一个@AutoConfigurationPackage,他也是一个组合注解,EnableAutoConfiguration它里面首先有一个注解,叫AutoConfigurationPackage,那么按照这个注解呢,翻译过来叫做自动配置包,自动配置包是什么意思呢,我们点击这个注解,/*** Indicates that the package containing the annotated class should be registered with* {@link AutoConfigurationPackages}.** @author Phillip Webb* @since 1.3.0* @see AutoConfigurationPackages*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {}它是用@Import(AutoConfigurationPackages.Registrar.class)注解完成的功能,而Import就是Spring的底层注解,他的作用就是给容器中,导入一个组件,导入那个组件呢,后面的这个类,在后面写一些逻辑判断,然后给他返回,由导入的组件这个类来指定,导入哪些组件,由import里面的class类,或者Spring注解的底层原理,我们就说一下AutoConfigurationPackages,他利用import,指定这个类给容器中导入组件,导入了什么组件呢,他这里有一个方法/*** {@link ImportBeanDefinitionRegistrar} to store the base package from the importing* configuration.*/
@Order(Ordered.HIGHEST_PRECEDENCE)
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {@Overridepublic void registerBeanDefinitions(AnnotationMetadata metadata,BeanDefinitionRegistry registry) {register(registry, new PackageImport(metadata).getPackageName());}@Overridepublic Set determineImports(AnnotationMetadata metadata) {return Collections.singleton(new PackageImport(metadata));}}叫做registerBeanDefinitions,注册一些bean定义信息,怎么导呢,new PackageImport(metadata).getPackageName(),metadata就是我们注解的原信息,所有的源数据,getPackageName拿到一个包名,首先metadata是注解的元信息,是Springboot注解,这是Springboot注解里面的东西,然后它是标注在HelloWorldMainApplication上的,元信息都能够拿得到,主要有一个new PackageImport(metadata).getPackageName(),可以来看一下包名,来计算一下,这个包名就叫做com.learn所以这个注解,AutoConfigurationPackages它本身的含义,将我们主配置类,主配置类就在这,所在的包下边,所有的组件,都扫描进去,这包名是主配置类的,将主配置类,也就是,就是我们SpringBootApplication注解,标注的这个类,所在包及下边所有子包,里面的所有组件,扫描到Spring容器中,这是非常重要的一句话,所以我们能够扫描我们的Controller,因为它是在我们住配置类的子包下,那么按照这种想法,我一旦说换包了,放到com下的一个HelloController,这里面才是我们的主类,看能不能扫描进来 
我再来启动看行不行,我们看能不能把外面的Controller扫进来呢,这个应用启动起来了,它是把error路径映射到了,但是hello没有,如果我们访问hello请求那肯定就是404了localhost:8080/hello报的是404的错误,就是扫不进来,它是将主配置类下面的,所有配置扫进来,这个就是@AutoConfigurationPackage这个注解的作用,@EnableAutoConfiguration注解里面还有一个注解,还标了一个注解是@Import(EnableAutoConfigurationImportSelector.class),我们说了import的左右就是,给容器中导入一些组件,导入什么组件呢,就是后面这个类告诉你,后面这个类翻译过来,开启自动配置导包的选择器,导入哪些组件的选择器,点进来看要导入哪些组件,@Deprecated
public class EnableAutoConfigurationImportSelectorextends AutoConfigurationImportSelector {@Overrideprotected boolean isEnabled(AnnotationMetadata metadata) {if (getClass().equals(EnableAutoConfigurationImportSelector.class)) {return getEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class,true);}return true;}}这里面只有一个方法叫做isEnabled,我们看到他的父类点进来AutoConfigurationImportSelector@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return NO_IMPORTS;}try {AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);AnnotationAttributes attributes = getAttributes(annotationMetadata);List configurations = getCandidateConfigurations(annotationMetadata,attributes);configurations = removeDuplicates(configurations);configurations = sort(configurations, autoConfigurationMetadata);Set 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);}
}里面有一个方法叫做selectImports,这个方法就是用来告诉Spring容器,到底要导哪些组件,将所有需要导入的组件,以全类名的方式返回,这些组件就会被添加到容器中,我们到底Selector给容器添加了哪些组件呢,我们分析一下刚才的代码,我以debug的方式来进行运行,运行来到这一步,这是我们获取注解的原信息,注解是SprintBootApplication,标在哪个类上都有,接下来放行,这一步返回了listConfigurations,下面都在用,最后还把configurations返回了,这个configurations数组,就是我们容器中需要导入的组件,有96个,AutoConfiguration,听名字呢,什么的自动配置,所以说他的作用,最终会给容器中,会导入非常多的自动配置类,我们叫做AutoConfiguration,这些自动配置类的作用,就是给容器中导入这些场景,需要的所有组件,并配置好这些组件,这就是这些配置类,如果我们要做AOP的功能,那AOP的自动配置类就配置好,我们要做批处理功能,就有批处理的自动配置类,比如我们要做mongodb的功能,那么mongodb的配置就要配置好,这些自动配置呢,都是通过这些自动配置类完成的,我们给容器中导入了大量的自动配置类,自动配置类的细节,我们后来在讲自动配置类的时候再说,有了这些自动配置类,免去了我们手动编写配置,和注入功能组件等工作,这些工作都不用我们做了,由配置类帮我们做好,那自动配置类他怎么就找到的呢,其实我们有据可查,他在调用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 getCandidateConfigurations(AnnotationMetadata metadata,AnnotationAttributes attributes) {List 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;
}调了这么一个方法,SpringFactoriesLoader.loadFactoryNames,这个方法里面传两个参数,第一个参数的值点进来/*** Return the class used by {@link SpringFactoriesLoader} to load configuration* candidates.* @return the factory class*/
protected Class getSpringFactoriesLoaderFactoryClass() {return EnableAutoConfiguration.class;
}叫EnableAutoConfiguration.class,第二个参数就是getBeanClassLoader类加载器机制了,然后他的作用是什么,他用classLoader类加载器,获取这个资源,获取完这个资源以后呢,它会把这个资源当做property配置文件,从Properties中拿出factoryPropertyName,我们工厂的名字,从哪里得呢,叫做"META-INF/spring.factories",他的作用就是从类路径下,META-INF/spring.factories中,获取EnableAutoConfiguration指定的值,那么我们可以来看一下,我们导入的jar包类路径里边

就是我们导入的自动配置类,所以我们一句话总结,Spring在启动的时候,从类路径下,这个文件夹中获取值,将这些值作为自动配置类,导入到容器中,然后我们这个自动配置类就生效了,他一生效以后呢,就能帮我们进行自动配置工作了,他只要一进行自动配置工作,我们就不用写那么多的代码了,其实为什么会有这么多神奇的效果,就是这个自动配置类,我们没写的配置,其实人家都帮我们来写了,比如我们来看一个自动配置类,我们现在是WEB应用,跟WEB有关的看一下org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\这里有WEB MVC,@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class,WebMvcConfigurerAdapter.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {这个注解以后我们详细再说,我们先来说一个@Bean@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {return new OrderedHiddenHttpMethodFilter();
}给容器中添加一个组件,这个后来也会说的,比如给容器中添加filter组件,包括给容器中做一些配置,给容器中添加视图解析器@Bean
@ConditionalOnBean(View.class)
@ConditionalOnMissingBean
public BeanNameViewResolver beanNameViewResolver() {BeanNameViewResolver resolver = new BeanNameViewResolver();resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10);return resolver;
}@Bean
@ConditionalOnMissingBean
public InternalResourceViewResolver defaultViewResolver() {InternalResourceViewResolver resolver = new InternalResourceViewResolver();resolver.setPrefix(this.mvcProperties.getView().getPrefix());resolver.setSuffix(this.mvcProperties.getView().getSuffix());return resolver;
}我们以前的配置都给配置类给替换了,我们需要自己指定的配置,自动配置类都帮我们做了,其实在底层用Spring的时候,一个都不能少,这个被Spring官方替我们做了,那么我们主要来看,这些自动配置类,其实都是在springboot.autoconfigure包下,这个就是对整个J2EE的大整合,比如有跟高级消息队列的,aop的,有做缓存的,有左DAO的整合,一篮子解决方案全都在这,自动配置,所以我们这个SpringBoot就会这么强大,J2EE整体的解决方案,和自动配置,都在我们这个包里边,spring-boot-autoconfigure-1.5.12.RELEASE-sources.jar他里面来帮我们做了这个事,所以我们用了SpringBoot就不用这个东西了,一切都有人来帮我们配,在自动配置包里边,看每一种功能,都是怎么配的,如果不满意,我们通过不断地学习,也可以自己来改善一些配置

 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章