@Import注入之ImportSelector和ImportBeanDefinitionRegistrar

在spring-boot中随处可以见的就是@Import, 它的作用就是通过导入的方式把实例注入到IOC中,本文主要介绍下@Import的用法。

知识点回顾:

给IOC容器中注册Bean的方式:

  1. 包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)
  2. @Bean
  3. @Import

@Import源码可以发现@Import注解只能注解在类

/**
 * Indicates one or more {@link Configuration @Configuration} classes to import.
 *
 * <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}).
 *
 * <p>{@code @Bean} definitions declared in imported {@code @Configuration} classes should be
 * accessed by using {@link org.springframework.beans.factory.annotation.Autowired @Autowired}
 * injection. Either the bean itself can be autowired, or the configuration class instance
 * declaring the bean can be autowired. The latter approach allows for explicit, IDE-friendly
 * navigation between {@code @Configuration} class methods.
 *
 * <p>May be declared at the class level or as a meta-annotation.
 *
 * <p>If XML or other non-{@code @Configuration} bean definition resources need to be
 * imported, use the {@link ImportResource @ImportResource} annotation instead.
 *
 * @author Chris Beams
 * @author Juergen Hoeller
 * @since 3.0
 * @see Configuration
 * @see ImportSelector
 * @see ImportResource
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
    Class<?>[] value();
}

从上面的英文注释可得知,参数value上可以配置3种类型的值:

普通的class

普通的class,容器中就会自动注册这个组件,id默认是全类名

public class Blue {}
public class Red {}
@Configuration
@Import({ Blue.class, Red.class })
public class ColorConfig {
}

ImportSelector

它需要返回需要导入的组件的全类名数组,它可以实现一些Aware接口:

  • EnvironmentAware
  • BeanFactoryAware
  • BeanClassLoaderAware
  • ResourceLoaderAware
/**
 * Interface to be implemented by types that determine which @{@link Configuration}
 * class(es) should be imported based on a given selection criteria, usually one or more
 * annotation attributes.
 *
 * <p>An {@link ImportSelector} may implement any of the following
 * {@link org.springframework.beans.factory.Aware Aware} interfaces, and their respective
 * methods will be called prior to {@link #selectImports}:
 * <ul>
 * <li>{@link org.springframework.context.EnvironmentAware EnvironmentAware}</li>
 * <li>{@link org.springframework.beans.factory.BeanFactoryAware BeanFactoryAware}</li>
 * <li>{@link org.springframework.beans.factory.BeanClassLoaderAware BeanClassLoaderAware}</li>
 * <li>{@link org.springframework.context.ResourceLoaderAware ResourceLoaderAware}</li>
 * </ul>
 *
 * <p>ImportSelectors are usually processed in the same way as regular {@code @Import}
 * annotations, however, it is also possible to defer selection of imports until all
 * {@code @Configuration} classes have been processed (see {@link DeferredImportSelector}
 * for details).
 *
 * @author Chris Beams
 * @since 3.1
 * @see DeferredImportSelector
 * @see Import
 * @see ImportBeanDefinitionRegistrar
 * @see Configuration
 */
public interface ImportSelector {

	/**
	 * Select and return the names of which class(es) should be imported based on
	 * the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
	 */
	String[] selectImports(AnnotationMetadata importingClassMetadata);
}

下面演示下它的用法:

public class MyImportSelector implements ImportSelector {
	@Override
	public String[] selectImports(AnnotationMetadata importingClassMetadata) {
		// 方法不要返回null值,就是到导入到容器中的组件全类名
		//return new String[]{"com.github.bean.Blue"};
		return new String[] { Blue.class.getName(), Yellow.class.getName() };
	}
}
@Configuration
@Import({ MyImportSelector.class })
public class ColorConfig {
}

ImportBeanDefinitionRegistrar

它提供了手动注册bean到容器中,它可以实现一些Aware接口:

  • EnvironmentAware
  • BeanFactoryAware
  • BeanClassLoaderAware
  • ResourceLoaderAware
/**
 * Interface to be implemented by types that register additional bean definitions when
 * processing @{@link Configuration} classes. Useful when operating at the bean definition
 * level (as opposed to {@code @Bean} method/instance level) is desired or necessary.
 *
 * <p>Along with {@code @Configuration} and {@link ImportSelector}, classes of this type
 * may be provided to the @{@link Import} annotation (or may also be returned from an
 * {@code ImportSelector}).
 *
 * <p>An {@link ImportBeanDefinitionRegistrar} may implement any of the following
 * {@link org.springframework.beans.factory.Aware Aware} interfaces, and their respective
 * methods will be called prior to {@link #registerBeanDefinitions}:
 * <ul>
 * <li>{@link org.springframework.context.EnvironmentAware EnvironmentAware}</li>
 * <li>{@link org.springframework.beans.factory.BeanFactoryAware BeanFactoryAware}
 * <li>{@link org.springframework.beans.factory.BeanClassLoaderAware BeanClassLoaderAware}
 * <li>{@link org.springframework.context.ResourceLoaderAware ResourceLoaderAware}
 * </ul>
 *
 * <p>See implementations and associated unit tests for usage examples.
 *
 * @author Chris Beams
 * @since 3.1
 * @see Import
 * @see ImportSelector
 * @see Configuration
 */
public interface ImportBeanDefinitionRegistrar {
	/**
	 * Register bean definitions as necessary based on the given annotation metadata of
	 * the importing {@code @Configuration} class.
	 * <p>Note that {@link BeanDefinitionRegistryPostProcessor} types may <em>not</em> be
	 * registered here, due to lifecycle constraints related to {@code @Configuration}
	 * class processing.
	 * @param importingClassMetadata annotation metadata of the importing class
	 * @param registry current bean definition registry
	 */
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
}

下面演示下它的用法:

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
	/**
	 * AnnotationMetadata:当前类的注解信息
	 * BeanDefinitionRegistry:BeanDefinition注册类;
	 */
	@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定义信息
			RootBeanDefinition beanDefinition = new RootBeanDefinition(Yellow.class);
			// 注册一个Bean,指定bean名
			registry.registerBeanDefinition(Yellow.class.getName(), beanDefinition);
		}
	}
}
@Configuration
@Import({ MyImportSelector.class, MyImportBeanDefinitionRegistrar.class })
public class ColorConfig {
}

这里重点下:

AnnotationMetadata,它可以获取当前类(被@Import标记)的注解信息,它使用标准的反射来获取制定类的内部注解信息。

public interface AnnotationMetadata extends ClassMetadata, AnnotatedTypeMetadata {
    Set<String> getAnnotationTypes();

    Set<String> getMetaAnnotationTypes(String var1);

    boolean hasAnnotation(String var1);

    boolean hasMetaAnnotation(String var1);

    boolean hasAnnotatedMethods(String var1);

    Set<MethodMetadata> getAnnotatedMethods(String var1);
}

AnnotationConfigApplicationContext,@Import内部制定的类作为regular component,而AnnotationConfigApplicationContext才能识别。

回答: @import: url()和@import: ''都是CSS中的@import规则的不同写法。@import: url()是通过引入外部CSS文件,使用url()指定文件路径来导入样式表。而@import: ''是通过引入局部文件,使用''来指定文件名来导入样式表。\[1\]\[3\]这两种写法在功能上是相同的,都可以用来导入外部样式表,但是在使用上有一些细微的差别。例如,@import: url()可以在加载页面前就加载完整个CSS文件,而@import: ''则是在读取完文件后再加载,可能会导致页面一开始没有样式,然后闪烁一下后才出现样式。\[2\]此外,@import: url()是CSS2中的规则,而@import: ''则是Sass中的规则。\[2\]\[3\]在使用JavaScript控制DOM去改变样式时,只能使用link标签,因为@import不是DOM可以控制的。\[2\]总的来说,@import: url()和@import: ''都是用来导入外部样式表的方法,具体使用哪种写法取决于个人的需求和使用环境。 #### 引用[.reference_title] - *1* *2* [关于css @import url(); 和如何导入样式](https://blog.csdn.net/qq_47443027/article/details/114697066)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Scss--@import--使用/实例](https://blog.csdn.net/feiying0canglang/article/details/125788169)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值