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生命周期中执行顺序为
- 构造函数
- BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry
- 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
究竟是怎样实现自动配置。
下回分解吧。。。
- spring注解:@ComponentScan,@Bean,@Import,@Component
- 装配Bean:JavaConfig@Component@ComponentScan@Configuration
- spring系列之@Configuration注解、@Bean注解以及自动扫描注解@componentScan
- spring的注解(1): @Configuration,@Bean,@Component,
- Spring中注解@Bean、@Resource、@Component、@SpringStudy
- Spring 使用@ComponentScan扫描注解包
- Spring Boot的@SpringBootApplication、@EnableAutoConfiguration、@ComponentScan注解
- Spring的bean的装配 @Componen @ComponentScan @Autowired
- Spring Annotation(注解) @Component
- Spring注解@Component、
- Spring中@component注解
- spring中@Component注解
- Spring-Component注解翻译
- spring 注解@component 学习
- 理解@ComponentScan注解
- 理解@ComponentScan注解
- Spring @Import注解
- <context:component-scan>的name-generator属性 自定义Spring Bean注解命名规则
- shiro登录成功后指定跳转页面
- Java OCR tesseract 图像智能字符识别技术
- 使用xperf收集并使用Windows Performance Analyzer查看Windows性能信息
- ldap服务器搭建
- 欢迎使用CSDN-markdown编辑器
- spring注解:@ComponentScan,@Bean,@Import,@Component
- Oracle PL/SQL Dev工具(破解版)被植入勒索病毒的安全预警及自查通告
- 知识星球作业(第5周)
- 选择排序法 Java实现
- Setting Up Swagger 2 with a Spring Boot REST API
- Vue 子组件的异步加载及其生命周期控制
- runOnUiThread 、Handler.post、View.post之间的区别
- 月薪过万的UI设计师有哪些能力
- oracle 精确到小数秒的timestamp类型分区表