Spring 注解驱动开发_组件注册-@Import 注解

一、@Import 注解介绍

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {

	/**
	 * value 值可以是 @Configuration注解类,或者 ImportSelector 以及 ImportBeanDifinitionRegistrar 的实现类,或者一些常规的组件类
	 */
	Class<?>[] value();

}
  • @Import 注解可用于导入一个或多个组件类(一般是 @Configuration 类)。
  • @Import 注解提供了与 Spring XML 中的 <limport> 元素等效的功能。允许导入@Configuration 类、ImportSelector 和 ImportBeanDefinitionRegistrar 实现类,以及常规组件类。

二、使用 Import 给容器中快速导入一个组件

创建实体类 Color

package org.example.pojo;

public class Color {
}

创建实体类 Red

package org.example.pojo;

public class Red {
}

创建配置类 ImportTestConfig,使用 @Import 注解向容器中注入 Color 以及 Red 组件

package org.example.config;

import org.example.pojo.Color;
import org.example.pojo.Red;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Import({Color.class, Red.class})
@Configuration
public class ImportTestConfig {
}

测试方法:

@Test
public void testImport(){
    ApplicationContext ac = new AnnotationConfigApplicationContext(ImportTestConfig.class);
    String[] beanDefinitionNames = ac.getBeanDefinitionNames();
    for (String beanDefinitionName : beanDefinitionNames) {
        System.out.println(beanDefinitionName);
    }
}

测试结果:
在这里插入图片描述
通过 @Import 注解成功的将 Color 以及 Red 两个实体类注入到了容器中,其在容器中的 id 默认是实体类的全类名

三、使用 ImportSelector 导入一组组件

3.1 接口定义

ImportSelector 是一个接口,先来看一下这个接口的定义:

public interface ImportSelector {

	/**
	 * 根据导入的 @Configuration 类的 AnnotationMetadata 选择并返回应导入的类的名称。
	 * @return 返回需要导入的类名,如果没有则返回一个空数组
	 */
	String[] selectImports(AnnotationMetadata importingClassMetadata);

	/**
	 * 用于排除某些不需要导入容器的候选类
	 */
	@Nullable
	default Predicate<String> getExclusionFilter() {
		return null;
	}

}

AnnotationMetadata 接口可以用来获取当前标注 @Import 注解的类的所有注解信息。

package org.springframework.core.type;

import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.stream.Collectors;

import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;

public interface AnnotationMetadata extends ClassMetadata, AnnotatedTypeMetadata {

	/**
	 * 获取基础类上存在的所有注释类型的完全限定类名。
	 */
	default Set<String> getAnnotationTypes() {
		return getAnnotations().stream()
				.filter(MergedAnnotation::isDirectlyPresent)
				.map(annotation -> annotation.getType().getName())
				.collect(Collectors.toCollection(LinkedHashSet::new));
	}

	/**
	 * 根据给定的注解名获取类上所有的元注解类型
	 */
	default Set<String> getMetaAnnotationTypes(String annotationName) {
		MergedAnnotation<?> annotation = getAnnotations().get(annotationName, MergedAnnotation::isDirectlyPresent);
		if (!annotation.isPresent()) {
			return Collections.emptySet();
		}
		return MergedAnnotations.from(annotation.getType(), SearchStrategy.INHERITED_ANNOTATIONS).stream()
				.map(mergedAnnotation -> mergedAnnotation.getType().getName())
				.collect(Collectors.toCollection(LinkedHashSet::new));
	}

	/**
	 * 确定基础类是否使用了给定类型的注解
	 */
	default boolean hasAnnotation(String annotationName) {
		return getAnnotations().isDirectlyPresent(annotationName);
	}

	/**
	 * 确定基础类是否有一个注释,该注释本身使用给定类型的元注释进行注释。
	 */
	default boolean hasMetaAnnotation(String metaAnnotationName) {
		return getAnnotations().get(metaAnnotationName,
				MergedAnnotation::isMetaPresent).isPresent();
	}

	/**
	 * 确定基础类是否具有使用给定注释类型注释(或元注释)的方法。
	 */
	default boolean hasAnnotatedMethods(String annotationName) {
		return !getAnnotatedMethods(annotationName).isEmpty();
	}

	/**
	 * 获取所有使用给定注释类型注释(或元注释)的所有方法的方法元数据。
	 */
	Set<MethodMetadata> getAnnotatedMethods(String annotationName);


	/**
	 * 使用标准反射为给定类创建新 AnnotationMetadata 实例的工厂方法
	 */
	static AnnotationMetadata introspect(Class<?> type) {
		return StandardAnnotationMetadata.from(type);
	}

}

3.2、案例

创建实体类 Yellow 以及 Blue

Yellow

package org.example.pojo;

public class Yellow {
}

Blue

package org.example.pojo;

public class Blue {
}

通过 @ImportSelector 注解的方式将 Yellow 和 Blue 这两个实体类注入到容器中

实现 ImportSelector 接口

package org.example.condition;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

import java.util.Set;


public class MyImportSelector implements ImportSelector {
    /**
     * AnnotationMetadata:用于获取当前标注 @Import 注解的类的所有注解信息
     * */
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"org.example.pojo.Blue","org.example.pojo.Yellow"};
    }
}

在配置类 @Import 注解上,新增 MyImportSelector.class

package org.example.config;

import org.example.condition.MyImportSelector;
import org.example.pojo.Color;
import org.example.pojo.Red;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Import({Color.class, Red.class, MyImportSelector.class})
@Configuration
public class ImportTestConfig {
}

测试方法:

@Test
public void testImport(){
    ApplicationContext ac = new AnnotationConfigApplicationContext(ImportTestConfig.class);
    String[] beanDefinitionNames = ac.getBeanDefinitionNames();
    for (String beanDefinitionName : beanDefinitionNames) {
        System.out.println(beanDefinitionName);
    }
}

测试结果:
在这里插入图片描述
根据测试结果可以看出,Blue 和 Yellow 两个实体类已经注册成功。

四、使用 ImportBeanDefinitionRegistrar 导入

4.1 ImportBeanDefinitionRegistrar 接口定义:

public interface ImportBeanDefinitionRegistrar {

	default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
			BeanNameGenerator importBeanNameGenerator) {

		registerBeanDefinitions(importingClassMetadata, registry);
	}

	/**
	 * 用于注册 beanDifinition
	 * AnnotationMetadata:当前类的注解信息
     * BeanDefinitionRegistry:BeanDifinition注册类
	 */
	default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
	}

}

4.2 案例

实体类 Rainbow

package org.example.pojo;

public class Rainbow {
}

MyImportBeanDefinitionRegistrar 类:

package org.example.condition;

import org.example.pojo.Rainbow;
import org.springframework.beans.factory.config.BeanDefinition;
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 {
    /**
     * AnnotationMetadata:当前类的注解信息
     * BeanDefinitionRegistry:BeanDifinition注册类
     *
     * 把所有需要添加到容器中的 bean,通过调用
     * BeanDefinitionRegistry.registerBeanDifinition 手工注册进来
     * @param importingClassMetadata
     * @param registry
     */

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        boolean definition = registry.containsBeanDefinition("org.example.pojo.Red");
        boolean definition2 = registry.containsBeanDefinition("org.example.pojo.Blue");

        if(definition && definition2){
            RootBeanDefinition beanDefinition = new RootBeanDefinition(Rainbow.class);
            registry.registerBeanDefinition("rainbow", beanDefinition);
        }
    }
}

在配置类的 @Import 注解上新增定义的 MyImportBeanDefinitionRegistrar 类

package org.example.config;

import org.example.condition.MyImportBeanDefinitionRegistrar;
import org.example.condition.MyImportSelector;
import org.example.pojo.Color;
import org.example.pojo.Red;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Import({Color.class, Red.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
@Configuration
public class ImportTestConfig {
}

测试方法:

@Test
public void testImport(){
    ApplicationContext ac = new AnnotationConfigApplicationContext(ImportTestConfig.class);
    String[] beanDefinitionNames = ac.getBeanDefinitionNames();
    for (String beanDefinitionName : beanDefinitionNames) {
        System.out.println(beanDefinitionName);
    }
}

测试结果:
在这里插入图片描述

总结

@Import 注解向容器中注入 bean 的方式有三种,一是直接导入普通类或者配置类,二是通过导入实现了 ImportSelector 接口的类来实现批量导入 bean 实例,三是通过导入实现了 ImportBeanDefinitionRegistrar 接口来实现导入 bean 实例。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值