Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using @Profile annotation with property place holder value

When we define profile for any component in spring, we declare it as @Profile(value="Prod"). But i want to give that value from properties file. Is it possible? If yes, how?

like image 668
MasterCode Avatar asked Sep 01 '14 08:09

MasterCode


3 Answers

You seem to be trying to abuse the @Profile annotation. Use profiles for enabling functionality. Not for saying that a Bean is active in a specific environment.

A way to achieve something closer to what I think you are looking for, would be to have properties files specific to your environment, which define the profiles which should be active in them. This way, you can start your app with an arg such as:

--spring.profiles.active=prd

Spring Boot will then attempt to load application-prd.properties, where you could activate environment-specific profiles:

spring.profiles.active=sqlserver,activedirectory,exchangeemail

That way your beans will only be activated when the functionality they provide is required.

like image 143
Steve Avatar answered Oct 12 '22 04:10

Steve


Going through the source code of Spring, I have arrived to the conclusion that what you are asking is not possible. To make this clear, it is not possible to have Spring evaluate ${property} inside @Profile.

Specifically take a look at ProfileCondition which checks whether or not the profile is active.

class ProfileCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        if (context.getEnvironment() != null) {
            MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
            if (attrs != null) {
                for (Object value : attrs.get("value")) {
                    if (context.getEnvironment().acceptsProfiles(((String[]) value))) {
                        return true;
                    }
                }
                return false;
            }
        }
        return true;
    }

}

The meat is context.getEnvironment().acceptsProfiles(((String[]) value)).

Now if you check the source of AbstractEnvironment where acceptsProfiles resides, you will find that the control reaches

protected boolean isProfileActive(String profile) {
    validateProfile(profile);
    return doGetActiveProfiles().contains(profile) ||
            (doGetActiveProfiles().isEmpty() && doGetDefaultProfiles().contains(profile));
}

which does not attempt to evaluate the expression, but takes the String verbatim (also note that nowhere before isProfileActive is the String expression being evaluated either)

You can find the code I have mentioned above here and here.


One another note, I am not sure why you would need to have a dynamic profile name.

like image 25
geoand Avatar answered Oct 12 '22 03:10

geoand


An alternative would be when creating the ApplicationContext:

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ConfigClass.class);
String profile = aplicationContext.getEnvironemnt().getRequiredProperty("profile");
applicationContext.getEnvironment().setActiveProfiles(profile);
like image 38
Random42 Avatar answered Oct 12 '22 04:10

Random42