Configuration coverage is better than profile
In production practice, configuration coverage is a common method to solve different configurations in different environments. For example, use configuration files on the production server to overwrite the files in the package, or use a centralized configuration service to overwrite the default business configuration.
Compared with the profile mechanism (such as maven's profile and spring boot's profile-specific properties), different environments use different configuration files, and the overlay method is more advantageous. Programmers do not need to care about the address, account and other information of the production environment database during development. They can run in different environments by building at one time. The profile mechanism needs to write the configuration of the production environment into the project resource file, and different construction parameters or operation parameters must be used for different environments.
Spring provides flexible configuration expansion capabilities, with multiple ways to integrate custom attribute sources into it, allowing easy configuration coverage.
This article is written based on Spring Boot 1.4.8/Spring 4.3.12
Use @PropertySource annotation to implement custom configuration files and configuration override
@ConfigurationProperties@Configurationpublic class DemoProperties { // properties with getter/setters} @PropertySource(value = { "test.properties", "file:/etc/test.properties",}, ignoreResourceNotFound = true)@Configurationpublic class DemoAutoConfiguration { @Autowired private DemoProperties demoProperties; @PostConstruct public void init() { System.out.println(demoProperties); }}Spring supports introducing custom configuration files using PropertySource annotations, where "test.properties" will cause Spring to load the file from classpath, "file:/etc/test.properties" will cause Spring to load the /etc/test.properties file from the file system, ignoreResourceNotFound = true makes Spring ignore the exception of file loading failure, that is, the configuration file is optional.
At the same time, since "file:/etc/test.properties" is located after "test.properties", this allows the file system configuration file to overwrite the configuration under classpath.
Custom property source factory
If you want to customize the property source more flexible, such as loading configurations from a centralized configuration service, you can implement the PropertySourceFactory interface and configure the factory parameters of the PropertySource annotation.
@Configuration@PropertySource(value = ""/*placeholder*/, factory = CompositePropertySourceFactory.class)public class CompositeConfigAutoConfiguration {}The value field is used to specify the resource file corresponding to the configuration source. If the resource file is not required, it can be configured as any value. The parameter value will be passed to the createPropertySource method of the factory parameter.
If the ignoreResourceNotFound field is specified as true, the exception thrown by the factory will be ignored, otherwise it will cause the startup to fail. Sometimes, it is a good practice to directly expose the startup failure.
The definition of the PropertySourceFactory interface is as follows:
/** * Strategy interface for creating resource-based {@link PropertySource} wrappers. * * @author Juergen Hoeller * @since 4.3 * @see DefaultPropertySourceFactory */public interface PropertySourceFactory { /** * Create a {@link PropertySource} that wraps the given resource. * @param name the name of the property source * @param resource the resource (potentially encoded) to wrap * @return the new {@link PropertySource} (never {@code null}) * @throws IOException if resource resolution failed */ PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException;}It should be noted that the loading time of PropertySourceFactory is earlier than that of Spring Beans containers, so the implementation cannot depend on Spring's IOC.
PropertySourceFactory requires the implementation class to return PropertySource. PropertySource is the core interface of Spring property (or configuration) function, and has many implementations, such as:
The actual implementation classes are far inferior to these. For specific purposes, you can read Spring documentation or source code.
MapPropertySource and CompositePropertySource are commonly used when customizing property sources.
MapPropertySource can be used to wrap the property data that it loads itself, refer to its construction method.
public MapPropertySource(String name, Map<String, Object> source) { super(name, source);}The latter can load multiple attribute sources by combining and customize the override order. For example:
PropertySource<?> packageInsidePropertySource = packageInsidePropertySourceIterateLoader.loadPropertySource(compositePropertySource); compositePropertySource.addPropertySource(packageInsidePropertySource);PropertySource<?> outerFilePropertySource = outerFilePropertySourceIterateLoader.loadPropertySource(compositePropertySource);// The priority is higher than the former compositePropertySource.addFirstPropertySource(outerFilePropertySource);
The addFirstPropertySource method can set the incoming PropertySource to the highest priority (inside this CompositePropertySource), and the addPropertySource method is the opposite, and the priority is lower afterwards.
Load all configuration files with the same name in the dependency jar package
Loading the configuration file directly from the classpath requires that the file must exist in the classpath. Consider in a WEB project, if the file exists in a dependency jar package, that is, it is located in WEB-INF/lib/xxx.jar, it cannot be loaded directly based on classpath. At this time, you can use the PathMatchingResourcePatternResolver provided by Spring to scan all jar packages by resource name to achieve the purpose.
private List<Resource> getPackageInsideResourcesByPattern(String resourceName) throws IOException { String resourcePathPattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + HbootConfigConstants.CONFIGS + resourceName; ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); return Arrays.asList(resourcePatternResolver.getResources(resourcePathPattern));} Then you can use ResourcePropertySource to build PropertySource from Resource to pass to Spring.
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.