@ConditionalOnXXX
此类注解做为Bean的注册条件。
@ConditionalOnClass
如@ConditionalOnClass(value = XXX.class)
是XXX.class
存在就将A对象注册到容器中、存在与不存在最好的区分方法就是如果XXX.class
没有编译出问题就肯定存在、但是这样的话就体验不出这个注解存在的作用、可以使用在类上和方法上。
@Bean
@ConditionalOnClass(value = XXX.class)
public A a() {
return new A();
}
真要亲自演示一遍的话可以试着我这样、这个注解一般用在引入第三方jar出现的比较多、简单理解一下、让你设计一个第三方的一个工具、但是你要根据项目中某个依赖类才能够将第三方jar中的类注册到容器中、如我当前项目使用的mysql、而我第三方jar中有个类需要是mysql中才能用的。
第三方jar
我们通过一个META-INF/spring.factories
、当做自动装配对象、然后在去配置依赖pom.xml
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.wei.CustomConfigOne
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<optional>true</optional>
</dependency>
<!--mysql驱动包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
<optional>true</optional>
</dependency>
</dependencies>
为什么这个第三方依赖需要加mysql依赖呢?是因为@ConditionalOnClass(JDBC4Connection.class)
在编译的时候会报错所以需要把它的依赖先给加上、不同的就是<optional>true</optional>
后面演示区别。
@ConditionalOnClass(JDBC4Connection.class)
public class CustomConfigOne {
}
第三方的jar就算弄好了、就相当于是引入了这个第三方jar的话JDBC4Connection.class
类必须存在、这个CustomConfigOne
类才会注入到spring容器中。
本地项目
将第三方jar引用到本地项目中
<dependency>
<groupId>com.wei</groupId>
<artifactId>demo2</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
然后设置启动后打印所有Bean名称
@SpringBootApplication
public class Demo1Application {
public static void main(String[] args) {
ApplicationContext applicationContext = SpringApplication.run(Demo1Application.class, args);
for (String name : applicationContext.getBeanDefinitionNames()) {
System.out.println(name);
}
}
}
启动中会发现没有叫CustomConfigOne
这个名称的Bean、然后我们将本地项目中的mysql依赖放入进去
<dependency>
<groupId>com.wei</groupId>
<artifactId>demo2</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!--mysql驱动包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
这个时候在启动就会发现CustomConfigOne
这个被注册进去了。
<optional>true</optional>
区别如果第三方不设置这个、本地项目maven如下
如果第三方设置了这个<optional>true</optional>
本地项目mavne如下
以上就是演示@ConditionalOnClass
注解如果设置不存在的类编译报错的情况下如何使用、以上说的要注意一个点就是第三方和本地的依赖版本的管理、如果本地用mysql8点几的依赖、而第三方又用mysql5点几、这样会导致你本地是引入了mysql的依赖但是没有@ConditionalOnClass
中设置的对象这就很尴尬了。
还有一个方式就是通过@ConditionalOnClass
name属性写全路径的的方式、这样就不存在类编译报错问题。
@ConditionalOnClass(name = "com.mysql.jdbc.JDBC4Connection")
简单来说:设置的全路径是一个存在且正确的位置、标记了该对象的话就会加载到容器中。
@ConditionalOnMissingClass
相比于上面@ConditionalOnClass
、这个@ConditionalOnMissingClass
还简单一些因为这个只有一个参数、就是设置全路径的方式、可以使用在类和方法上。
@Bean
@ConditionalOnMissingClass(value = {"com.wei.CustomConfigOne"})
public A a() {
return new A();
}
当@ConditionalOnMissingClass
中设置的类路径能找到时、A对象不会被注册到容器中、是否能找到怎么样才算找到?你可以理解为使用Class.forName()
能加载出来类对象就证明这个类存在。
简单来说:设置的全路径是一个存在且正确的位置、标记了该对象则不会加载到容器中。
@ConditionalOnMissingBean
如@ConditionalOnMissingBean(XXXX.class)
中的XXXX.class
类型没有被加载到Spring容器
中的话就将A对象
加载到容器中。
PS:注解支持放在类上。
@Bean
@ConditionalOnMissingBean(XXXX.class)
public A a(){
return new A();
}
例子
@Configuration
public class CustomConfig {
@Bean
public B b() {
return new B();
}
@Bean
@ConditionalOnMissingBean(value = B.class)
public A a() {
return new A();
}
}
上面例子就会加载B对象到容器中、而A对象要加载的时候发现使用了这个注解、而B对象已经在容器中了、这个时候就不会加载A对象到容器中、要注意的在@Configuration
中加载bean的顺序是从上往下、如果B写在A后面加载的话则A对象也会被加载到容器中。
简单一句话概括就是:如果指定对象已经在容器中存在就不会加载该对象到容器中。
@ConditionalOnBean
如@ConditionalOnBean(value = XXX.class)
中的XXX类存在容器中就会加载A对象到容器中
PS:注解支持放在类上。
@Bean
@ConditionalOnBean(value = XXX.class)
public A a() {
return new A();
}
例子
@Configuration
public class CustomConfig {
@Bean
@ConditionalOnBean(value = B.class)
public A a() {
return new A();
}
@Bean
public B b() {
return new B();
}
}
而上面例子中就会加载B对象在容器中、这个注解的作用就是容器中有对应对象就会加载A对象。
简单一句话概括就是:如果指定对象已经在容器中存在就会加载该对象到容器中。
@ConditionalOnProperty
这个注解的作用是指、指定存在某个配置项的时候就注册bean到容器中、不存在则不加载。
PS:注解支持放在类上。
a:
b:
c: d
@Configuration
public class CustomConfig {
@Bean
@ConditionalOnProperty("a.b.c")
public A a() {
return new A();
}
}
参数说明
// 默认值、设置包括前缀以及配置名称
String[] value() default {};
// 前缀名称
String prefix() default "";
// 配置名称、一般以最后一个name做为配置名称
String[] name() default {};
// 设置配置的值、如果不相同则不加载、确保配置项存在的情况下
String havingValue() default "";
// 默认找不到配置项则不加载bean
boolean matchIfMissing() default false;
例子
@Configuration
public class CustomConfig {
@Bean
@ConditionalOnProperty(prefix = "a.b", name = "c", havingValue= "d")
public A a() {
return new A();
}
}
配置项要匹配、并值要等于b、否者不加载A对象。
简单来说:使用这个注解的话配置类中需要对应配置的内容、否则不加载该类。
@AutoConfigureXXX
@AutoConfigureOrder
、@AutoConfigureBefore
和@AutoConfigureAfter
这三个注解适用于自动配置类的加载顺序。
SpringBoot中的自动配置类都是这个文件中配置我们也可以在自己项目中的resources
下META-INF/spring.factories
、写一个这样的文件。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.wei.config.C,com.wei.config.B,com.wei.config.A
注意:这三种注解只能在spring.factories
中配置的类才能使用这三个注解生效、其次不会按照文件中类的顺序加载、目前你可以理解为A-B-C这种加载方式
@AutoConfigureOrder
这个最好理解、值越小加载就加载自动配置的类。
@AutoConfigureOrder(1)
public class A {
public A() {
System.out.println("A.......");
}
}
@AutoConfigureOrder(2)
public class B {
public B() {
System.out.println("B.......");
}
}
@AutoConfigureOrder(0)
public class C {
public C() {
System.out.println("C.......");
}
}
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.wei.config.C,com.wei.config.B,com.wei.config.A
这个是必须要的、要不然的话都没有加载到容器中。
测试结果
C.......
A.......
B.......
@AutoConfigureAfter
可以这样理解:在加载当前类的时候先去加载@AutoConfigureAfter
中指定的类、等指定的类加载后在去加载当前的类、注意的是要在spring.factories
中配置的类
public class A {
public A() {
System.out.println("A.......");
}
}
@AutoConfigureAfter(C.class)
public class B {
public B() {
System.out.println("B.......");
}
}
public class C {
public C() {
System.out.println("C.......");
}
}
测试结果
A.......
C.......
B.......
@AutoConfigureBefore
可以这样理解:当前类的时候先会去有没有类使用了@AutoConfigureBefore
注解标记当前加载的类我就先加载标记的类、再去加载当前类。
public class A {
public A() {
System.out.println("A.......");
}
}
public class B {
public B() {
System.out.println("B.......");
}
}
@AutoConfigureBefore(A.class)
public class C {
public C() {
System.out.println("C.......");
}
}
测试结果
C.......
A.......
B.......
默认的话肯定是A-B-C的这种加在顺序、按默认加载方式、我加载A的时候我先去找有没有类被@AutoConfigureBefore
标记了A类、发现C类标记了所以先加载C类、在加载A类、后面就在加载B类。
@EnableConfigurationProperties
这个注解@EnableConfigurationProperties
一般配合@ConfigurationProperties
注解使用、只能放在类上、先看个例子
a:
b:
c: dfffff
@ConfigurationProperties(prefix = "a.b")
public class AProperties {
private String c;
public String getC() {
return c;
}
public void setC(String c) {
this.c = c;
}
}
@Configuration
@EnableConfigurationProperties(AProperties.class)
public class CustomConfig {
@Autowired
private AProperties aProperties;
@PostConstruct
public void init(){
System.out.println(aProperties.getC());
}
}
最后输出的结果就是dfffff
、最后可以理解为@EnableConfigurationProperties
注解会将设置的配置类注入到容器中、但是配置类中需要加上@ConfigurationProperties
注解、不加就报错!!!
还有一种就是不使用@EnableConfigurationProperties
和@ConfigurationProperties
、使用@Component
和@ConfigurationProperties
这样就是直接标记配置类到容器中了。
还有一个要注意的就是使用了@Component
又使用@EnableConfigurationProperties
、在@Autowired
对象的时候就会报错:说找到了两个类型的类、不知道选择哪一个。
@Import
这个@Import
相当于是将填写的类注入到容器中使用、如一个类加了@Configuration
、但是@Import
中填写的类中不需要@Configuration
。
public class CustomConfigOne {
}
@Configuration
@Import(CustomConfigOne.class)
public class CustomConfig {
}
customConfig
com.wei.config.CustomConfigOne
输出Bean名称会发现两种Bean的名称不一样、注入使用是没有问题的。
小结
以上注解说明了一下使用的方式、没有包含很细节的源码实现解释、还有一些不起眼的注解你们也可以发来一起看看它的使用方式.....以及以上注解有什么问题可以指出来。