When we develop applications based on spring, we typically place the configuration of the database in the properties file.
At the time of code analysis, a summary of the knowledge points involved:
- Namespacehandler parsing a custom namespace in an XML configuration file
- Contextnamespacehandler a context-sensitive parser, which defines how to parse the Property-placeholder parser
- Beandefinitionparser interface for parsing bean definition
- Beanfactorypostprocessor The bean definition can be modified after loading it.
- Propertysourcesplaceholderconfigurer handling placeholders in bean definition
Let's take a look at the specific use.
Property usage Configure the properties file in the XML file
<?xmlVersion= "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="Http://www.springframework.org/schema/beansHttp://www.springframework.org/schema/beans/spring-beans-4.2.xsd http ://www.springframework.org/schema/context< Span class= "Hljs-tag" > http://www.springframework.org/schema/context/ Spring-context-4.2.xsd "> <context:property-placeholder location= "classpath: Foo.properties " /></BEANS>
So the/src/main/resources/foo.properties file will be loaded by spring
If you want to use more than one configuration file, you can add an order field to sort
Configuring with Propertysource annotations
Spring3.1 added @propertysource annotations to facilitate the addition of property files to the environment.
@Configuration@PropertySource("classpath:foo.properties")public class PropertiesWithJavaConfig { @Bean public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { return new PropertySourcesPlaceholderConfigurer(); }}
The injection and use of properties
Use @value annotations in Java to get
@Value( "${jdbc.url}" )private String jdbcUrl;
You can also add a default value
@Value( "${jdbc.url:aDefaultUrl}" )private String jdbcUrl;
In the spring XML configuration file, get
<bean id="dataSource"> <property name="url" value="${jdbc.url}" /></bean>
Source parsing properties configuration information loading
Spring starts the container initialization work through Abstractapplicationcontext#refresh at startup, and delegates the loadbeandefinitions parsing of the XML configuration file.
Protected Final void Refreshbeanfactory()Throwsbeansexception {if (Hasbeanfactory ()) {Destroybeans ();Closebeanfactory (); }try {defaultlistablebeanfactory beanfactory =createbeanfactory (); beanfactory. setserializationid (getid ()); customizebeanfactory (beanfactory); loadbeandefinitions (beanfactory); synchronized (this.< Span class= "Fu" >beanfactorymonitor) {this.catch (IOException ex) {throw new "I/O error parsing bean definition source for "+ getdisplayname (), ex);}
Loadbeandefinitions to find Defaultbeandefinitiondocumentreader#parsebeandefinition parse specific bean through layer-by-layer delegation
Protected void Parsebeandefinitions(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.parsedefaultelement (Ele, delegate);} else {delegate.else {delegate.
Because this is not a standard class definition, the delegate beandefinitionparserdelegate resolves
by Namespacehandler find the corresponding processor is Contextnamespacehandler, and then through the ID found Propertyplaceholderbeandefinitionparser parser parsing
@OverridePublic void Init() {This is the parser we're looking for.Registerbeandefinitionparser ("Property-placeholder",NewPropertyplaceholderbeandefinitionparser ());Registerbeandefinitionparser ("Property-override",NewPropertyoverridebeandefinitionparser ());Registerbeandefinitionparser ("Annotation-config",NewAnnotationconfigbeandefinitionparser ());Registerbeandefinitionparser ("Component-scan",NewComponentscanbeandefinitionparser ());Registerbeandefinitionparser ( "Load-time-weaver", new Span class= "Fu" >loadtimeweaverbeandefinitionparser ()); registerbeandefinitionparser ( "spring-configured", span class= "kw" >new springconfiguredbeandefinitionparser ()); registerbeandefinitionparser ( "Mbean-export", new mbeanexportbeandefinitionparser ()); registerbeandefinitionparser ( "Mbean-server", new mbeanserverbeandefinitionparser ());}
Propertyplaceholderbeandefinitionparser is the focus of this round of code analysis.
Let's take a look at its parent class.
Beandefinitionparser
Used by Defaultbeandefinitiondocumentreader to parse personalized labels
This only defines a parse API that parses element
public interface BeanDefinitionParser {BeanDefinition parse(Element element, ParserContext parserContext);}
- Abstractbeandefinitionparser
The default abstract implementation of the Beandefinitionparser interface. Spring's forte, this side provides a lot of handy API, and uses the template method design pattern to provide the child class with custom implementation hooks
Let's take a look at parse when the specific handling logic puts:
- Call Hook parseinternal Parsing
- Generate Bean ID, generate using Beannamegenerator, or read ID attribute directly
- Handling name and alias aliases
- Registering beans in a container
- To trigger an event
Abstractsinglebeandefinitionparser
Parsing, defining an abstract parent class for a single beandefinition
In Parseinternal, the Parentname,beanclass,source is parsed and encapsulated using the Beandefinitionbuilder
Abstractpropertyloadingbeandefinitionparser
Parse Property-related properties, such as Location,properties-ref,file-encoding,order, etc.
Propertyplaceholderbeandefinitionparser
There's not much to deal with, it's setting up ingore-unresolvable and System-properties-mode.
Properties file loading, bean instantiation
Next, we look at when this bean is instantiated, there are 2 instances of the general class, one is the instantiation of a singleton system start-up, and a non-singleton (or singleton lazy loading) is instantiated at Getbean.
The trigger here is through beanfcatorypostprocessor.
Beanfactorypostprocessor is to modify the bean definition before the bean is instantiated, such as the placeholder in the bean definition is resolved here, and the properties we use now are resolved here.
This is achieved through postprocessorregistrationdelegate#invokebeanfactorypostprocessors.
Scan the beanfactorypostprocessor in the container, find the propertysourcesplaceholderconfigurer needed here, and instantiate it through the getbean of the container
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); }
Once the Propertysourcesplaceholderconfigurer instantiation is complete, it fires directly and loads the information
OrderComparator.sort(priorityOrderedPostProcessors); invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
Let's take a look at the succession system of Propertysourcesplaceholderconfigurer
Beanfactorypostprocessor
Defines an interface that modifies the attributes of a bean definition in a container. Its implementation class is instantiated before the generic class is used, and the properties of other classes are modified.
This is clearly different from Beanpostprocessor, where beanpostprocessor is modifying the bean instance.
Propertiesloadersupport
The abstract class that loads the properties file.
Here the specific load logic is delegated propertiesloaderutils#fillproperties implementation
Propertyresourceconfigurer
The substitution of placeholders in bean definition is implemented by this abstract class.
Implement Beanfactorypostprocessor#postprocessbeanfactory, iterate the class definition in the container, make modifications
Specifically how to modify the hook processproperties by the sub-class implementation
Placeholderconfigurersupport
Use visitor design mode to update properties with Beandefinitionvisitor and Stringvalueresolver
Stringvalueresolver is an interface that transforms string type data, and the API implementation that really updates the properties is Propertyplaceholderhelper#parsestringvalue
Propertysourcesplaceholderconfigurer
Overwrite Postprocessorbeanfactory API definition parsing process
Go The use and analysis of Property-placeholder in spring