SpringBoot底层大量使用的注解,表示按照一定的条件进行判断,若满足条件则给容器中注册bean
@Conditional可以标注在类上 也可以标注在方法上
@Test
void conditionTest(){
//配置类测试
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
System.out.println("容器创建完毕");
System.out.println("准备获取bean...");
Map<String, Person> beansOfType = applicationContext.getBeansOfType(Person.class);
for (String person:beansOfType.keySet()){
System.out.println(beansOfType.get(person));
}
}
MainConfig2.java
@Configuration
public class MainConfig2 {
// 由于容器中已经有了一个名为"person"的bean, 所以如果再注入"person"的时候会报错 需要修改下注入的bean的名称
// @Scope("prototype")
@Bean("person2")
public Person person(){
System.out.println("person2创建中...");
return new Person("qd2",22);
}
@Bean("bill")
public Person person1(){
System.out.println("bill创建中...");
return new Person("bill",62);
}
@Bean("linus")
public Person person2(){
System.out.println("linus创建中...");
return new Person("linus",48);
}
}
加上条件判断
LinuxCondition.java
package com.example.annotations.condition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 获取IOC使用的beanFactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 获取类加载器
ClassLoader classLoader = context.getClassLoader();
// 获取bean定义的注册类
BeanDefinitionRegistry registry = context.getRegistry();
// 获取当前环境信息
Environment environment = context.getEnvironment();
// 动态获取环境变量的值
String property = environment.getProperty("os.name");
if (property.contains("Linux")){
System.out.println("the running environment is 'Linux'");
return true;
}
return false;
}
}
注意
- 实现
Condition
接口的时候注意导的包- 需要实现的方法:
matches
参数解释:
- ConditionContext:判断条件能使用的上下文环境
- AnnotationTypeMetadata:注释信息
BeanDefinitionRegistry registry = context.getRegistry();
所有bean定义都在这个类,也可以用其来注册/移除/查询/一个bean定义
WindowsCondition.class
package com.example.annotations.condition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 获取运行时环境
Environment environment = context.getEnvironment();
// 动态获取环境变量的值
String property = environment.getProperty("os.name");
// 匹配环境
if (property.contains("Windows")){
System.out.println("the running environment is 'Windows'");
return true;
}
return false;
}
}
@Configuration
public class MainConfig2 {
// 由于容器中已经有了一个名为"person"的bean, 所以如果再注入"person"的时候会报错 需要修改下注入的bean的名称
@Bean("person2")
public Person person(){
System.out.println("person2创建中...");
return new Person("qd2",22);
}
@Conditional(WindowsCondition.class)
@Bean("bill")
public Person person1(){
System.out.println("bill创建中...");
return new Person("bill",62);
}
@Conditional(LinuxCondition.class)
@Bean("linus")
public Person person2(){
System.out.println("linus创建中...");
return new Person("linus",48);
}
}
运行结果;
组建注册 @Import 给容器快速导入一个组件
给容器注册组件:
- 包扫描 + 组件标注注解(@Controller @Service @Repository @Component),局限于自己写的
- @Bean(可导入第三方包里的组件)
- @Import(快速给容器中导入组件)
- @Import([要导入容器中的组件]):容器中就会自动注册这个组件,id默认为全类名
@Import(Color.class)
@Import({Color.class,Red.class})
- 实现ImportSelector接口:返回需要导入的组件的全类名数组
- 实现ImportBeanDefinitionRegistrar接口:手动注册bean到容器中
- 使用Spring提供的FactoryBean工厂
配置类 MainConfig3.class
测试
@Test
void importTest(){
//配置类测试
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig3.class);
System.out.println("容器创建完毕");
System.out.println("准备获取bean...");
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String name:beanDefinitionNames){
System.out.println(name);
}
}
ImportSelector 测试
Color.java
package com.example.annotations.bean;
public class Color {
}
Red.java
package com.example.annotations.bean;
public class Red {
}
MyImportSelector.java
package com.example.annotations.importselector;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
/**
* 自定义逻辑返回需要导入的组件
*/
public class MyImportSelector implements ImportSelector {
// 返回值:导入到容器中的组件 (全类名)
// AnnotationMetadata:当前标注@Import注解的类的所有注解信息
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// 不能返回 null 可以是空数组
return new String[]{"com.example.annotations.bean.Color","com.example.annotations.bean.Red"};
}
}
运行结果:
实现ImportBeanDefinitionRegistrar接口
MyImportBeanDefinitionRegistrar.class
package com.example.annotations.importselector;
import com.example.annotations.bean.RainBow;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
*
* @param importingClassMetadata 当前类的注解信息
* @param registry BeanDefinition的注册类 负责将bean添加进容器
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 指定bean定义信息(Bean的类型 Bean的作用域 ...)
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(RainBow.class);
// 注册:指定bean名
if (!registry.containsBeanDefinition("rainbow")){
System.out.println(" start create 'rainbow' ...");
registry.registerBeanDefinition("rainbow",rootBeanDefinition);
}else {
System.out.println("'rainbow' already exists ");
}
}
}
运行结果
使用FatoryBean
普通bean
将bean导入到容器后,容器会调用其无参构造器,默认创建一个对象注册在容器中
FactoryBean
- 是一个接口
- 整合第三方框架的时候用的多
- 默认获取的是工厂bean调用getObject创建的对象
- 要获取工厂bean本身,需要给id前加一个
&
需要实现方法
getObject()
getObjectType()
isSingleton() :默认是true 单实例
实例测试
ColorFactoryBean.java
package com.example.annotations.bean;
import org.springframework.beans.factory.FactoryBean;
/**
* 创建一个Spring定义的FactoryBean
*/
public class ColorFactoryBean implements FactoryBean<Color> {
/**
* 返回分Color对象会被添加到容器中
* @return Color
* @throws Exception
*/
@Override
public Color getObject() throws Exception {
return new Color();
}
/**
*
* @return
*/
@Override
public Class<?> getObjectType() {
return Color.class;
}
/**
* true: 单实例 在容器中保存一份
* false:多实例 每获取一次就会创建一个新bean
* @return
*/
@Override
public boolean isSingleton() {
return true;
}
}
MainConfig2.java
@Configuration
public class MainConfig2 {
@Bean
public ColorFactoryBean colorFactoryBean(){
return new ColorFactoryBean();
}
}
测试
@Test
void factoryBeanTest(){
//配置类测试
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
System.out.println("容器创建完毕");
System.out.println("准备获取bean...");
Object bean1 = applicationContext.getBean("colorFactoryBean");//Color.class
Object bean2 = applicationContext.getBean("colorFactoryBean");//Color.class
System.out.println("bean1 == bean2? => " + (bean1 == bean2));
}
测试结果
现将ColorFactoryBean.java中的isSingleton改为false,再次运行
查看获取的类型
@Test
void factoryBeanTest(){
//配置类测试
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
System.out.println("容器创建完毕");
System.out.println("准备获取bean...");
Object bean1 = applicationContext.getBean("colorFactoryBean");//Color.class 获取的是工厂bean调用
Object bean2 = applicationContext.getBean("&colorFactoryBean");//ColorFactoryBean.class
System.out.println("bean1 == bean2? => " + (bean1 == bean2));
System.out.println("bean1 " + bean1.getClass());
System.out.println("bean2 " + bean2.getClass());
}