Skip to content

maskwang520/springboot-mystarter

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 

Repository files navigation

 在我们日常用springboot的开发过程中,经常会遇到使用如下的一个类来代表程序的入口类。即

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

  包括我自己,我平常在开发的过程中,并没有去重点关注spring boot的运行原理,大家都是约定俗成的这么去使用。接下的过程中,将会结合源码简单的分析下springboot运行原理。

一.Springboot 自动配置原理分析

   @SpringBootApplication注解@SpringBootApplication是一个复合注解,它包括@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan三个注解。其中最关键的莫过@EnableAutoConfiguration这个注解。在它的源码中加入了这样一个注解@Import({EnableAutoConfigurationImportSelector.class})EnableAutoConfigurationImportSelector,它使用SpringFactoriesLoader. loadFactoryNames方法来扫描META-INF/spring.factories文件,此文件中声明了有哪些自动配置。源码如下(我挑选出重要的一部分)

public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();
        try {
            Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                    ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
            List<String> result = new ArrayList<String>();
            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-boot-autoconfigure-1.5.3.RELEASE.jar中的spring.factories,有如下的自动配置。

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\

上述spring.factories对应key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的值即为启动时候需要自动配置的类。

二. 实现自定义的starter

  1. 首先定义一个基本的对象类,用来接收application.properties里面特定字段的值。
@ConfigurationProperties(prefix = "hello")
public class HelloServiceProperties {
    private static final String MSG="world";
    private String msg=MSG;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}
  • @ConfigurationProperties(prefix = "hello")是类型安全的属性获取。在application.properties 中通过hello.msg来设置,如果不设置默认就是“word"。
  1. 定义条件类(根据此类的存在与否来创建这个类的Bean,这个类可以是第三方类库的类)。
public class HelloService {
    private String msg;
    public String sayHello(){
        return msg;
    }
    public void setMsg(String msg){
        this.msg=msg;
    }
}
  1. 自动配置类
@Configuration  //1
@EnableConfigurationProperties(HelloServiceProperties.class)//2
@ConditionalOnClass(HelloService.class)   //3
@ConditionalOnProperty(prefix = "hello",value = "enabled",matchIfMissing = true)  //4
public class HelloServiceAutoConfiguration {

    @Autowired
    private HelloServiceProperties helloServiceProperties;

    @Bean
    @ConditionalOnMissingBean(HelloService.class)  //5
    public HelloService helloService(){
        HelloService helloService=new HelloService();
        helloService.setMsg(helloServiceProperties.getMsg());
        return helloService;
    }
}
  • @Configuration 它告知 Spring 容器这个类是一个拥有 bean 定义和依赖项的配置类。
  • @EnableConfigurationProperties的bean可以以标准方式被注册(例如使用 @Bean 方法),即我定义HelloServiceProperties可以作为标准的Bean被容器管理。
  • @ConditionalOnClass表示该类在类路径下存在,自动配置该类下的Bean。
  • @ConditionalOnProperty当指定的属性等于指定的值的情况下加载当前配置类,在这里如果matchIfMissing如果为false,则在application.properties中必须存在hello.enable(且不能为false)
  • @ConditionalOnMissingBean()表示指定的bean不在容器中,则重新新建@Bean注解的类,并交给容器管理。

  配置好之后,我们还需要在src\main\resources下新建文件夹WEB-INF,再新建文件spring.factories里面的内容如下

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.springboot.mystartertool.HelloServiceAutoConfiguration

里面指定的类是上面自定义的那个配置类HelloServiceAutoConfiguration

  定义spring.factories的原因是因为@EnableAutoConfiguration会扫描jar包下所有spring.factories文件,从而构造自动配置类。我们使用的时候使用 @Autowired注入就行。

在以上工作完成后,我们执行如下命令

    mvn clean install

  就将项目打包到本地maven仓库中,有条件的可以安装的到私服中。

三. 应用自定义starter

  1. 首先引入自定义的starter的jar包
 <!--引入我的start-->
        <dependency>
            <groupId>com.maskwang</groupId>
            <artifactId>Springboot-mystart</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
  1. 当我们在application.properties配置如下
hello.msg=maskwang

  我们就可以使用自定义的starter啦。

@RestController
public class HelloController {
    @Autowired
    HelloService helloService;
    @RequestMapping("/hello")
    public String hello() {
        return helloService.sayHello();
    }
}

  由于我们没有自定义HelloService,所以会配置类会发挥作用,新建一个HelloService,并把里面的msg设置成”maskwang"。没有配置msg,则会采用默认的。结果如下

image.png

参考文献:

  1. 使用 Java 配置进行 Spring bean 管理
  2. Spring boot实战(汪云飞著) github地址

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages