@Conditional
条件装配: 满足Conditional指定的条件,则进行组件注入
Conditional还是个根注解,它下面还派生了非常多的注解,注解的功能可以来看一下Conditional
在IDEA
中找到@Conditional
注解:
package org.springframework.context.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
Class<? extends Condition>[] value();
}
Ctrl + h
打开继承数:
每一个注解代表了不同的功能,我们找几个具有典型代表的
@ConditionalOnBean
就是说当容器中存在我们指定的这个Bean(组件)的时候我们才干某些事情
相反的就有一个
@ConditionalOnMissingBean
:当容器中没有这个Bean(组件)的时候,我们才干某些事情@ConditionalOnClass
当容器中有某ry一个类的时候,我们才干某些事情
相反的就有一个
@ConditionalMissingClass
:当容器中没有这个类的时候,我们才干某些事情(比如没有的时候给容器中注入哪些组件)@ConditionalOnResource
当我们这个项目的类路径里面存在某一个资源的时候,我们才干什么
@ConditionalOnJava
是指定某些java版本号后我们才干什么
@ConditionalOnWebApplication
当我们这个应用是web应用的时候,我们才干什么
相反的就有一个
@ConditionalOnNotWebApplication
当我们的应用不是web应用的时候我们做什么@ConditionalOnSingleCandidate
当我们容器中指定了这个组件只有一个实例或者它有多个实例但是有一个东西是我们的说的主实例(也就是我们用
@Primary
我们标注的)说明@ConditionalOnSingleCandidate
才生效@ConditionalOnProperty
当配置文件里面配置了某个属性的时候我们才干某些事情
等等
取出这些例子,来做俩个实例
@ConditionalOnBean
还是来到
MyConfig.java
配置类:package com.chentianyu.boot.config; import com.chentianyu.boot.bean.Pet; import com.chentianyu.boot.bean.User; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @Configuration 标注在一个类上告诉它(Spring)这是一个配置类 * 1、配置类里面我们可以使用@Bean标注在方法上给容器注册组件,默认也是单实例的 * 2、需要注意的是@Configuration标注的这个类,它本身也是一个组件 * 3、proxyBeanMethods: 代理Bean的方法 */ //@Component @Configuration(proxyBeanMethods = false)//告诉SpringBoot这是一个配置类(把这个类说明@Configuration类似于告诉spring这个文件是配置文件) public class MyConfig { /** * 外部无论对配置类中的这个组件注册方法调用多少次,获取的都是之前注册容器中的单实例对象 * @return */ @Bean //我们不用<Bean>标签,我们用@Bean注解 public User user01(){ return new User(18, "lisi"); } @Bean("tom") public Pet tomcatPet(){ return new Pet("tomcat01"); } }
这段配置我们看到
user01()
我们给容器中注册(@Bean
)了一个user01
组件,这个组件有没有,它不一定。假设我们给容器中都没有注册(//@Bean("tom")
)这个tom
组件。为了不引起报错,把主程序写的全都注释掉;我们调用一下conrainsBean()
方法,我们判断一下我们容器中是不是包含我们某个组件。//@Bean("tom") public Pet tomcatPet(){ return new Pet("tomcat01"); }
现在它就是一个常规方法。它并不能给容器中注册组件,看一下容器中是不是有tom组件。
主程序中测试:
boolean tom = run.containsBean("tom"); System.out.println("容器中是否有tom组件:" + tom);
得到结果:
容器中是否有tom组件:false
那有没有user01呢?(user01方法上有@Bean注解)
boolean user01 = run.containsBean("user01"); System.out.println("容器中是否有user01组件:" + user01);
得到结果:
容器中是否有user01组件:true
但是我最终想要的效果是:我们这个
user01
用户依赖这个宠物tomcatPet
,如果容器中没有这个宠物,你也别给我从容器中注册这个用户了。所以我们可以用到条件注解@ConditionalOnBean
,OnBean
就是说在容器中有某个组件,有哪个组件呢?我们可以在()
指定ConditionalOnBean.java
package org.springframework.boot.autoconfigure.condition; import java.lang.annotation.Annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.beans.factory.BeanFactory; import org.springframework.context.annotation.Conditional; @Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Documented @Conditional(OnBeanCondition.class) public @interface ConditionalOnBean { Class<?>[] value() default {}; String[] type() default {}; Class<? extends Annotation>[] annotation() default {}; String[] name() default {}; SearchStrategy search() default SearchStrategy.ALL; Class<?>[] parameterizedContainer() default {}; }
在这个Bean里面呢,我们可以使用
Class<?>[] value() default {};
指定我们这个组件的类型,当容器里面有这个组件的时候;
String[] name() default {};
:还有我们组件的名字@ConditionalOnBean(name = "name")
当我们这个容器中有这个名字的组件,哪个名字呢?
@ConditionalOnBean(name = "tom")
有tom组件的时候 , 我呢在给容器中注入
user01
组件结果为:
容器中是否有tom组件:false 容器中是否有user01组件:false
@ConditionalOnBean(name = "tom")
甚至可以标注在类上,标注在类上也就是说当容器中有tom组件的时候,下面方法才生效,否则下面方法都不生效@ConditionalOnMissingBean
@ConditionalOnMissingBean(name = "tom") public class MyConfig { /** * 外部无论对配置类中的这个组件注册方法调用多少次,获取的都是之前注册容器中的单实例对象 * @return */ @Bean //我们不用<Bean>标签,我们用@Bean注解 public User user01(){ User lisi = new User(18,"lisi"); lisi.setPet(tomcatPet()); return lisi; } //@Bean("tom") @Bean("tom22") public Pet tomcatPet(){ return new Pet("tomcat01"); } }
则结果为:
容器中是否有tom组件:false 容器中是否有user01组件:true 容器中是否有tom22组件:true
当我们没有tom(
@ConditionalOnMissingBean(name = "tom")
)user01
和tom22
就有了
所以我们这些条件注解如果加在方法上,当我们这个条件成立以后,我们这个方法返回的组件才会被注册在容器中,否则就不注册;如果加在类上,当我们这个条件成立以后,我们类下面的配置才能生效,否则呢就不生效。这是我们说的条件装配。大家未来在springboot
底层里面会遇到非常多的条件装配。这是以ConditionalOnBean为例。
在SpringBoot底层经常会有这些判断:比如我们导入了某些场景,当我们这些场景里面什么东西配了以后我才帮你配什么(比如ConditionalOnBean
),什么东西没配我就不帮你配了;或者是你缺少什么了(比如@ConditionalOnMissingBean
),我帮你配什么