我们在基于spring开发应用的时候,一般都会将数据库的配置放置在properties文件中.
代码分析的时候,涉及的知识点概要:
NamespaceHandler 解析xml配置文件中的自定义命名空间
ContextNamespaceHandler 上下文相关的解析器,这边定义了具体如何解析property-placeholder的解析器
BeanDefinitionParser 解析bean definition的接口
BeanFactoryPostProcessor 加载好bean definition后可以对其进行修改
PropertySourcesPlaceholderConfigurer 处理bean definition 中的占位符
我们先来看看具体的使用吧
property的使用 在xml文件中配置properties文件<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" "> <context:property-placeholder location="classpath:foo.properties"/> </beans>
这样/src/main/resources/foo.properties文件就会被spring加载
如果想使用多个配置文件,可以添加order字段来进行排序
Spring3.1添加了@PropertySource注解,方便添加property文件到环境.
@Configuration @PropertySource("classpath:foo.properties") public class PropertiesWithJavaConfig { @Bean public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { return new PropertySourcesPlaceholderConfigurer(); } }
properties的注入与使用
java中使用@Value注解获取
@Value( "${jdbc.url}" ) private String jdbcUrl;
还可以添加一个默认值
@Value( "${jdbc.url:aDefaultUrl}" ) private String jdbcUrl;
在Spring的xml配置文件中获取
<bean id="dataSource"> <property name="url" value="${jdbc.url}" /> </bean>
源码解析 properties配置信息的加载Spring在启动时会通过AbstractApplicationContext#refresh启动容器初始化工作,期间会委托loadBeanDefinitions解析xml配置文件.
protectedfinalvoidrefreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
loadBeanDefinitions通过层层委托,找到DefaultBeanDefinitionDocumentReader#parseBeanDefinition解析具体的bean
protectedvoidparseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }