前言
我甚至连本篇的标题是否准确都不是特别确定。仅仅想聊下下面几个注解,用法其次的,感受下java程序员最骄傲的框架spring的精妙操作。
@Conditional
@Import
@AutoConfigureAfter
@utoConfigureBefore
@DependsOn
准备
新建两个类,TestA 和TestB,如下:
package com.cmdc.bean;
import lombok.extern.slf4j.Slf4j;
/**
* @author : wuwensheng
* @date : 15:59 2021/12/3
*/
@Slf4j
public class TestA {
public TestA() {
log.warn("testA is created!");
}
}
package com.cmdc.bean;
import lombok.extern.slf4j.Slf4j;
/**
* @author : wuwensheng
* @date : 16:01 2021/12/3
*/
@Slf4j
public class TestB {
public TestB() {
log.warn("testB is created!");
}
}
@ConditionalOnBean、@ConditionalOnMissingBean
@ConditionalOnBean:仅在该注解规定的类实例存在于 spring容器中时,使用该注解的config或者bean声明才会被实例化到容器中
@ConditionalOnMissingBean:仅在该注解规定的类实例不存在于 spring容器中时,使用该注解的config或者bean声明才会被实例化到容器中
下面试验下: 创建一个配置类:
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
/**
* @author : wuwensheng
* @date : 10:04 2021/12/6
*/
@Configuration
@Slf4j
public class TestConfiguration {
@ConditionalOnMissingBean
@Bean
public TestA getTestA(){
log.warn("start new TestA");
return new TestA();
}
}
目前,并没有TestA类型的Bean存在于spring的容器中。所以这个getTestA()方法会执行。TestA类的实例将被创建,名字为getTestA.
ok的。那么现在在TestConfiguration这个类中增加下面这段:
@ConditionalOnBean(TestA.class)
@Bean(value = "testB2")
@DependsOn("getTestA")
public TestB getTestB() {
log.warn("start new TestB");
return new TestB();
}
变成这个样子
@ConditionalOnBean(TestA.class)表示我希望仅仅在TestA的实例存在于spring容器中时,才调用getTestB方法创建TestB的实例。@DependsOn注解要求这个方法的执行依赖getTestA实例的创建。
那么下面运行下;
对的。
假设我们此时注释掉TestA实例的创建,那么自然而然的TestB的实例也无法创建了。
@ConditionalOnClass、@ConditionalOnMissingClass
这两个注解
@ConditionalOnClass:某个class位于类路径上,才会实例化一个Bean
@ConditionalOnMissingClass:某个class没有位于类路径上,才会实例化一个Bean
增加两个类,TestC、TestD
package com.cmdc.bean;
import lombok.extern.slf4j.Slf4j;
/**
* @author : wuwensheng
* @date : 16:04 2021/12/3
*/
@Slf4j
public class TestC {
public TestC() {
log.info("testC is created!");
}
}
import lombok.extern.slf4j.Slf4j;
/**
* @author : wuwensheng
* @date : 16:22 2021/12/3
*/
@Slf4j
public class TestD {
public TestD() {
log.info("testD is created!");
}
}
配置类增加如下两个配置方法:
@ConditionalOnClass(TestC.class)
@Bean
public TestC getTestC() {
log.info("start new TestC");
return new TestC();
}
@ConditionalOnMissingClass("com.cmdc.bean.Test")
@Bean
public TestD getTestD() {
log.info("start new TestD");
return new TestD();
}
那么TestC位于类路径,所以getTestC方法会被执行。
“com.cmdc.bean.Test”是一个不存在的类路径,getTestD也会被执行。
运行结果符合预期的。
最后多说一句,控制依赖顺序的Conditional家族不仅仅这几个注解还有许多,感兴趣的可以都看一看,但是一般来说,即便封装个小框架,上面提到的掌握了基本也是够用的。
@DependsOn
作用:
用于指定某个类的创建依赖的bean对象先创建。spring中没有特定bean的加载顺序,
使用此注解则可指定bean的加载顺序。(在基于注解配置中,是按照类中方法的书写顺序决定的)
属性:
value:
用于指定bean的唯一标识。被指定的bean会在当前bean创建之前加载。
这个注解咱们刚才已经使用过了,就不再多做阐述。用于指定bean的依赖关系。
@AutoConfigureAfter、@AutoConfigureBefore
这两个注解用于配置类上,规定类加载的顺序问题,在框架的源码中也是非常常见的。 下面继续咱们的实验。
有这么几点注意事项: 1、使用该注解的配置类必须在springboot启动类扫描不到的地方。 2、使用spring.factories的方式来加载使用这个注解的配置类。
新建TestE和TestF类
import lombok.extern.slf4j.Slf4j;
/**
* @author : wuwensheng
* @date : 15:15 2021/12/6
*/
@Slf4j
public class TestE {
public TestE() {
log.info("testE is created!");
}
}
import lombok.extern.slf4j.Slf4j;
/**
* @author : wuwensheng
* @date : 15:15 2021/12/6
*/
@Slf4j
public class TestF {
public TestF() {
log.info("testF is created!");
}
}
我在启动类下新建了一个test包。
这两个配置类分别加载TestE和TestF
import com.cmdc.bean.TestF;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
*
* @author : wuwensheng
* @date : 14:44 2021/12/6
*/
@Slf4j
@AutoConfigureAfter({TestEConfiguration.class})
@Configuration
public class AutoConfiguration {
public AutoConfiguration() {
log.info("执行。。。");
}
@Bean
public TestF tetstF(){
log.info("create testF!!");
return new TestF();
}
}
import com.cmdc.bean.TestE;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author : wuwensheng
* @date : 14:48 2021/12/6
*/
@Slf4j
@Configuration
public class TestEConfiguration {
public TestEConfiguration() {
log.info("执行");
}
@Bean
public TestE testC(){
log.info("create testE!!!!!!");
return new TestE();
}
}
配置spring.factories文件
ok,那么现在在AutoConfiguration配置类中使用的是@AutoConfigureAfter,所以是TestEConfiguration先执行,AutoConfiguration后执行:
是的,然后将注解改成@AutoConfigureBefore
是对的! 这两个注解作用于标记了@Configuration的类!
总结
本文到此,随时补充。