@Conditional
@Conditional是Spring4新提供的注解,它的作用是按照一定的條件進行判斷,滿足條件給容器注冊bean。
創建ConfigConditional類和測試類ConfigConditionalTest
@Configuration
public class ConfigConditional {
@Bean(name = "xiaoming")
public Student getStudent1(){
Student student = new Student();
student.setName("xiaoming");
student.setAge(18);
return student;
}
@Bean(name = "xiaohong")
public Student getStudent2(){
Student student = new Student();
student.setName("xiaohong");
student.setAge(17);
return student;
}
}
測試類ConfigConditionalTest
輸出結果為{xiaoming=Student(age=18, name=xiaoming), xiaohong=Student(age=17, name=xiaohong)},說明兩個Student實例被注入進容器。
public class ConfigConditionalTest {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ConfigConditional.class);
@Test
public void test1() {
Map<String, Student> map = applicationContext.getBeansOfType(Student.class);
System.out.println(map);
}
}
//輸出為{xiaoming=Student(age=18, name=xiaoming), xiaohong=Student(age=17, name=xiaohong)}
如果我想根據當前操作系統來注入Student實例,只有在非windows操作系統的情況下注入xiaoming。
這就需要我們用到@Conditional注解了。
@Conditional作用
Class<? extends Condition>[] value()說明@Conditional注解傳入的是一個Class數組,存在多種條件類的情況。@Target({ElementType.TYPE, ElementType.METHOD})說明@Conditional可以作用在方法和類上,一個方法只能注入一個bean實例,所以@Conditional標注在方法上只能控制一個bean實例是否注入。標注在類上:一個類中可以注入很多實例,@Conditional標注在類上就決定了一批bean是否注入。
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
/**
* All {@link Condition} classes that must {@linkplain Condition#matches match}
* in order for the component to be registered.
*/
Class<? extends Condition>[] value();
}
@Conditional舉例
創建WindowsConfig,非windows系統,返回true。
public class WindowsConfig implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//獲取ioc使用的beanFactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//獲取類加載器
ClassLoader classLoader = context.getClassLoader();
//獲取當前環境信息
Environment environment = context.getEnvironment();
//獲取bean定義的注冊類
BeanDefinitionRegistry registry = context.getRegistry();
//獲得當前系統名
String property = environment.getProperty("os.name");
//不包含Windows則說明不是windows系統,返回true
if (!property.contains("Windows")) {
return true;
}
return false;
}
}
@Conditional作用在方法上
@Configuration
public class ConfigConditional {
@Bean(name = "xiaoming")
@Conditional(WindowsConfig.class)
public Student getStudent1(){
Student student = new Student();
student.setName("xiaoming");
student.setAge(18);
return student;
}
@Bean(name = "xiaohong")
public Student getStudent2(){
Student student = new Student();
student.setName("xiaohong");
student.setAge(17);
return student;
}
}
因為只在非windows系統注入xiaoming,因此輸出為{xiaohong=Student(age=17, name=xiaohong)}。
@Conditional作用在類上
@Configuration
@Conditional(WindowsConfig.class)
public class ConfigConditional {
@Bean(name = "xiaoming")
public Student getStudent1(){
Student student = new Student();
student.setName("xiaoming");
student.setAge(18);
return student;
}
@Bean(name = "xiaohong")
public Student getStudent2(){
Student student = new Student();
student.setName("xiaohong");
student.setAge(17);
return student;
}
}
因為只在非windows系統注入xiaoming和xiaohong,因此輸出為{}
@import
@Import注解用來幫助我們把一些需要定義為Bean的類導入到IOC容器里面。如果配置類在標准的springboot的包結構下,就是SpringbootApplication啟動類在包的根目錄下,配置類在子包下。就不需要使用@Import導入配置類,如果配置類在第三方的jar下,我們想要引入這個配置類,就需要@Import對其引入到工程中才能生效。因為這個時候配置類不再springboot默認的掃描范圍內。
@Import源碼注釋里可以知道,value里面傳遞的Class會被Spring識別成為component組件。
@Import源碼注釋里面的一段說明,指出了@Import的用法:
- 導入一個@Configuration類
- 導入ImportSelector,ImportBeanDefinitionRegistrar的實現類
- 導入一個普通的類
/*
*<p>Provides functionality equivalent to the {@code <import/>} element in Spring XML.
* Allows for importing {@code @Configuration} classes, {@link ImportSelector} and
* {@link ImportBeanDefinitionRegistrar} implementations, as well as regular component
* classes (as of 4.2; analogous to {@link AnnotationConfigApplicationContext#register}).
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
/**
* {@link Configuration @Configuration}, {@link ImportSelector},
* {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.
*/
Class<?>[] value();
}
@Import引入普通類
@Import引入普通的類可以幫助我們把普通的類定義為Bean。@Import可以添加在@SpringBootApplication(啟動類)、@Configuration(配置類)、@Component(組件類)對應的類上。
定義Teacher類
@Data
public class Teacher {
private int age;
private String name;
}
在springboot的啟動類@Import Teacher類,這個類就可以被其他類當做bean來引用。
輸出結果Teacher(age=0, name=null)
@SpringBootApplication
@Import({Teacher.class})
public class SpringbootReviewApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(SpringbootReviewApplication.class, args);
Teacher teacher = run.getBean(Teacher.class);
System.out.println(teacher);
}
}
//輸出結果Teacher(age=0, name=null)
@Import引入配置類(@Configuration修飾的類)
@Import除了可以把普通的類定義為Bean,@Import還可以引入一個@Configuration修飾的類(引入配置類),從而把讓配置類生效(配置類下的所有Bean添加到IOC容器里面去)如果配置類在標准的SpringBoot包結構下(SpringBootApplication啟動類包的根目錄下)。是不需要@Import導入配置類的,SpringBoot自動幫做了。上面的情況一般用於@Configuration配置類不在標准的SpringBoot包結構下面。所以一般在自定義starter的時候用到。
public class ImportDemo {
public void doSomething () {
System.out.println("ImportDemo.doSomething()");
}
}
@Configuration
@Import({ImportDemo.class})
public class ImportConfig{
@Bean
public Student returnOneStudent(){
return new Student();
}
}
@RestController
public class ImportDemoController {
@Autowired
private Student student;
@Autowired
private ImportDemo importDemo;
@RequestMapping("/importDemo")
public String demo() throws Exception {
importDemo.doSomething();
return "ImportDemo" + student.toString;
}
}