不学无数—SpringBoot入门Ⅶ

SpringBoot入门Ⅶ

Posted by 不学无数 on September 7, 2018

SpringBoot

1.创建自己的Auto-configuration

无论是在公司中你想开发自己的一套框架,定制一些东西,或者是在开源网站中分享自己做的一些东西。你可能想要开发属于自己的Auto-configuration。Auto-configuration的类能够捆绑到外部的jar包中,并且被SpringBoot进行使用。例如我们经常使用的@Autowire注解会自动的注入一个实例到Spring的容器中,这时我们被注入进来的类必须有个注解进行标注,例如:@Service、@Controller等等。但是对于在jar包中的类的话,考虑的需要多一些,例如需要考虑在注入时我会依赖到谁,谁先进行注入等等。

Auto-configuration通常是和starter联系起来的,一个官网提供的小例子展示了如何一步一步创建属于自己的starter

1.1 理解Auto-configured类

在底层代码中,Auto-configured是被@Configuration注解的类实现的。另外@Conditional注解被用来限制什么时候Auto-configured应该被应用。通常来说,Auto-configured的类使用@ConditionalOnClass@ConditionalOnMissingBean这两个注解,这是为了确保 auto-configuration 只在一些相关的类生效以后才会加载@Configuration类。

你也可以通过浏览SpringBoot-autoConfigure由Spring提供的@Configuration类。

1.2 Auto-configuration的目录结构

SpringBoot会检查所有jar包中的META-INF/spring.factories文件,在这个文件中应该列出了key是EnableAutoConfiguration value是想要配置的类,例如下:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.mycorp.libx.autoconfigure.LibXAutoConfiguration,\
com.mycorp.libx.autoconfigure.LibXWebAutoConfiguration

当然也可以使用 @AutoConfigureAfter@AutoConfigureBefore两个注解进行标识想要哪个类进行先加载。例如想要提供一个特定的web配置,那么你的类应该在WebMvcAutoConfiguration之后加载。

如何想要auto-configurations的类进行顺序的加载,那么可以使用@AutoConfigureOrder注解进行排序。

Auto-configurations仅仅能够被这种方式进行加载,实际上,他们不会被包扫描进行加载。

1.3 Condition注解

SpringBoot利用@Condition注解来确定是不是要创建Bean实例

在所开发的对外封装jar包中可能会使用一个或者多个的@Condition注解在自动配置的类中。@ConditionalOnMissingBean注解会覆盖掉你的默认配置。

SpringBoot包括许多的@Conditional的注解,你能够重复使用它在类中或者单独的@Bean方法上。这些注解包括

  • Class Conditions
  • Bean Conditions
  • Property Conditions
  • Resource Conditions
  • Web Application Conditions

1.3.1 Class Conditions

  • @ConditionalOnClass: 某个class位于类路径上,才会实例化一个Bean。该注解的参数对应的类必须存在,否则不解析该注解修饰的配置类。这个很有用的,比如不同的jar包之间有依赖,如果依赖的类不存在的话,那么就会直接跳过,不会报错。
  • @ConditionalOnMissingBean:仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean。该注解表示,如果存在它修饰的类的bean,则不需要再创建这个bean,可以给该注解传入参数例如@ConditionOnMissingBean(name = “example”),这个表示如果name为“example”的bean存在,这该注解修饰的代码块不执行

1.3.2 Bean Conditions

  • @ConditionalOnBean:仅仅在当前上下文中存在某个对象时,才会实例化一个Bean
  • @ConditionalOnMissingBean:仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean

举例如下:

@Configuration
public class MyAutoConfiguration {

	@Bean
	@ConditionalOnMissingBean
	public MyService myService() { ... }

}

1.3.3 Property Conditions

  • @ConditionalOnProperty:这个注解能够控制某个configuration是否生效。具体操作是通过其两个属性name以及havingValue来实现的,其中name用来从application.properties中读取某个属性值,如果该值为空,则返回false;如果值不为空,则将该值与havingValue指定的值进行比较,如果一样则返回true;否则返回false。如果返回值为false,则该configuration不生效;为true则生效。

1.3.4 Resource Conditions

  • @ConditionalOnResource注解允许只有在特定资源出现时配置才会生效。资源可以使用常见的Spring约定命名,例如file:/home/user/test.dat。

1.3.5 Web Application Conditions

  • @ConditionalOnWebApplication和@ConditionalOnNotWebApplication两个注解会根据应用是否为一个Web应用而使配置生效。

2. 一个自动配置的小例子

2.1 创建一个接受配置属性的类

如果对于如何用java实体类进行接受配置文件的属性不明白的,可以参考我的文章不学无数——SpringBoot入门Ⅲ,里面有详细讲解。


@ConfigurationProperties("acme")
@Validated
public class AcmeProperties {
	private boolean enabled;
	@NotNull(message = "不能weikong ")
	private String remoteAddress;

	public boolean isEnabled() { return enabled; }

	public void setEnabled(boolean enabled) { this.enabled=enabled; }

	public String getRemoteAddress() { return remoteAddress; }

	public void setRemoteAddress(String remoteAddress) { this.remoteAddress=remoteAddress; }

}

2.2 创建配置属性的类

这里只是简单的举个配置属性的例子: 例如在这里可以进行配置数据库的事务。然后在动态创建数据源的时候可以判断这个类是否创建然后创建数据源。

即这个类是一个作为判断依据的类

public class AcmeService {
    private String msg;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    @Override
    public String toString() {
        return "AcmeService{" +
                "msg='" + msg + '\'' +
                '}';
    }
}

2.3 创建自动配置的类

@ConditionalOnClass该注解在之前已经讲过,这里的意思就是AcmeService类在路径中已经存在以后才会解析配置类。 @ConditionalOnMissingBean方法上的注解我们上面也解释过了,在这的意思就是在容器中没有AcmeService对象时才会实例化此Bean。


@Configuration
@ConditionalOnClass(AcmeService.class)
@EnableConfigurationProperties(AcmeProperties.class)
public class AcmeAutoConfiguration {

    private final AcmeProperties acmeProperties;

    public AcmeAutoConfiguration(AcmeProperties acmeProperties) {
        this.acmeProperties = acmeProperties;
    }

    @Bean
    @ConditionalOnMissingBean(AcmeService.class)
    public AcmeService getAcmeService(){
        AcmeService acmeService=new AcmeService();
        acmeService.setMsg(acmeProperties.toString());
        return acmeService;
    }
}

2.4 注册配置

resources-META-INF文件夹下创建spring.factories文件,里面写入自动配置类的路径

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.FirstSpringBoot.Configuration.AcmeAutoConfiguration

2.5 开始使用

因为我们创建的自动配置是要供别人使用的,只对外提供配置的属性值,所以我们将我们写的自动配置的一系列类进行打jar包,另一个项目引用过后只需要在配置文件中配置我们对外提供的配置属性进行配置以后就可以使用我们自动配置类提供的功能了。这也正符合了SpringBoot的开箱即用的观点。