SpringBoot核心特性——你所要知道的自动装配

2023年 8月 1日 85.3k 0

前言

本文主要讲解SpringBoot的自动装配特性,这个特性使得第三方应用很容易就集成到SpringBoot中,这也是为什么使用SpringBoot的时候,只需要引入依赖,稍微修改配置,就能迅速使用这些第三方应用进行开发的原因。

创建自己的自动装配

假设我们正在开发一个多节点切换的库,这个库是作为第三方依赖提供给当前项目使用的。

新建一个Master主节点配置类,代码如下:

package geek.springboot.configuration;  
  
import lombok.extern.slf4j.Slf4j;  
  
import javax.annotation.PostConstruct;  
  
/**  
* 主节点配置类  
*  
* @author Bruse  
*/  
@Slf4j  
public class MasterNodeAutoConfiguration {  
  
    @PostConstruct  
    public void init() {  
        // 在该类的实例初始化时打印
        log.info("MasterNodeAutoConfiguration init");  
    }  
  
}

注意,这里MasterNodeAutoConfiguration全限定类名是geek.springboot.configuration.MasterNodeAutoConfiguration , SpringApplication启动类的全限定类名是geek.springboot.application.Application,SpringApplication启动时,默认只会扫描当前所在的包及其子包,所以这里相当于模拟了一个第三方库,因为第三方库使用的包名类路径不可能和你的项目一样。

这个时候启动SpringApplication,MasterNodeAutoConfiguration其实不会被SpringApplication扫描到的,还需要告诉SpringBoot这是个自动装配的类。

spring.factories 自动装配

在项目resources目录下新建META-INF/spring.factories文件,并添加以下代码:

   org.springframework.boot.autoconfigure.EnableAutoConfiguration=geek.springboot.configuration.MasterNodeAutoConfiguration

MasterNodeAutoConfiguration加上@AutoConfiguration注解,表示它是一个配置类。

@Slf4j  
@AutoConfiguration  
public class MasterNodeAutoConfiguration {  
  
     ......
  
}

启动SpringApplication,可以看到MasterNodeAutoConfiguration已被初始化

image.png

AutoConfiguration.imports 自动装配

除了使用spring.factories进行自动装配,还可以在resources目录下新建META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件,并把MasterNodeAutoConfiguration的全限定类名写在该文件中,代码如下:

geek.springboot.configuration.MasterNodeAutoConfiguration

如果有多个需要自动装配的类,直接换行,再补充上相关类名即可,像这样:

geek.springboot.configuration.MasterNodeAutoConfiguration
geek.springboot.configuration.MasterNodeAutoConfiguration

@ImportAutoConfiguration

还可以在SpringApplication启动类加上@ImportAutoConfiguration注解,让SpringBoot在启动的时候加载MasterNodeAutoConfiguration,代码如下:

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

注意:用@Import也可以让SpringBoot在启动时加载自定义的Configuration,但是这样无法使用@AutoConfigureOrder、@Order指定加载优先级

使用@Import注解进行MasterConfiguration加载,代码如下:

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

自动装配的顺序

如果想要让自己的配置类按特定顺序初始化,那么可以使用相关注解进行调整。

@AutoConfigureAfter 和 @AutoConfigureBefore

新建一个SlaveNodeAutoConfiguration,代码如下:

package geek.springboot.configuration;  
  
import lombok.extern.slf4j.Slf4j;  
import org.springframework.boot.autoconfigure.AutoConfiguration;  
  
import javax.annotation.PostConstruct;  
  
/**  
* 从节点配置类  
*  
* @author Bruse  
*/  
@Slf4j  
@AutoConfiguration  
public class SlaveNodeAutoConfiguration {  
  
    @PostConstruct  
    public void init() {  
        log.info("SlaveNodeAutoConfiguration init");  
    }  
  
}

spring.factories也给加上:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=geek.springboot.configuration.MasterNodeAutoConfiguration,  
geek.springboot.configuration.SlaveNodeAutoConfiguration

最后给MasterNodeAutoConfiguration加上@AutoConfigureAfter,要求MasterNodeAutoConfiguration在SlaveNodeAutoConfiguration之后才被加载:

@Slf4j  
@AutoConfigureAfter(SlaveNodeAutoConfiguration.class)  
@AutoConfiguration  
public class MasterNodeAutoConfiguration {  
  
    ......
  
}

除了用@AutoConfigureAfter外,还可以配置@AutoConfiguration的after属性,比如:

@AutoConfiguration(after = SlaveNodeAutoConfiguration.class)  
public class MasterNodeAutoConfiguration {
    ......
}

启动SpringApplication,输出如下,说明顺序调整成功:

image.png

除了@AutoConfigureAfter,相关的注解还有@AutoConfigureBefore,这里就不做演示了。

注意:@AutoConfigureAfter和@AutoConfigureBefore的顺序调整只能作用在同样加上@AutoConfiguration注解的Bean之间,举个例子,如果当前的@AutoConfigureBefore注解配置的目标类,是一个@Service, 那么当前的Configuration初始化也并不会在Service之前。

@AutoConfigureOrder

除了上边提到的两个注解外,还可以使用@AutoConfigureOrder注解进行自动配置的顺序。它和@Order注解的作用是一样的,只不过它是专门为自动装配的类而用的。

SlaveNodeAutoConfiguration稍作调整,代码如下:

@Slf4j  
@AutoConfigureOrder(10)  // 自动装配优先级,数值越小越优先
@AutoConfiguration  
public class SlaveNodeAutoConfiguration {  
  ......
}

MasterNodeAutoConfiguration稍作调整,代码如下:

@Slf4j  
@AutoConfigureOrder(20)  // 自动装配优先级,数值越小越优先
@AutoConfiguration  
public class MasterNodeAutoConfiguration {  
 ......
}

启动SpringAppcaliton,控制台输出如下,SlaveConfiguration在MasterConfiguration之前被初始化:

image.png

特定条件下的灵活自动装配

有时候我们会需要在特定条件下灵活决定SpringBoot是否加载我们的Configuration,那么Spring也提供了相关注解。

@ConditionalOnClass

该注解表示当前项目存在指定的类时,才实例化修饰了该注解的Java Bean。

MasterConfiguration加上该注解,并要求SpringApplicaiton启动后能在classpath中找到WebService类时,才初始化MasterConfiguration :

@Slf4j  
// 当前项目classpath存在WebService才初始化该Configuration  
@ConditionalOnClass(name = {"geek.springboot.application.service.WebService"})  
@AutoConfigureOrder(20)  
@AutoConfiguration  
public class MasterNodeAutoConfiguration {  
    
    ...... 
}

因为当前项目还没新建WebService这个类,所以启动SpringApplication后,会发现MasterConfiguration没有被初始化,仅仅只有SlaveConfiguration初始化了。

image.png

@ConditionalOnMissingClass

该注解则刚好相反,反而是表示当前项目不存在指定的类时,才实例化修饰了该注解的Java Bean。

MasterConfiguration稍作调整:

@Slf4j  
// 当前项目classpath不存在WebService才初始化该Configuration  
@ConditionalOnMissingClass(value = {"geek.springboot.application.service.WebService"})  
@AutoConfigureOrder(20)  
@AutoConfiguration  
public class MasterNodeAutoConfiguration {  
  ......
}

启动SpringApplication,可以看到即便项目没有WebService这个类,MasterConfiguration也被初始化了。

image.png

@ConditionalOnBean 和 @ConditionalOnMissingBean

这两个注解作用其实跟上边提到的两个注解相似,只不过@ConditionalOnMissingClass 和 @ConditionalOnClass 关注的是是否存在某些类,而这两个注解关注的是当前Spring IOC容器中是否存在某些Bean。这里就不再做具体演示了。

@ConditionalOnProperty

该注解表示当前项目存在某个配置,且值符合条件时,才初始化Configuration。

MasterNodeAutoConfiguration再次稍作调整:

@Slf4j  
// 需要存在node.open配置,且该配置的值为true时,才初始化  
@ConditionalOnProperty(name = "node.open", havingValue = "true")  
@AutoConfiguration  
public class MasterNodeAutoConfiguration {  
  ......  
}

启动SpringApplication,会看到因为项目还没加上node.open这个配置,所以MasterConfiguration没有初始化:

image.png

往application.yml添加配置:

node:  
  open: true

启动SpringApplication,这次MasterNodeAutoConfiguration被初始化了。

image.png

@ConditionalOnResource

该注解表示当存在某个资源文件时,才初始化Configuration。

倒霉的MasterNodeAutoConfiguration再次做调整:

@Slf4j  
// 表示当前classpath下存在node.yml才初始化,也可以是别的路径  
@ConditionalOnResource(resources = {"classpath:node.yml"})  
@AutoConfiguration  
public class MasterNodeAutoConfiguration {  
  ......  
}

那么在resources目录下不存在node.yml的情况下,MasterConfiguration不会被初始化,反之如果resources目录下存在node.yml,MasterConfiguration则会被初始化。这里就不再贴图了,不妨自己动手尝试一下。

@ConditionalOnWebApplication 和 @ConditionalOnNotWebApplication

@ConditionalOnWebApplication注解表示只有当前SpirngApplication是一个Web应用程序时,才初始化该注解修饰的Jave Bean。@ConditionalOnNotWebApplication则相反,表示当前SpringApplication不是作为一个Web应用运行时,才初始化Java Bean。

@ConditionalOnExpression

该注解则比较灵活,允许你用SpEL表达式的方式定义什么条件下才初始化Java Bean。

结尾

本文章源自《Learn SpringBoot》专栏,感兴趣的话还请关注点赞收藏.

上一篇文章:《SpringBoot核心特性——异步任务和定时任务那些事》

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论