Friday, January 20, 2017

Use Spring profiles and yaml configuration without Spring Boot

That's a refinement you can do to updgrade legacy applications. Using yaml config files combines with Spring profiles is a great way to configure your apps. Let's see how to do that.

Firstly, let's consider that we weill inject something in a java class depending on the runtime  environment.

@Service
public class MyService {

@Value("${service.url}")
private String URL;

}

application.yaml should be like this :

service:
   url: http://alexdp.free.fr/violetumleditor

---
spring:
  profiles: production

service:
   url: http://violet.sourceforge.net


Thus, if I lauch my applicatin without JVM Spring profile params, URL will be http://alexdp.free.fr/violetumleditor. If I launch it with -Dspring.profiles.active=production, URL will be http://violet.sourceforge.net. Great! But this feature is natively supported only for Spring Boot based applications. So, let's active this on legacy apps with this XML spring config file fragment :

<bean id="yamlProperties"
class="org.springframework.beans.factory.config.YamlPropertiesFactoryBean">
<property name="resources">
<list>
<value>classpath:application.yml</value>
</list>
</property>
<property name="documentMatchers">
<bean
class="mypackage.SpringProfileDocumentMatcher" />
</property>
</bean>
<context:property-placeholder properties-ref="yamlProperties" />

Of course, you saw that we wrote our custom SpringProfileDocumentMatcher.

import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Properties;
import java.util.Set;

import org.springframework.beans.factory.config.YamlProcessor.DocumentMatcher;
import org.springframework.beans.factory.config.YamlProcessor.MatchStatus;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;


/**
 * Allows to use Spring profiles without Spring Boot for legacy Spring based apps
 * 
 * @author Alexandre de Pellegrin
 *
 */
public class SpringProfileDocumentMatcher implements DocumentMatcher, EnvironmentAware {

private static final String[] DEFAULT_PROFILES = new String[] { "default" };

private String[] activeProfiles = new String[0];

public SpringProfileDocumentMatcher() {
}

public SpringProfileDocumentMatcher(String... profiles) {
addActiveProfiles(profiles);
}

public void addActiveProfiles(String... profiles) {
LinkedHashSet set = new LinkedHashSet(
Arrays.asList(this.activeProfiles));
Collections.addAll(set, profiles);
this.activeProfiles = set.toArray(new String[set.size()]);
}

@Override
public MatchStatus matches(Properties properties) {
String[] profiles = this.activeProfiles;
if (profiles.length == 0) {
profiles = DEFAULT_PROFILES;
}
return new ArrayDocumentMatcher("spring.profiles", profiles).matches(properties);
}

@Override
public void setEnvironment(Environment environment) {
if (environment != null) {
       addActiveProfiles(environment.getActiveProfiles());
   }
}


private class ArrayDocumentMatcher implements DocumentMatcher {

private final String key;

private final String[] patterns;

public ArrayDocumentMatcher(final String key, final String... patterns) {
this.key = key;
this.patterns = patterns;

}

@Override
public MatchStatus matches(Properties properties) {
if (!properties.containsKey(this.key)) {
return MatchStatus.ABSTAIN;
}
Set values = StringUtils.commaDelimitedListToSet(properties
.getProperty(this.key));
for (String pattern : this.patterns) {
for (String value : values) {
if (value.matches(pattern)) {
return MatchStatus.FOUND;
}
}
}
return MatchStatus.NOT_FOUND;
}
}
}


That's it!

1 comment:

SATHYA TECH said...

Thank you for sharing such a nice and interesting blog with us.very unique and recommanded I would like to suggest your blog in my student circle

java training in hyderabad
java training institute in hyderabad
java training in ameerpet

Download Oracle JDK from command line

Found on the web. You can adapt the url with one grabbed from Oracle JDK download page. What I love here is the fact is send Oracle licence ...