SpingBoot(三)——自动配置

SpringBoot与SSM搭建步骤相比更加简洁高效,其得益于Springboot强大的自动配置功能。两者底层是一样的SpringBoot更像是Spring的注解版。

如图是springboot的一个标注启动类(程序入口)由@SpringBootApplication修饰

@SpringBootApplication


该注解有两大部分组成分

元注解

JAVA中有4个元注解专职负责注解其他注解。用来标示其他注解的使用范围和作用域

元注解 描述
@Target 表示该注解可以用于什么地方。ElementType参数包括:1)CONSTRUCTOR:构造器的生命; 2)FIELD:域声明(包括enum实例); 3)LOCAL_VARIABLE:局部变量声明 4)METHOD:方法声明; 5)PACKAGE:包声明; 6)PARAMETER:参数声明 ; 7)TYPE:类、接口(包括注解类型)或enum声明;
@Retention 表示需要在什么级别保存该注解信息。可选的RetentionPolicy参数包括: 1)SOURCE:注解将在编译器丢弃,在源文件有效 2)CLASS:注解在class文件中可用,但会被VM丢弃; 3)RUNTIME:VM将在运行期也保留注解,因此可以通过反射机制读取注解的信息
@Documented 将此注解包含在Javadoc中
@Inherited 允许子类继承父类中的注解
功能注解
  • @SpringBootConfiguration

    是SpringBoot项目的配置注解(在springboot中替代Spring@Configuration)。表示这是一个配置类,即SSM中的XML配置文件,而现在用java配置。并将当前类内生命的一个或多个以@Bean注解标注的方法实例放入IOC容器中管理。它同样是个组合注解;用法与@Configuration一样在;在SpringBoot中支持用@SpringBootConfiguration来代替

  • @EnableAutoConfiguration

    开启自动配置功能,自动导入程序所需要的默认配置使其生效

    ​ @AutoConfigurationPackge:自动配置包组合注解

    ​ @Import({Registrar.class})

    ​ 给容器导入组件导入的组件由Registrar.class决定

    ​ 将启动类所在的包及其子包下的所有组件扫描加入到Spring容器中启动类所在的位置是不能随便移动的

    ​ @Import(AutoConfigurationPackages.Registrar.class) 将各个场景所有要的组件导入

    默认加载场景配置118个

    扫描地址

         /**
          *进入getCandidateConfigurations看到
          *是通过SpringFactoriesLoader来实现查询的
          **/
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
            List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
        }
    
    

    继续进入loadFactoryNames方法

      /**可以看到加载位置
       *classLoader.getResources("META-INF/spring.factories") :           
       * ClassLoader.getSystemResources("META-INF/spring.factories");
       */
    public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
            String factoryClassName = factoryClass.getName();
            return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
        }
    
        private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
            MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
            if (result != null) {
                return result;
            } else {
                try {
                    Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                   
                    LinkedMultiValueMap result = new LinkedMultiValueMap();
    
                    while(urls.hasMoreElements()) {
                        URL url = (URL)urls.nextElement();
                        UrlResource resource = new UrlResource(url);
                        Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                        Iterator var6 = properties.entrySet().iterator();
    
                        while(var6.hasNext()) {
                            Entry<?, ?> entry = (Entry)var6.next();
                            String factoryClassName = ((String)entry.getKey()).trim();
                            String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                            int var10 = var9.length;
    
                            for(int var11 = 0; var11 < var10; ++var11) {
                                String factoryName = var9[var11];
                                result.add(factoryClassName, factoryName.trim());
                            }
                        }
                    }
    
                    cache.put(classLoader, result);
                    return result;
                } catch (IOException var13) {
                    throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
                }
            }
        }
    
    

    从而实现自动配置。自己写场景启动器也需要在META-INF/spring.factories配置默认的配置类

  • @ConponentScan指定需要扫描的类所在的包 配置扫描范围

  • SpringMVC的自动配置

/**
 *表示此类是个配置类;可以在容器中添加组件
 **/
@Configuration  

/**
 *判断当前应用是否web应用  是且是服务器时此配置生效
 **/
@ConditionalOnWebApplication(
    type = Type.SERVLET
)  
/**
 *判断当前项目有没有这些类
 **/
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
/**
*判断当前项目中没有WebMvcConfigurationSupport.class这个类 返回true
*/
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
/**
 *控制加载顺序
 */
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {
    ....
@Conditional派生注解

作用:必须是@Conditional指定的条件成立,才给容器中添加组件,配置配里面的所有内容才生效;

@Conditional扩展注解 作用(判断是否满足当前指定条件)
@ConditionalOnJava 系统的java版本是否符合要求
@ConditionalOnBean 容器中存在指定Bean;
@ConditionalOnMissingBean 容器中不存在指定Bean;
@ConditionalOnExpression 满足SpEL表达式指定
@ConditionalOnClass 系统中有指定的类
@ConditionalOnMissingClass 系统中没有指定的类
@ConditionalOnSingleCandidate 容器中只有一个指定的Bean,或者这个Bean是首选Bean
@ConditionalOnProperty 系统中指定的属性是否有指定的值
@ConditionalOnResource 类路径下是否存在指定资源文件
@ConditionalOnWebApplication 当前是web环境
@ConditionalOnNotWebApplication 当前不是web环境
@ConditionalOnJndi JNDI存在指定项
SpringMVC自动配置官方文档

Spring Boot provides auto-configuration for Spring MVC that works well with most applications.

The auto-configuration adds the following features on top of Spring’s defaults:

  • Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.

    ​ 自动配置视图解析器

  • Support for serving static resources, including support for WebJars (covered later in this document)).

    自动配置静态资源,支持webJar

  • Automatic registration of Converter, GenericConverter, and Formatter beans.

    类转换器 Converter() ;时间格式化

  • Support for HttpMessageConverters (covered later in this document).

    与SSM比自动配置了http请求和相应中 对象与JSON的自动转换

  • Automatic registration of MessageCodesResolver (covered later in this document).

    错误码规则

  • Static index.html support.

    首页

  • Custom Favicon support (covered later in this document).

    favicon图标

  • Automatic use of a ConfigurableWebBindingInitializer bean (covered later in this document).

    自动使用ConfigurableWebBindingInitializer 将请求的参数转化为对应的JavaBean,并且会结合上面的类型、格式转换一起使用。

If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc. If you wish to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, you can declare a WebMvcRegistrationsAdapter instance to provide such components.

If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc
#####扩展配置

  1. SpringBoot自动配置MVC时会先扫描用户自己的配置(@Bean @Component)优先使用

  2. 扩展SpringMVC 使用@Configuration描述类 继承WebMvcConfigurerAdapter即可

  3. 不可用@EnableWebMvc(全面接管自动配置,自动配置失效)

    /**
      *增加本地资源文件夹作为应用中的资源
      */
    @Configuration
    public class FileWebMvcConfigurerAdapter implements WebMvcConfigurer {
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            /**
             * 如果我们将/xxxx/** 修改为 /** 与默认的相同时,则会覆盖系统的配置,可以多次使用 addResourceLocations 添加目录,
             * 优先级先添加的高于后添加的。
             *
             * 如果是/xxxx/** 引用静态资源 加不加/xxxx/ 均可,因为系统默认配置(/**)也会作用
             * 如果是/** 会覆盖默认配置,应用addResourceLocations添加所有会用到的静态资源地址,系统默认不会再起作用
             */
            registry.addResourceHandler("/**")
                    .addResourceLocations("classpath:/META-INF/resources/")
                    .addResourceLocations("classpath:/resources/")
                    .addResourceLocations("classpath:/static/")
                    .addResourceLocations("classpath:/public/");        registry.addResourceHandler("/localimage/**").addResourceLocations("file:E:/Resources/image/");
        }
    
    }
    

猜你喜欢

转载自blog.csdn.net/weixin_38615065/article/details/88565753
今日推荐