spring根据条件注入Bean

一、常用的注入spring Bean的几种方式:

1.常用的@controller、@Service、@Repository、@Configuration、@Component等注解,默认都会注入单例的Bean,如果这些类在启动类的同级包或同级包下面则会被自动注入,若不在,则需要加上@ComponentScan或者@ComponentScans将包名加入扫描才起作用

2.@Bean,也比较常用,一般通过构造方式返回一个类实例,然后会被spring加入IOC

3.@Import注解,可以直接将需要注入的class填入即可注入,一般用于自定义注解时使用

4.实现ImportSelector接口中selectImports方法,该方法返回一个String数组,String就是你需要实例化的类的包+类名,此方法也可用于读取自定义注解的值:

public class AliasRegister implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        Map<String, Object> map = importingClassMetadata.getAnnotationAttributes(EnableKitIo.class.getName());
        if (map == null || map.isEmpty()) {
            throw new EnerkitIoException("No attrs for enerkit-io");
        }
        String[] alias = (String[]) map.get("alias");
        String defaultAlias = (String)map.get("defaultAlias");
        if (defaultAlias.trim().length() == 0){
            defaultAlias = alias[0];
        }
        IoClientInitializer.setDefaultAlias(defaultAlias);
        Set<String> clientAlias = new HashSet<>();
        clientAlias.addAll(Arrays.asList(alias));
        IoClientInitializer.setClientAlias(clientAlias);
        return new String[0];
    }
}

5.实现ImportBeanDefinitionRegistrar接口中registerBeanDefinitions方法


public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
	/**
	 * AnnotationMetadata:当前类的注解信息
	 * BeanDefinitionRegistry:BeanDefinition注册类;
	 * 		把所有需要添加到容器中的bean;调用
	 * 		BeanDefinitionRegistry.registerBeanDefinition手工注册进来
	 */
	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
 
		boolean definition = registry.containsBeanDefinition(Red.class.getName());
		boolean definition2 = registry.containsBeanDefinition(Blue.class.getName());
		if (definition && definition2) {
			// 指定Bean定义信息;(Bean的类型,Bean。。。)
			RootBeanDefinition beanDefinition = new RootBeanDefinition(Yellow.class);
			// 注册一个Bean,指定bean名
			registry.registerBeanDefinition(Yellow.class.getName(), beanDefinition);
		}
	}
}

6.通过实现FactoryBean中的方法注入:

//1. 这里的接口泛型参数为要注入Bean的类型
public class MyFactoryBean implements FactoryBean<Department> {
    //2.重写的第一个方法返回Bean的实例
    @Override
    public Department getObject() throws Exception {
        return new Department();
    }

    //3.重写的第二个方法返回Bean的类型
    @Override
    public Class<?> getObjectType() {
        return Department.class;
    }

    //4.重写的第三个方法返回一个boolean值,决定该Bean的类型是单例还是多实例。这里返回true,为单例。
    @Override
    public boolean isSingleton() {
        return true;
    }
}

二、有时会有需求:根据不通条件判断是否注入该Bean

spring中提供了很多个条件注入的注解,全都是 @ConditionalOnxxx,这边例举几个:

@ConditionalOnBean(A.class) //需要注入了A的前提下才会注入B
@Bean
public B b(){
    return new B();
}


@ConditionalOnMissingBean(B.class) //当容器中不存在B时会注入B
@Bean
public B b(){
    return new B();
}

//当有spring.batch.job.names配置,且值为order-cancelorder才注入
@Configuration
@ConditionalOnProperty(name = "spring.batch.job.names",havingValue = "order-cancelorder")
public class CancelOrderConfig {...}

最近用了一个@ConditionalOnClass,遇到点问题,记录下,该注解可通过判断运行中的包中是否存在该类来动态注入Bean,

使用时必须加在单独一个类上,且类中只能有一个条件注入的Bean,否则就会报classNotFound,不知道是不是我使用错误的问题。

@ConditionalOnClass(MinioOSSClient.class)
public class OSSMinioConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public MinioOSSClient minioOSSClient(OSSProperties ossProperties){
        return new MinioOSSClient(ossProperties.getMinio().getEndpoint(),
                ossProperties.getMinio().getAccessKey(),
                ossProperties.getMinio().getSecretKey(),
                ossProperties.getMinio().getBucket());
    }
}

最后也可自己通过实现Condition接口来自定义注入的条件:

示例(参考自:https://blog.csdn.net/qq_27470131/article/details/79538046

@Configuration
public class ConditionConfig {
    @Conditional(WindowsCondition.class)
    @Bean("bill")
    public Person bill(){
        return new Person("bill",10);
    }

    @Conditional(LinuxCondition.class)
    @Bean("Linus")
    public Person person(){
        return new Person("Linus",10);
    }
}

public class WindowsCondition implements Condition {
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //获取当前运行环境信息
        Environment environment = context.getEnvironment();
        //获取当前环境名称
        String osName = environment.getProperty("os.name");
        return osName.contains("Windows");
    }
}

public class LinuxCondition implements Condition {
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //获取当前运行环境信息
        Environment environment = context.getEnvironment();
        //获取当前环境名称
        String osName = environment.getProperty("os.name");
        return osName.contains("Linux");
    }
}

 


版权声明:本文为u010737670原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。