简体   繁体   中英

How to externalize Spring Boot application.properties to tomcat/lib folder

I need a configuration free, deployable war, myapp1.war that can retrieve the configuration files from the tomcat/lib folder. As I have other web applications coexisting on the same Tomcat: myapp2.war, myapp3.war, I need this layout:

tomcat/lib/myapp1/application.properties
tomcat/lib/myapp2/application.properties
tomcat/lib/myapp3/application.properties

This way I can build the war files without any properties files inside the war and deploy on any server.

I have read the Spring documentation but it explains how to set the location when running as a jar:

java -jar myapp.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties

I cannot figure out how to do this for the case of multiple coexisting war files.

I would like to know if this is possible or should I give up on Spring Boot and go back to the traditional Spring MVC applications.

A solution could be to load application-{profile}.properties as @PropertySource annotations as this question suggests, but then the logging system wont work, as you can see in the documentation .

The logging system is initialized early in the application lifecycle and as such logging properties will not be found in property files loaded via @PropertySource annotations.

This means that your logging properties in application-{profiles}.properties like:

logging.config=classpath:myapp1/logback.xml
logging.path = /path/to/logs
logging.file = myapp1.log

will be ignored and the logging system wont work.

To solve this I have used the SpringApplicationBuilder.properties() method to load properties at the beginning, when the application is configured. There I set the 'spring.config.location' used by Spring Boot to load all the application-{profiles}.properties:

public class Application extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder springApplicationBuilder) {
        return springApplicationBuilder
                .sources(Application.class)
                .properties(getProperties());
    }

    public static void main(String[] args) {

        SpringApplicationBuilder springApplicationBuilder = new SpringApplicationBuilder(Application.class)
                .sources(Application.class)
                .properties(getProperties())
                .run(args);
    }

   static Properties getProperties() {
      Properties props = new Properties();
      props.put("spring.config.location", "classpath:myapp1/");
      return props;
   }
}

Then I have moved the properties files from src/main/resources to src/main/resources/myapp1

.
├src
| └main
|   └resources
|     └myapp1
|       └application.properties
|       └application-development.properties
|       └logback.xml
└─pom.xml

In the pom.xml I have to set the scope of embedded tomcat libraries as "provided". Also, to exclude all properties files in src/main/resources/myapp1 from the final war and generate a configuration free, deployable war:

    <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.6</version>
        <configuration>
            <failOnMissingWebXml>false</failOnMissingWebXml>
            <packagingExcludes>
              **/myapp1/
            </packagingExcludes>
        </configuration>
    </plugin>

Then in Tomcat I have

├apache-tomcat-7.0.59
 └lib
   ├─myapp1
   |  └application.properties        
   |  └logback.xml
   └─myapp2
     └application.properties
     └logback.xml

Now I can generate the configuration free war and drop it into the apache-tomcat-7.0.59/webapps folder. Properties files will be resolved using the classpath, independently for each webapp:

   apache-tomcat-7.0.59/lib/myapp1
   apache-tomcat-7.0.59/lib/myapp2
   apache-tomcat-7.0.59/lib/myapp3

With Spring 4.2 and @Annotation config and tomcat on linux serveur

In your Application class set the @PropertySource like that :

@Configuration
@EnableWebMvc
@PropertySource(value = { "classpath:application-yourapp.properties"})
@ComponentScan(basePackages = "com.yourapp")
public class YourAppWebConfiguration extends WebMvcConfigurerAdapter {

    ...
}

Now you just need to include the property file in your classpath

In production

Deploy your .war files ( or anything ) on tomcat, and put your application-yourapp.properties anyway on your production machine. ( for exemple in /opt/applyconfigfolder/application-yourapp.properties" )

Then in your tomcat ( here tomcat 7 ) open bin\\catalina.sh

You have this line

# Ensure that any user defined CLASSPATH variables are not used on startup,
# but allow them to be specified in setenv.sh, in rare case when it is needed.
CLASSPATH=

Just add the path of the folder which contains application.properties

CLASSPATH=:/opt/applyconfigfolder

If you have already some classpath define you can add it

CLASSPATH=:/opt/applyconfigfolder:/yourpath1:/yourpath2:

I haven't try with windows but I think there is no problem

In Dev ( with eclipse )

├src
| └main
|   └ ....
└config
| └application-yourapp.properties

instead of src/main/resources/application-yourapp.properties

Now in eclipse add your config folder to classpath, go to "Run Configurations" of your tomcat server ( or equivalent ) and add the folder Config to User Entries

在此输入图像描述

Ok that's it, your application.properties is out of the application and your project run perfectly in dev environment.

Daniel Mora gave a good solution but instead of using spring.config.location you can use spring.config.name ( https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-application-property-files ), so you can have different properties file for different web apps in the same tomcat/lib directory:

    public class Application extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder springApplicationBuilder) {
        return springApplicationBuilder
                .sources(Application.class)
                .properties(getProperties());
    }
    public static void main(String[] args) {

        SpringApplicationBuilder springApplicationBuilder = new SpringApplicationBuilder(Application.class)
                .sources(Application.class)
                .properties(getProperties())
                .run(args);
    }

   static Properties getProperties() {
      Properties props = new Properties();
      props.put("spring.config.name", "myapp1");
      return props;
   }
}

I think that the lib directory is for third party libraries not for storing configuration properties for your web apps. So I think that a better solution is to add an external folder as additional classpath folder using shared.loader property in conf/catalina.properties:

shared.loader=${catalina.base}/shared/configurations

You can put your application properties app1.properties, app2.properties, ecc.. in apache-tomcat-7.0.59/shared/configurations.

Before finding Daniel Mora solution of overridding configure method of SpringBootServletInitializer my solution was to add a context.xml in src/main/webapp/META-INF with this content:

<Context>
    <Environment name="spring.config.name" value="myapp1" type="java.lang.String" override="false" description="define the property file for srping boot application"/>
</Context>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM