在spring-boot中随处可以见的就是@Import, 它的作用就是通过导入的方式把实例注入到IOC中,本文主要介绍下@Import的用法。
知识点回顾:
给IOC容器中注册Bean的方式:
- 包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)
- @Bean
- @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才能识别。