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

前言

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

创建自己的自动装配

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

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

kotlin 复制代码
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文件,并添加以下代码:

ini 复制代码
   org.springframework.boot.autoconfigure.EnableAutoConfiguration=\geek.springboot.configuration.MasterNodeAutoConfiguration

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

less 复制代码
@Slf4j  
@AutoConfiguration  
public class MasterNodeAutoConfiguration {  
  
     ......
  
}

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

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,代码如下:

less 复制代码
@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加载,代码如下:

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

自动装配的顺序

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

@AutoConfigureAfter 和 @AutoConfigureBefore

新建一个SlaveNodeAutoConfiguration,代码如下:

kotlin 复制代码
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也给加上:

ini 复制代码
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\geek.springboot.configuration.MasterNodeAutoConfiguration,\  
geek.springboot.configuration.SlaveNodeAutoConfiguration

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

less 复制代码
@Slf4j  
@AutoConfigureAfter(SlaveNodeAutoConfiguration.class)  
@AutoConfiguration  
public class MasterNodeAutoConfiguration {  
  
    ......
  
}

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

kotlin 复制代码
@AutoConfiguration(after = SlaveNodeAutoConfiguration.class)  
public class MasterNodeAutoConfiguration {
    ......
}

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

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

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

@AutoConfigureOrder

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

SlaveNodeAutoConfiguration稍作调整,代码如下:

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

MasterNodeAutoConfiguration稍作调整,代码如下:

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

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

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

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

@ConditionalOnClass

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

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

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

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

@ConditionalOnMissingClass

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

MasterConfiguration稍作调整:

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

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

@ConditionalOnBean 和 @ConditionalOnMissingBean

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

@ConditionalOnProperty

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

MasterNodeAutoConfiguration再次稍作调整:

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

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

往application.yml添加配置:

yaml 复制代码
node:  
  open: true

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

@ConditionalOnResource

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

倒霉的MasterNodeAutoConfiguration再次做调整:

less 复制代码
@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核心特性------异步任务和定时任务那些事

相关推荐
神明不懂浪漫13 分钟前
【第五章】Java中的继承与多态
java·开发语言
AI多Agent协作实战派2 小时前
AI多Agent协作系统实战(十七):凌晨4点,我的AI系统在“假装工作“——3个bug同时爆炸的5小时
java·前端·bug
gaolei_eit2 小时前
Java+Ai+vue
java·spring·maven
qq_2518364572 小时前
基于java Web 动漫视频网站毕业论文
java·开发语言·前端
LayZhangStrive3 小时前
JUC相关的函数、注解、变量杂记
java·面试·多线程·juc
未秃头的程序猿3 小时前
给公司做了个AI客服Agent,用的Spring AI 1.0,3天上线领导拍板了
java·后端·ai编程
曹牧3 小时前
Eclipse 批量文本替换
java·ide·eclipse
程序员清风3 小时前
OpenAI官方发布最新提示词技巧!
java·后端·面试
一只枫林3 小时前
MySQL内、外连接知识点汇总
java·前端·数据库
梅头脑3 小时前
写了3年CRUD,volatile和synchronized的区别还是答不清——直到我画出了这张三性两锁边界图
java