@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.
 *
 * 

Provides functionality equivalent to the {@code } 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}). * *

{@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. * *

May be declared at the class level or as a meta-annotation. * *

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.
 *
 * 

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}: *

    *
  • {@link org.springframework.context.EnvironmentAware EnvironmentAware}
  • *
  • {@link org.springframework.beans.factory.BeanFactoryAware BeanFactoryAware}
  • *
  • {@link org.springframework.beans.factory.BeanClassLoaderAware BeanClassLoaderAware}
  • *
  • {@link org.springframework.context.ResourceLoaderAware ResourceLoaderAware}
  • *
* *

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.
 *
 * 

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}). * *

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}: *

    *
  • {@link org.springframework.context.EnvironmentAware EnvironmentAware}
  • *
  • {@link org.springframework.beans.factory.BeanFactoryAware BeanFactoryAware} *
  • {@link org.springframework.beans.factory.BeanClassLoaderAware BeanClassLoaderAware} *
  • {@link org.springframework.context.ResourceLoaderAware ResourceLoaderAware} *
* *

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. *

Note that {@link BeanDefinitionRegistryPostProcessor} types may not 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 getAnnotationTypes();

    Set getMetaAnnotationTypes(String var1);

    boolean hasAnnotation(String var1);

    boolean hasMetaAnnotation(String var1);

    boolean hasAnnotatedMethods(String var1);

    Set getAnnotatedMethods(String var1);
}

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

你可能感兴趣的:(spring源码,玩转spring,cloud)