spring注解:@ComponentScan,@Bean,@Import,@Component

来源:互联网 发布:域名name代表什么意思 编辑:程序博客网 时间:2024/05/08 11:03

我们知道我们要扫描某些包下的注解类,或者某些注解类,可以用@ComponentScan去扫描。我们需要类能被扫描到,可能会用到@Configuration,@Service,@Repository,这三个都使用了@Component注解。实际上扫描的是Component注解。我们也可以用@Bean来定义一个bean,也可以用Import来导入一个bean或者一个资源文件。

那么这些注解spring是如何扫描并且注册到spring容器的呢?

@Configuration@Import(ImportConfig.class)public class JavaConfig {}  @Test    public void test(){        ApplicationContext app = new AnnotationConfigApplicationContext(JavaConfig.class);        Student student = (Student) app.getBean("student");        student.say();    }

我们从AnnotationConfigApplicationContext出发

public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistrypublic class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry 

来看AnnotationConfigApplicationContext的构造函数

    public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) {        super(beanFactory);        this.reader = new AnnotatedBeanDefinitionReader(this);        this.scanner = new ClassPathBeanDefinitionScanner(this);    }public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {        this();        register(annotatedClasses);        refresh();}    public AnnotationConfigApplicationContext(String... basePackages) {        this();        scan(basePackages);        refresh();    }

进入this.reader = new AnnotatedBeanDefinitionReader(this);

    public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");        Assert.notNull(environment, "Environment must not be null");        this.registry = registry;        this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);        AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);    }
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(            BeanDefinitionRegistry registry, @Nullable Object source) {        DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);        if (beanFactory != null) {            if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {                beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);            }            if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {                beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());            }        }        Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(4);        if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {            RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);            def.setSource(source);            beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));        }        if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {            RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);            def.setSource(source);            beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));        }        if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {            RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);            def.setSource(source);            beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));        }        // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.        if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {            RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);            def.setSource(source);            beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));        }        // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.        if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {            RootBeanDefinition def = new RootBeanDefinition();            try {                def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,                        AnnotationConfigUtils.class.getClassLoader()));            }            catch (ClassNotFoundException ex) {                throw new IllegalStateException(                        "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);            }            def.setSource(source);            beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));        }        if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {            RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);            def.setSource(source);            beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));        }        if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {            RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);            def.setSource(source);            beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));        }        return beanDefs;    }
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {            RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);            def.setSource(source);            beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));        }

以上面的代码查看,ConfigurationClassPostProcessor被加入到了spring容器当中了。

同理AutowiredAnnotationBeanPostProcessor,RequiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor等都被加入了spring容器当中了。

而他们都实现了BeanPostProcessor,从前面两篇spring生命周期来看,在spring生命周期中会执行相应的方法。

spring生命周期

CommonAnnotationBeanPostProcessor讲过@PostConstruct会使用这个类来进行初始化方法。

重点讲解ConfigurationClassPostProcessor类,它会去读取@Component,@Bean,@Import等等。

public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,        PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAwarepublic interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor

ConfigurationClassPostProcessor他继承了BeanDefinitionRegistryPostProcessor

/** * Extension to the standard {@link BeanFactoryPostProcessor} SPI, allowing for * the registration of further bean definitions <i>before</i> regular * BeanFactoryPostProcessor detection kicks in. In particular, * BeanDefinitionRegistryPostProcessor may register further bean definitions * which in turn define BeanFactoryPostProcessor instances. * * @author Juergen Hoeller * @since 3.0.1 * @see org.springframework.context.annotation.ConfigurationClassPostProcessor */public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {

我们前面讲过实现BeanDefinitionRegistryPostProcessor,在spring生命周期中执行顺序为

  1. 构造函数
  2. BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry
  3. BeanFactoryPostProcessor.postProcessBeanFactory

ConfigurationClassPostProcessor的构造函数是默认的。

ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry

    @Override    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {        int registryId = System.identityHashCode(registry);        if (this.registriesPostProcessed.contains(registryId)) {            throw new IllegalStateException(                    "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);        }        if (this.factoriesPostProcessed.contains(registryId)) {            throw new IllegalStateException(                    "postProcessBeanFactory already called on this post-processor against " + registry);        }        this.registriesPostProcessed.add(registryId);        processConfigBeanDefinitions(registry);    }

processConfigBeanDefinitions主要看

//处理相关注册的类parser.parse(candidates);//注册这些类到spring容器当中this.reader.loadBeanDefinitions(configClasses);
public void parse(Set<BeanDefinitionHolder> configCandidates) {        this.deferredImportSelectors = new LinkedList<>();        for (BeanDefinitionHolder holder : configCandidates) {            BeanDefinition bd = holder.getBeanDefinition();            try {                if (bd instanceof AnnotatedBeanDefinition) {                    parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());                }                else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {                    parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());                }                else {                    parse(bd.getBeanClassName(), holder.getBeanName());                }            }            catch (BeanDefinitionStoreException ex) {                throw ex;            }            catch (Throwable ex) {                throw new BeanDefinitionStoreException(                        "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);            }        }        processDeferredImportSelectors();    }进入parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
    protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {        if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {            return;        }        ConfigurationClass existingClass = this.configurationClasses.get(configClass);        if (existingClass != null) {            if (configClass.isImported()) {                if (existingClass.isImported()) {                    existingClass.mergeImportedBy(configClass);                }                // Otherwise ignore new imported config class; existing non-imported class overrides it.                return;            }            else {                // Explicit bean definition found, probably replacing an import.                // Let's remove the old one and go with the new one.                this.configurationClasses.remove(configClass);                for (Iterator<ConfigurationClass> it = this.knownSuperclasses.values().iterator(); it.hasNext();) {                    if (configClass.equals(it.next())) {                        it.remove();                    }                }            }        }        // Recursively process the configuration class and its superclass hierarchy.        SourceClass sourceClass = asSourceClass(configClass);        do {            sourceClass = doProcessConfigurationClass(configClass, sourceClass);        }        while (sourceClass != null);        this.configurationClasses.put(configClass, configClass);    }

先来看

if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {            return;        }
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {        if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {            return false;        }        if (phase == null) {            if (metadata instanceof AnnotationMetadata &&                    ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {                return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);            }            return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);        }        List<Condition> conditions = new ArrayList<>();        for (String[] conditionClasses : getConditionClasses(metadata)) {            for (String conditionClass : conditionClasses) {                Condition condition = getCondition(conditionClass, this.context.getClassLoader());                conditions.add(condition);            }        }        AnnotationAwareOrderComparator.sort(conditions);        for (Condition condition : conditions) {            ConfigurationPhase requiredPhase = null;            if (condition instanceof ConfigurationCondition) {                requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();            }            if (requiredPhase == null || requiredPhase == phase) {                if (!condition.matches(this.context, metadata)) {                    return true;                }            }        }        return false;    }

看我们的类有没有使用@Conditional,有使用就进行判断,如果相关条件不通过则丢弃该类,也就是该类不会被注入到spring容器当中。这里就涉及到springboot中很多的条件注解。
关于这个注解以及相关的的条件注解如何实现放在下次讲。

进入sourceClass = doProcessConfigurationClass(configClass, sourceClass);

    @Nullable    protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)            throws IOException {        // Recursively process any member (nested) classes first        processMemberClasses(configClass, sourceClass);        // Process any @PropertySource annotations        for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(                sourceClass.getMetadata(), PropertySources.class,                org.springframework.context.annotation.PropertySource.class)) {            if (this.environment instanceof ConfigurableEnvironment) {                processPropertySource(propertySource);            }            else {                logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +                        "]. Reason: Environment must implement ConfigurableEnvironment");            }        }        // Process any @ComponentScan annotations        Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(                sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);        if (!componentScans.isEmpty() &&                !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {            for (AnnotationAttributes componentScan : componentScans) {                // The config class is annotated with @ComponentScan -> perform the scan immediately                Set<BeanDefinitionHolder> scannedBeanDefinitions =                        this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());                // Check the set of scanned definitions for any further config classes and parse recursively if needed                for (BeanDefinitionHolder holder : scannedBeanDefinitions) {                    if (ConfigurationClassUtils.checkConfigurationClassCandidate(                            holder.getBeanDefinition(), this.metadataReaderFactory)) {                        parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());                    }                }            }        }        // Process any @Import annotations        processImports(configClass, sourceClass, getImports(sourceClass), true);        // Process any @ImportResource annotations        AnnotationAttributes importResource =                AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);        if (importResource != null) {            String[] resources = importResource.getStringArray("locations");            Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");            for (String resource : resources) {                String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);                configClass.addImportedResource(resolvedResource, readerClass);            }        }        // Process individual @Bean methods        Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);        for (MethodMetadata methodMetadata : beanMethods) {            configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));        }        // Process default methods on interfaces        processInterfaces(configClass, sourceClass);        // Process superclass, if any        if (sourceClass.getMetadata().hasSuperClass()) {            String superclass = sourceClass.getMetadata().getSuperClassName();            if (superclass != null && !superclass.startsWith("java") &&                    !this.knownSuperclasses.containsKey(superclass)) {                this.knownSuperclasses.put(superclass, configClass);                // Superclass found, return its annotation metadata and recurse                return sourceClass.getSuperClass();            }        }        // No superclass -> processing is complete        return null;    }

我们从注释就可以看出,这里处理了本类所相关的注解,@PropertySource,@ComponentScan,@Import,@ImportResource,@Bean。

这里我着重讲解@Import,其他的看代码就很容器理解,也可以按照我这样一步步分析。

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,            Collection<SourceClass> importCandidates, boolean checkForCircularImports) throws IOException {        if (importCandidates.isEmpty()) {            return;        }        if (checkForCircularImports && isChainedImportOnStack(configClass)) {            this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));        }        else {            this.importStack.push(configClass);            try {                for (SourceClass candidate : importCandidates) {                    if (candidate.isAssignable(ImportSelector.class)) {                        // Candidate class is an ImportSelector -> delegate to it to determine imports                        Class<?> candidateClass = candidate.loadClass();                        ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);                        ParserStrategyUtils.invokeAwareMethods(                                selector, this.environment, this.resourceLoader, this.registry);                        if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {                            this.deferredImportSelectors.add(                                    new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));                        }                        else {                            String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());                            Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);                            processImports(configClass, currentSourceClass, importSourceClasses, false);                        }                    }                    else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {                        // Candidate class is an ImportBeanDefinitionRegistrar ->                        // delegate to it to register additional bean definitions                        Class<?> candidateClass = candidate.loadClass();                        ImportBeanDefinitionRegistrar registrar =                                BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);                        ParserStrategyUtils.invokeAwareMethods(                                registrar, this.environment, this.resourceLoader, this.registry);                        configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());                    }                    else {                        // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->                        // process it as an @Configuration class                        this.importStack.registerImport(                                currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());                        processConfigurationClass(candidate.asConfigClass(configClass));                    }                }            }            catch (BeanDefinitionStoreException ex) {                throw ex;            }            catch (Throwable ex) {                throw new BeanDefinitionStoreException(                        "Failed to process import candidates for configuration class [" +                        configClass.getMetadata().getClassName() + "]", ex);            }            finally {                this.importStack.pop();            }        }    }

我们使用的@Import(ImportConfig.class)

public class ImportConfig {    @Bean    public Student student(){        return new Student();    }}

ImportConfig只是一个普通的类。

processImports会先判断import中的是ImportSelector还是ImportBeanDefinitionRegistrar,做相应的处理。
关于这两个接口,我想单独拿出来讲解,不放在这里,以免篇幅过长。
读者也可以自己思考。

我们看

// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->                        // process it as an @Configuration classthis.importStack.registerImport(                                currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());                        processConfigurationClass(candidate.asConfigClass(configClass));

看注释该类不是ImportSelector或者ImportBeanDefinitionRegistrar我们把它当做@Configuration类来处理。
再执行
processConfigurationClass(candidate.asConfigClass(configClass));
又回到了我们最开始。

我们解析JavaConfig,解析到@Import中的ImportConfig,发现ImportConfig不是ImportSelector和ImportBeanDefinitionRegistrar,我们把它当做Configuration做同样的处理,如此递归下去,直接解析完所有的类。

到这里我们有所的Configuration,Import配置类等等都解析出来了。

来看

this.reader.loadBeanDefinitions(configClasses);    public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {        TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();        for (ConfigurationClass configClass : configurationModel) {            loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);        }    }private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass,            TrackedConditionEvaluator trackedConditionEvaluator) {        if (trackedConditionEvaluator.shouldSkip(configClass)) {            String beanName = configClass.getBeanName();            if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {                this.registry.removeBeanDefinition(beanName);            }            this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());            return;        }        if (configClass.isImported()) {            registerBeanDefinitionForImportedConfigurationClass(configClass);        }        for (BeanMethod beanMethod : configClass.getBeanMethods()) {            loadBeanDefinitionsForBeanMethod(beanMethod);        }        loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());        loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());    }

这里就把我们的配置类注册到spring容器当中了。

回顾一下:
ConfigurationClassPostProcessor使我们实现注册的核心类,在我们项目启动的时候,该类就被加载进来,在spring生命周期中,进行我们配置类的检测,将相关的类注册到spring容器当中。

ConfigurationClassPostProcessor先去扫描@Configuration,然后处理它@PropertySource,@ComponentScan,@Import,@ImportResource,@Bean。递归下去直到扫描完毕。这些类被处理后都放入spring容器当中。

@PropertySource:读取配置文件
@ComponentScan:扫描相应包下的注解类,或者扫描指定的类
@ImportResource:导入资源文件
@Bean:实例化一个bean放入spring容器当中。
@Import:实例化一个指定的类,当这个类没有实现ImportSelector或者ImportBeanDefinitionRegistrar,会把它当中一个普通的@Configuration来处理。

讲到这里相信大家对spring如何加载java注解配置文件已经基本了解。那么关于@Import中的ImportSelector和ImportBeanDefinitionRegistrar他们是用来干嘛的呢?

@SuppressWarnings("deprecation")@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage@Import(EnableAutoConfigurationImportSelector.class)public @interface EnableAutoConfiguration {    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";    /**     * Exclude specific auto-configuration classes such that they will never be applied.     * @return the classes to exclude     */    Class<?>[] exclude() default {};    /**     * Exclude specific auto-configuration class names such that they will never be     * applied.     * @return the class names to exclude     * @since 1.3.0     */    String[] excludeName() default {};}

springboot中EnableAutoConfiguration自动配置,使用了EnableAutoConfigurationImportSelector

public class EnableAutoConfigurationImportSelector        extends AutoConfigurationImportSelector {public class AutoConfigurationImportSelector        implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,        BeanFactoryAware, EnvironmentAware, Ordered {public interface DeferredImportSelector extends ImportSelector

究竟是怎样实现自动配置。

下回分解吧。。。

阅读全文
0 0
原创粉丝点击