多php网站空间,自动编程软件,直接玩的网页游戏,九江网站建设哪家公司好不难知道#xff0c; property-placeholder 的解析是 PropertyPlaceholderBeanDefinitionParser 完成的#xff0c; 但是 它仅仅是个parser #xff0c; 它仅仅是读取了 location 等配置属性#xff0c; 并没有完成真正的解析#xff0c;及 注册。 context:property-p…不难知道 property-placeholder 的解析是 PropertyPlaceholderBeanDefinitionParser 完成的 但是 它仅仅是个parser 它仅仅是读取了 location 等配置属性 并没有完成真正的解析及 注册。 context:property-placeholder locationappa.properties/ 我们把 location 设置为一个错误的 路径就会报错 从错误堆栈中可以看出 实际的解析是 PropertySourcesPlaceholderConfigurer 完成的 警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanInitializationException: Could not load properties; nested exception is java.io.FileNotFoundException: class path resource [appa.properties] cannot be opened because it does not existException in thread main org.springframework.beans.factory.BeanInitializationException: Could not load properties; nested exception is java.io.FileNotFoundException: class path resource [appa.properties] cannot be opened because it does not existat org.springframework.context.support.PropertySourcesPlaceholderConfigurer.postProcessBeanFactory(PropertySourcesPlaceholderConfigurer.java:148)at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:281)at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:161)at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:686)at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:524)at org.springframework.context.support.ClassPathXmlApplicationContext.init(ClassPathXmlApplicationContext.java:139)at org.springframework.context.support.ClassPathXmlApplicationContext.init(ClassPathXmlApplicationContext.java:83)at LKtest.main(LKtest.java:11)Caused by: java.io.FileNotFoundException: class path resource [appa.properties] cannot be opened because it does not existat org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:172)at org.springframework.core.io.support.EncodedResource.getInputStream(EncodedResource.java:154)at org.springframework.core.io.support.PropertiesLoaderUtils.fillProperties(PropertiesLoaderUtils.java:98)at org.springframework.core.io.support.PropertiesLoaderSupport.loadProperties(PropertiesLoaderSupport.java:177)at org.springframework.core.io.support.PropertiesLoaderSupport.mergeProperties(PropertiesLoaderSupport.java:158)at org.springframework.context.support.PropertySourcesPlaceholderConfigurer.postProcessBeanFactory(PropertySourcesPlaceholderConfigurer.java:139)... 7 more 但是 PropertyPlaceholderBeanDefinitionParser具体是 何时被注册的呢 我纠结了很久 仔细调试代码终于发现了奥秘 at org.springframework.context.config.PropertyPlaceholderBeanDefinitionParser.getBeanClass(PropertyPlaceholderBeanDefinitionParser.java:48)at org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser.parseInternal(AbstractSingleBeanDefinitionParser.java:66) // 又交给了实际的子类去parse at org.springframework.beans.factory.xml.AbstractBeanDefinitionParser.parse(AbstractBeanDefinitionParser.java:61)at org.springframework.beans.factory.xml.NamespaceHandlerSupport.parse(NamespaceHandlerSupport.java:74)at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1411)at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1401)at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:172)at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:142)at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:94)at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:508)at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:392)at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:336)at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:304)at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:181)at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:217)at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:188)at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:252)at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:127)at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:93)at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:129)at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:613)at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:514)- locked 0x5d2 (a java.lang.Object)at org.springframework.context.support.ClassPathXmlApplicationContext.init(ClassPathXmlApplicationContext.java:139)at org.springframework.context.support.ClassPathXmlApplicationContext.init(ClassPathXmlApplicationContext.java:83)at LKtest.main(LKtest.java:11) 原来是在解析 property-placeholder 这个xml元素的时候完成的 parseCustomElement 。 解析 property-placeholder的时候找到了 PropertyPlaceholderBeanDefinitionParser 。 然后把 配置中的location 交给了它处理。 AbstractSingleBeanDefinitionParserprotected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {BeanDefinitionBuilder builder BeanDefinitionBuilder.genericBeanDefinition();String parentName this.getParentName(element);if(parentName ! null) {builder.getRawBeanDefinition().setParentName(parentName);}Class? beanClass this.getBeanClass(element); 根据context:property-placeholder 找到class。返回的正是 PropertySourcesPlaceholderConfigurer ..}PropertyPlaceholderBeanDefinitionParserprotected Class? getBeanClass(Element element) {return ENVIRONMENT.equals(element.getAttribute(system-properties-mode))?PropertySourcesPlaceholderConfigurer.class:PropertyPlaceholderConfigurer.class;} 但是我还是不知道 properties 文件是如何被读取和解析的 直到我注意到 PropertySourcesPlaceholderConfigurer 实现了 BeanFactoryPostProcessor at org.springframework.core.io.support.PropertiesLoaderUtils.fillProperties(PropertiesLoaderUtils.java:85)at org.springframework.core.io.support.PropertiesLoaderSupport.loadProperties(PropertiesLoaderSupport.java:177) // 这里完成了properties 的读取at org.springframework.core.io.support.PropertiesLoaderSupport.mergeProperties(PropertiesLoaderSupport.java:158)at org.springframework.context.support.PropertySourcesPlaceholderConfigurer.postProcessBeanFactory(PropertySourcesPlaceholderConfigurer.java:139) // 因为PropertySourcesPlaceholderConfigurer 实现了 BeanFactoryPostProcessorat org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:281)at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:161)at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:686)at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:524)- locked 0x6c6 (a java.lang.Object)at org.springframework.context.support.ClassPathXmlApplicationContext.init(ClassPathXmlApplicationContext.java:139)at org.springframework.context.support.ClassPathXmlApplicationContext.init(ClassPathXmlApplicationContext.java:83)at LKtest.main(LKtest.java:11) 具体来说 public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {if(this.propertySources null) {this.propertySources new MutablePropertySources();if(this.environment ! null) {this.propertySources.addLast(new PropertySourceEnvironment(environmentProperties, this.environment) {public String getProperty(String key) { return ((Environment)this.source).getProperty(key); } }); } try { PropertySource? localPropertySource new PropertiesPropertySource(localProperties, this.mergeProperties()); // BeanFactory 创建完成后 读取所有的 properties 文件 if(this.localOverride) { this.propertySources.addFirst(localPropertySource); } else { this.propertySources.addLast(localPropertySource); } } catch (IOException var3) { throw new BeanInitializationException(Could not load properties, var3); } } this.processProperties(beanFactory, (ConfigurablePropertyResolver)(new PropertySourcesPropertyResolver(this.propertySources)));// 将properties 文件内容应用到所有的配置中去也就是替换 ${} 部分 this.appliedPropertySources this.propertySources; } 对 ${} 的替换 at org.springframework.beans.factory.config.BeanDefinitionVisitor.visitPropertyValues(BeanDefinitionVisitor.java:142) at org.springframework.beans.factory.config.BeanDefinitionVisitor.visitBeanDefinition(BeanDefinitionVisitor.java:82) at org.springframework.beans.factory.config.PlaceholderConfigurerSupport.doProcessProperties(PlaceholderConfigurerSupport.java:220) // 完成了所有的beanDefinition 的预处理之后 开始替换 Placeholder at org.springframework.context.support.PropertySourcesPlaceholderConfigurer.processProperties(PropertySourcesPlaceholderConfigurer.java:180) at org.springframework.context.support.PropertySourcesPlaceholderConfigurer.postProcessBeanFactory(PropertySourcesPlaceholderConfigurer.java:152) ... protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess, StringValueResolver valueResolver) { BeanDefinitionVisitor visitor new BeanDefinitionVisitor(valueResolver); String[] beanNames beanFactoryToProcess.getBeanDefinitionNames(); // 获取所有已经注册的 bean 定义 String[] var5 beanNames; int var6 beanNames.length; for(int var7 0; var7 var6; var7) { String curName var5[var7]; if(!curName.equals(this.beanName) || !beanFactoryToProcess.equals(this.beanFactory)) { BeanDefinition bd beanFactoryToProcess.getBeanDefinition(curName); try { visitor.visitBeanDefinition(bd); } catch (Exception var11) { throw new BeanDefinitionStoreException(bd.getResourceDescription(), curName, var11.getMessage(), var11); } } } beanFactoryToProcess.resolveAliases(valueResolver); beanFactoryToProcess.addEmbeddedValueResolver(valueResolver); } PropertySourcesPlaceholderConfigurer的父类定义了 如何设置 placeholder 可见前缀和后缀 public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfigurer implements BeanNameAware, BeanFactoryAware { public static final String DEFAULT_PLACEHOLDER_PREFIX ${; public static final String DEFAULT_PLACEHOLDER_SUFFIX }; public static final String DEFAULT_VALUE_SEPARATOR :; protected String placeholderPrefix ${; protected String placeholderSuffix }; protected String valueSeparator :; PropertySource 就是一个kv 配置项。 其中位于 BeanDefinitionVisitor public void visitBeanDefinition(BeanDefinition beanDefinition) { this.visitParentName(beanDefinition); this.visitBeanClassName(beanDefinition); this.visitFactoryBeanName(beanDefinition); this.visitFactoryMethodName(beanDefinition); this.visitScope(beanDefinition); this.visitPropertyValues(beanDefinition.getPropertyValues()); ConstructorArgumentValues cas beanDefinition.getConstructorArgumentValues(); this.visitIndexedArgumentValues(cas.getIndexedArgumentValues()); this.visitGenericArgumentValues(cas.getGenericArgumentValues()); }