ilovkatie ilovkatie - 2 months ago 12
Java Question

Externalize properties and logback Spring

I'm using Spring (without spring-boot). I want to build standalone application that can be run with default configuration (

logback.xml
and
application.properties
in resource folder) or with
-Dconfig.folder=/path/to/custom/external/directory

(
logback.xml
and
application.properties
in /path/to/custom/external/directory). When application will be run with -Dconfig.folder param
AppConfig
should load both logback and properties from external directory.

Is there anyway to make external folder act like a resource folder?

If not, what is a common solution for this?

My current implementation (using default resource folder only):

App.java

public class App {

public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

SampleAction p = context.getBean(SampleAction.class);
p.performTask();
}
}


AppConfig.java

@ComponentScan
@PropertySource("classpath:application.properties")
class AppConfig {

@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}


SampleAction.java

@Component
public class SampleAction {
private final Logger logger = LoggerFactory.getLogger(this.getClass());

@Value("${sample.prop}")
private String sampleProp;

public void performTask(){
logger.debug(sampleProp);
}
}


logback.xml and application.properties are not relevant to the problem

Answer Source

Unlike the other answer suggests, if you use file prefix in @PropertySource, you're screwed because it won't be able to load the default application.properties from the jar. What you should do is the following:

@PropertySource("${config.folder:'classpath:'}/application.properties")
public class AppConfig

For logback.xml:

@Value("${config.folder}:")
private String configFolder;

InputStream = Optional.of(new ClassPathResource(configFolder + "/logback.xml"))
    .filter(r -> r.exists())
    .orElse(new ClassPathResource("classpath:/logback.xml"))
    .getInputStream();

In both cases, I gave preference to the command line argument over the default packaged files. Of course, I didn't compile the above, so there may be typos or minor errors, but you get the idea.

Edit:

Since OP claims to not understand where to run the above code -

public class AppConfig {
    @PostConstruct
    void init() {
        // init logback here
    }
}