克拉玛依市建设局网站,苏州优秀网站设计公司,常州自助做网站,网站建设公司推广网站品牌运营Configuration 注解是spring-context模块提供的一个给开发者使用的配置类注解#xff0c;开发者可以通过Configuration注解来定义配置类#xff0c;也可以使用xml形式注入。 例如配置数据库配置#xff0c;定义一个配置类#xff0c;注入数据源DataSource, 事务管理器Trans… Configuration 注解是spring-context模块提供的一个给开发者使用的配置类注解开发者可以通过Configuration注解来定义配置类也可以使用xml形式注入。 例如配置数据库配置定义一个配置类注入数据源DataSource, 事务管理器TransactionManager 多数据源管理等都可以使用Configuration 类来标记该类是一个配置类Spring 框架会扫描并解析该类里的Bean 并注入下面就如何解析配置类源码解析。 官方源码解释: 1. Indicates that a class declares one or more Bean methods and may be processed by the spring container to generate bean definitions and service requests for those beans at runtime. 表示一个类声明了一个或多个被Bean注解标记的方法 他们应该会在运行时被Spring 容器处理并会为这些Bean产生bean definitions 和服务请求。 Configurationpublic class AppConfig {Beanpublic MyBean myBean() {// instantiate, configure and return bean ...}} 简单讲: Configuration 标记的类可以用Bean 定义很多Bean method 。
一、Configuration 用法
1. 注解形式Configuration Configurationpublic class AppConfig {Beanpublic MyBean myBean() {// instantiate, configure and return bean ...}} 使用AnnotationConfigurationApplicationContext初始化配置类。
AnnotationConfigApplicationContext ctx new AnnotationConfigApplicationContext();ctx.register(AppConfig.class);ctx.refresh();MyBean myBean ctx.getBean(MyBean.class);// use myBean ...
2. xml形式 使用context:annotation-config 属性声明, xml形式需要使用ClassPathXmlApplicationContext来加载。
beanscontext:annotation-config/bean classcom.acme.AppConfig//beans 官方: In the example above, context: annotation-config is required in order to enable ConfigurationClassPostProcessor. 我们从官方解释中看到根据配置会进入到ConfigurationClassPostProcessor那ConfigurationClassPostProcessor 会是扫描这些配置Bean的入口。
二、ConfigurationClassPostProcessor源码解析 ConfigurationClassPostProcessor 类实现了BeanFacotryPostProcessor和BeanDefinitionRegistryPostProcessor 两个接口 是解析Configuration类的入口。 1. BeanFactoryPostProcessor: PostProcessBeanFactory 方法入参为ConfigurableListableBeanFactory, ConfigurableListableBeanFactory的默认实现为DefaultListableBeanFactory 提供 2.BeanDefinitionRegistryPostProcessor: postProcessBeanDefinitionRegistry()方法入参为BeanDefinitionRegistry。该方法的作用主要是扫描并注册所有Configuraiton注解标记的类下的bean。 先进入到processConfigBeanDefinitions方法看看做了哪些事? 这里我们可以发现遍历所有的BeanDefinition, 过滤掉已经处理完的ConfigurationClass. 用isFullConfigurationClass和isLiteConfigurationClass来判断。 如果已经设置了候选人身份那么该判断就为true, 也就不会继续进行放入到configCondidates里。 如果之前没有设置候选人身份那么在执行CheckConfigurationClassCandidate时会检查是否为FullConfigurationCandidate和LiteConfigurationCandidate 接着看FullConfigurationCandidate和LiteConfigurationCandidate。
FullConfigurationCandidate和LiteConfigurationCandidate 从字面意思上理解一个为满一个为简的候选人那他们真正的含义是什么呢? FullConfigurationCandidate 直接被Configuration注解标记的类被称为FullConfigurationCandidate。 public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {return metadata.isAnnotated(Configuration.class.getName());} LiteConfigurationCandidate 主要是指被Component、ComponentScan、Import、ImportSource注解标记的类。 private static final SetString candidateIndicators new HashSet(8);static {candidateIndicators.add(Component.class.getName());candidateIndicators.add(ComponentScan.class.getName());candidateIndicators.add(Import.class.getName());candidateIndicators.add(ImportResource.class.getName());}public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata) {// Do not consider an interface or an annotation...if (metadata.isInterface()) {return false;}// Any of the typical annotations found?for (String indicator : candidateIndicators) {if (metadata.isAnnotated(indicator)) {return true;}}// Finally, lets look for Bean methods...try {return metadata.hasAnnotatedMethods(Bean.class.getName());}catch (Throwable ex) {if (logger.isDebugEnabled()) {logger.debug(Failed to introspect Bean methods on class [ metadata.getClassName() ]: ex);}return false;}} 如果是FullConfigurationCandidate或者LiteConfigurationCandidate, 那么给该Definition打个标记表示该BeanDefinition已经候选过 那下次扫描的时候就会跳过该BeanDefinition。
if (isFullConfigurationCandidate(metadata)) {// 表示已经候选过beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);}else if (isLiteConfigurationCandidate(metadata)) {beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);} 走到这里configCandidates有一个值了该值我配置的MybatisConfig类: 接下来就是解析候选ConfigurationClass 解析所有的候选ConfigurationClass并加载所有的Bean 1. 由ConfigurationClassParser 解析所有的candidates。 2. 由ConfigurationClassBeanDefinitionReader 来解析该configurationClass里的所有Bean。 3. 再次检查是否有新的ConfigurationClass加入到candidates集合里如果有那么继续解析并加载所有的Bean。 源码如下:
do {//解析所有的候选Beanparser.parse(candidates);//对ConfigurationClass校验, 如果是Final类会报错。parser.validate();SetConfigurationClass configClasses new LinkedHashSet(parser.getConfigurationClasses());configClasses.removeAll(alreadyParsed);// Read the model and create bean definitions based on its contentif (this.reader null) {this.reader new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment,this.importBeanNameGenerator, parser.getImportRegistry());}// 加载所有的BeanDefinitionsthis.reader.loadBeanDefinitions(configClasses);// 已经解析了加入到alreadyParsed集合了alreadyParsed.addAll(configClasses);candidates.clear();// 再次检查以防有新的ConfigurationClass 加入if (registry.getBeanDefinitionCount() candidateNames.length) {String[] newCandidateNames registry.getBeanDefinitionNames();SetString oldCandidateNames new HashSet(Arrays.asList(candidateNames));SetString alreadyParsedClasses new HashSet();for (ConfigurationClass configurationClass : alreadyParsed) {alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());}for (String candidateName : newCandidateNames) {if (!oldCandidateNames.contains(candidateName)) {BeanDefinition bd registry.getBeanDefinition(candidateName);if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) !alreadyParsedClasses.contains(bd.getBeanClassName())) {// 补偿未添加上的Candidatescandidates.add(new BeanDefinitionHolder(bd, candidateName));}}}candidateNames newCandidateNames;}}while (!candidates.isEmpty());
三、Configuration配合Profile使用 官方源码给出了一个用法例子对于不同的开发环境可以使用Profile注解来指定配置文件。 Profile(development)Configurationpublic class EmbeddedDatabaseConfig {Beanpublic DataSource dataSource() {// instantiate, configure and return embedded DataSource}}Profile(production)Configurationpublic class ProductionDatabaseConfig {Beanpublic DataSource dataSource() {// instantiate, configure and return production DataSource}} spring boot项目使用spring.profiles.activedevelopment来指定激活的profile 指定哪个就用哪个。