@Override publicvoidinit(){ registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser()); registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser()); registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser()); registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser()); registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser()); registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser()); registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser()); registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser()); } }
@Override protected Class<?> getBeanClass(Element element) { // As of Spring 3.1, the default value of system-properties-mode has changed from // 'FALLBACK' to 'ENVIRONMENT'. This latter value indicates that resolution of // placeholders against system properties is a function of the Environment and // its current set of PropertySources. if (SYSTEM_PROPERTIES_MODE_DEFAULT.equals(element.getAttribute(SYSTEM_PROPERTIES_MODE_ATTRIBUTE))) { return PropertySourcesPlaceholderConfigurer.class; }
// The user has explicitly specified a value for system-properties-mode: revert to // PropertyPlaceholderConfigurer to ensure backward compatibility with 3.0 and earlier. return PropertyPlaceholderConfigurer.class; }
Specifies if failure to find the property value to replace a key should be ignored. Default is “false”, meaning that this placeholder configurer will raise an exception if it cannot resolve a key. Set to “true” to allow the configurer to pass on the key to any others in the context that have not yet visited the key in question.
The separating character between the placeholder variable and the associated default value: by default, a ‘:’ symbol.
null-value
A value that should be treated as ‘null’ when resolved as a placeholder value: e.g. “” (empty String) or “null”. By default, no such null value is defined.
/** * Should an ID be generated instead of read from the passed in {@link Element}? * <p>Disabled by default; subclasses can override this to enable ID generation. * Note that this flag is about <i>always</i> generating an ID; the parser * won't even check for an "id" attribute in this case. * @return whether the parser should always generate an id */ protectedbooleanshouldGenerateId(){ returnfalse; }
/** * Parse the elements at the root level in the document: * "import", "alias", "bean". * @param root the DOM root element of the document */ 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); } }
/** * Parses the supplied {@link Element} by delegating to the {@link BeanDefinitionParser} that is * registered for that {@link Element}. */ @Override public BeanDefinition parse(Element element, ParserContext parserContext){ return findParserForElement(element, parserContext).parse(element, parserContext); }
/** * Locates the {@link BeanDefinitionParser} from the register implementations using * the local name of the supplied {@link Element}. */ private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext){ String localName = parserContext.getDelegate().getLocalName(element); BeanDefinitionParser parser = this.parsers.get(localName); if (parser == null) { parserContext.getReaderContext().fatal( "Cannot locate BeanDefinitionParser for element [" + localName + "]", element); } return parser; }
/** * {@inheritDoc} * <p>Processing occurs by replacing ${...} placeholders in bean definitions by resolving each * against this configurer's set of {@link PropertySources}, which includes: * <ul> * <li>all {@linkplain org.springframework.core.env.ConfigurableEnvironment#getPropertySources * environment property sources}, if an {@code Environment} {@linkplain #setEnvironment is present} * <li>{@linkplain #mergeProperties merged local properties}, if {@linkplain #setLocation any} * {@linkplain #setLocations have} {@linkplain #setProperties been} * {@linkplain #setPropertiesArray specified} * <li>any property sources set by calling {@link #setPropertySources} * </ul> * <p>If {@link #setPropertySources} is called, <strong>environment and local properties will be * ignored</strong>. This method is designed to give the user fine-grained control over property * sources, and once set, the configurer makes no assumptions about adding additional sources. */ @Override publicvoidpostProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)throws BeansException { if (this.propertySources == null) { this.propertySources = new MutablePropertySources(); if (this.environment != null) { this.propertySources.addLast( new PropertySource<Environment>(ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME, this.environment) { @Override public String getProperty(String key){ returnthis.source.getProperty(key); } } ); } try { PropertySource<?> localPropertySource = new PropertiesPropertySource(LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME, mergeProperties()); if (this.localOverride) { this.propertySources.addFirst(localPropertySource); } else { this.propertySources.addLast(localPropertySource); } } catch (IOException ex) { thrownew BeanInitializationException("Could not load properties", ex); } }
processProperties(beanFactory, new PropertySourcesPropertyResolver(this.propertySources)); this.appliedPropertySources = this.propertySources; }
/** * <p>Any local properties (e.g. those added via {@link #setProperties}, {@link #setLocations} * et al.) are added as a {@code PropertySource}. Search precedence of local properties is * based on the value of the {@link #setLocalOverride localOverride} property, which is by * default {@code false} meaning that local properties are to be searched last, after all * environment property sources. */
/** * Visit each bean definition in the given bean factory and attempt to replace ${...} property * placeholders with values from the given properties. */ protectedvoidprocessProperties(ConfigurableListableBeanFactory beanFactoryToProcess, final ConfigurablePropertyResolver propertyResolver)throws BeansException {
<xsd:attributename="ignore-unresolvable"type="xsd:boolean"default="false"> <xsd:annotation> <xsd:documentation><![CDATA[ Specifies if failure to find the property value to replace a key should be ignored. Default is "false", meaning that this placeholder configurer will raise an exception if it cannot resolve a key. Set to "true" to allow the configurer to pass on the key to any others in the context that have not yet visited the key in question. ]]></xsd:documentation> </xsd:annotation> </xsd:attribute>
BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);
String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames(); for (String curName : beanNames) { // Check that we're not parsing our own bean definition, // to avoid failing on unresolvable placeholders in properties file locations. if (!(curName.equals(this.beanName) && beanFactoryToProcess.equals(this.beanFactory))) { BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(curName); try { visitor.visitBeanDefinition(bd); } catch (Exception ex) { thrownew BeanDefinitionStoreException(bd.getResourceDescription(), curName, ex.getMessage(), ex); } } }
// New in Spring 2.5: resolve placeholders in alias target names and aliases as well. beanFactoryToProcess.resolveAliases(valueResolver);
// New in Spring 3.0: resolve placeholders in embedded values such as annotation attributes. beanFactoryToProcess.addEmbeddedValueResolver(valueResolver); }
/** * Traverse the given BeanDefinition object and the MutablePropertyValues * and ConstructorArgumentValues contained in them. * @param beanDefinition the BeanDefinition object to traverse * @see #resolveStringValue(String) */ publicvoidvisitBeanDefinition(BeanDefinition beanDefinition){ visitParentName(beanDefinition); visitBeanClassName(beanDefinition); visitFactoryBeanName(beanDefinition); visitFactoryMethodName(beanDefinition); visitScope(beanDefinition); visitPropertyValues(beanDefinition.getPropertyValues()); ConstructorArgumentValues cas = beanDefinition.getConstructorArgumentValues(); visitIndexedArgumentValues(cas.getIndexedArgumentValues()); visitGenericArgumentValues(cas.getGenericArgumentValues()); }
/** * Resolve the given String value, for example parsing placeholders. * @param strVal the original String value * @return the resolved String value */ protected String resolveStringValue(String strVal){ if (this.valueResolver == null) { thrownew IllegalStateException("No StringValueResolver specified - pass a resolver " + "object into the constructor or override the 'resolveStringValue' method"); } String resolvedValue = this.valueResolver.resolveStringValue(strVal); // Return original String if not modified. return (strVal.equals(resolvedValue) ? strVal : resolvedValue); }
顺藤摸瓜,看看valueResolver,就是之前的StringValueResolver
这是一个接口只有一个方法
1 2 3 4 5 6 7 8 9 10
publicinterfaceStringValueResolver{
/** * Resolve the given String value, for example parsing placeholders. * @param strVal the original String value * @return the resolved String value */ String resolveStringValue(String strVal);
/** * Creates a new {@code PropertyPlaceholderHelper} that uses the supplied prefix and suffix. * @param placeholderPrefix the prefix that denotes the start of a placeholder * @param placeholderSuffix the suffix that denotes the end of a placeholder * @param valueSeparator the separating character between the placeholder variable * and the associated default value, if any * @param ignoreUnresolvablePlaceholders indicates whether unresolvable placeholders should * be ignored ({@code true}) or cause an exception ({@code false}) */
/** * Replaces all placeholders of format {@code ${name}} with the value returned * from the supplied {@link PlaceholderResolver}. * @param value the value containing the placeholders to be replaced * @param placeholderResolver the {@code PlaceholderResolver} to use for replacement * @return the supplied value with placeholders replaced inline */ public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver){ Assert.notNull(value, "'value' must not be null"); return parseStringValue(value, placeholderResolver, new HashSet<String>()); }