springboot——自动配置

自动配置是什么?

什么是自动配置?举例来讲,当你通过@Autowired或@Resource注解,自动注入一个类实例之前,被注入进来的这个类实例需要被spring容器纳管,不然肯定会注入失败。往往我们会在xml通过`bean id="dfdf"` 或者在类定义上使用@Component、@Configuration等注解,来实现其被spring容器管理。而对于jar包中的类,则稍微复杂一点,要根据jar包中类的实现进行相应引入。
而spring boot的自动配置功能,会对我们配置的一些类,自动注入到spring容器中。特别是对于依赖的jar包中的一些类,在我们的工程用到这些类实例时,直接@Autowired或@Resource注解注入使用就可以了。

自动配置如何实现的?

使用@EnableAutoConfiguration注解,会启用自动配置

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

该注解导入了EnableAutoConfigurationImportSelector,其selectImports方法

@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);
   }
}

其通过getCandidateConfigurations 方法,获取配置文件列表:

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;
}

loadFactoryNames会加载所有META-INF下有spring.factories文件的jar包,并根据spring.factories文件中的配置,去加载相应的类。

public static List loadFactoryNames(Class factoryClass, ClassLoader classLoader) {
   String factoryClassName = factoryClass.getName();
   try {
      Enumeration urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
            ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
      List result = new ArrayList();
      while (urls.hasMoreElements()) {
         URL url = urls.nextElement();
         Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
         String factoryClassNames = properties.getProperty(factoryClassName);
         result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
      }
      return result;
   }
   catch (IOException ex) {
      throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
            "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
   }
}

随便找一个spring.factories文件看看:

springboot——自动配置_第1张图片

利用自动配置,加载自定义jar包

看的差不多了,我们可以自己实现一个工具类,然后利用spring boot的自动配置。

自定义工具类

创建一个maven工程:

xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
com.jzh
envutils
0.0.1-SNAPSHOT
创建一个工具类:

package envutils;

public class EnvUtils {
    private String env = "test";

    public String printEnv() {
        System.out.println(env);
        return env;
    }

    public String getEnv() {
        return env;
    }

    public void setEnv(String env) {
        this.env = env;
    }

}

很简单,pringEnv方法,会返回env值,也就是“test"

接下来,就是在META-INF目录下,创建一个spring.factories文件,默认META-INF目录是没有的,我们手动创建一个:

springboot——自动配置_第2张图片

其中写入:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\

envutils.EnvUtils

测试类

同样的,我们再创建一个maven工程

xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
com.jzh
AotuTest
0.0.1-SNAPSHOT


    org.springframework.boot
    spring-boot-starter-parent
    1.5.0.RELEASE



    
        com.jzh
        envutils
        0.0.1-SNAPSHOT
    
    
        org.springframework.boot
        spring-boot-starter-web
    
    
        org.springframework.boot
        spring-boot-starter-web
    
    
        org.springframework.boot
        spring-boot-autoconfigure
    

其中引用了spring的一些基础包,和我们上面创建的工具类

创建一个测试类:

package com.jzh.autotest;

        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.boot.SpringApplication;
        import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
        import org.springframework.stereotype.Controller;
        import org.springframework.web.bind.annotation.RequestMapping;
        import org.springframework.web.bind.annotation.ResponseBody;

        import envutils.EnvUtils;

@Controller
@EnableAutoConfiguration
public class AutoTest {

    @Autowired
    private EnvUtils envUtils;

    @RequestMapping("/env")
    @ResponseBody
    public String env() {
        String env = envUtils.printEnv();
        return env;
    }

    public  static void main(String args[]) {
        SpringApplication.run(AutoTest.class,args);
    }
}

运行,发现envUtils注入成功。

调用/env,返回test:

springboot——自动配置_第3张图片

一点拓展

上面简单演示了自动配置。想一想,如果我们工程中,需要更改env值,应该怎么办?env.setEnv肯定有点丑陋了。能否读取文件中的配置呢?当然可以。

在工具上,添加@ConfigurationProperties(prefix="env")注解。

在测试类的配置文件中,添加:env.env=online(你想要设置给env的值)。

注意:当@ConfigurationProperties注解类中属性,添加@NotNull注解时,必须要在配置文件中设置,否则启动会报错。


参考:http://blog.sina.com.cn/s/blog_c90ce4e00103296u.html

你可能感兴趣的:(spring-boot)