Spring Framework
  1. Spring Framework
  2. SPR-8869

Introduce SystemEnvironmentPropertySource

    Details

    • Type: New Feature New Feature
    • Status: Closed
    • Priority: Minor Minor
    • Resolution: Complete
    • Affects Version/s: None
    • Fix Version/s: 3.1 RC2
    • Component/s: Core
    • Labels:
      None

      Description

      For background, see http://blog.springsource.org/2011/02/14/spring-3-1-m1-introducing-profile/#comment-223530 and http://www.linuxquestions.org/questions/linux-general-1/is-it-possible-to-set-an-environment-variable-name-containing-a-period-in-bash-724256/.

      The following is not possible in bash:

      $ spring.profiles.active=p1,p2 java -classpath ... MyApplication
      

      As bash does not support '.' in variable names:

      -bash: spring.profiles.active=p1,p2: command not found
      

      This means that it is currently not possible to set active or default profiles via the system environment if one is using bash. Nor is it possible to use the system environment for resolution of any other user-defined property using the PropertySource/Environment API developed as part of Spring 3.1.

      Note that this is possible under other shells, such as tcsh:

      % setenv spring.profiles.active p1,p2
      % java -classpath ... MyApplication
      

      There are several possible solutions, the simplest of which would be to change the property name from spring.profiles.active to spring_profiles_active or something similar that bash does not take issue with. However, this is undesirable, because it suggests that all properties to be resolved through the PropertySource mechanism should avoid '.' characters. This goes strongly against convention in java, where such naming is common (think about .properties files here. This 'solution' would also have the negative effect of breaking all existing applications running against 3.1 milestones and release candidates at this point, as well as all documentation and blog post that have been written about profile support and it's activation mechanisms.

      Therefore, the better solution is probably to provide custom support at the environment property source level, allowing for interchangeability of '.' and '_' characters. This would allow for the following:

      $ spring_profiles_active=p1,p2 java -classpath ... MyApplication
      

      as well as the following

      $ java -Dspring.profiles.active=p1,p2 -classpath ... MyApplication
      

      This would apply generally, such that a call to resolve property foo.bar, e.g.:

      env.getProperty("foo.bar")
      

      would return non-null assuming that the Environment object env contains a system environment PropertySource and there is an environment variable present named foo.bar or foo_bar.

      In the rare case that both variables foo.bar and foo_bar are present in the environment (possible under tcsh, for example), then the variable matching the original request will be the one returned. That is, a call to getProperty("foo.bar") will return the value of foo.bar, and a call to getProperty("foo_bar") will return the value of foo_bar.

      Appropriate debug logging will be added to inform the user when this is occurring.

      It may also make sense to allow for case-insensitivity when resolving properties against the system environment PropertySource, which will allow for more idiomatic invocation, e.g.:

      SPRING_PROFILES_ACTIVE=p1,p2 java -classpath ... MyApplication
      

      Javadoc will be updated to reflect these changes at the appropriate locations.

        Activity

        Hide
        jean added a comment -

        Definitely sounds like a good way to deal with the presence of "." in environment variable.

        But there is potentially a wider need to be adressed: when you have to run several applications on a single machine, each one needing it's own set of active profiles. A defined single spring.profiles.active can't be enough.

        It'd be nice to be able to specify the value of the variable that set default and active Spring profiles within Spring context.
        In the classic Spring spirit, when a convention doesn't suits your needs, you have the possibility to override it.

        Would that be a valuable requirement?

        Show
        jean added a comment - Definitely sounds like a good way to deal with the presence of "." in environment variable. But there is potentially a wider need to be adressed: when you have to run several applications on a single machine, each one needing it's own set of active profiles. A defined single spring.profiles.active can't be enough. It'd be nice to be able to specify the value of the variable that set default and active Spring profiles within Spring context. In the classic Spring spirit, when a convention doesn't suits your needs, you have the possibility to override it. Would that be a valuable requirement?
        Hide
        Chris Beams added a comment -

        Jean,

        If by "several applications on a single machine" you mean several independent java processes on a single machine, then you would simply set the environment variable on a process-by-process basis, e.g.:

        $ SPRING_PROFILES_ACTIVE=p1 java -classpath ... App1
        $ SPRING_PROFILES_ACTIVE=p2 java -classpath ... App2
        $ SPRING_PROFILES_ACTIVE=p3 java -classpath ... App3
        

        Or perhaps more preferably, specify -Dspring.profiles.active=p1,p2 to the java processes themselves. Either should work fine. Did you have some other use case in mind here?

        Show
        Chris Beams added a comment - Jean, If by "several applications on a single machine" you mean several independent java processes on a single machine, then you would simply set the environment variable on a process-by-process basis, e.g.: $ SPRING_PROFILES_ACTIVE=p1 java -classpath ... App1 $ SPRING_PROFILES_ACTIVE=p2 java -classpath ... App2 $ SPRING_PROFILES_ACTIVE=p3 java -classpath ... App3 Or perhaps more preferably, specify -Dspring.profiles.active=p1,p2 to the java processes themselves. Either should work fine. Did you have some other use case in mind here?
        Hide
        jean added a comment -

        Chris,

        this is the use case I had in mind.
        But my idea was precisely to avoid to have to specify the environment variable when starting application.

        This is especially useful when you only deploy a WAR on a running app server.
        Ideally you would be able to drop a WAR for deployment in a running appserver without even having to think about Spring profile.

        Each application can have its fixed dedicated environment variable on the machine they get deployed to.
        You just have to set it once.

        Show
        jean added a comment - Chris, this is the use case I had in mind. But my idea was precisely to avoid to have to specify the environment variable when starting application. This is especially useful when you only deploy a WAR on a running app server. Ideally you would be able to drop a WAR for deployment in a running appserver without even having to think about Spring profile. Each application can have its fixed dedicated environment variable on the machine they get deployed to. You just have to set it once.
        Hide
        Chris Beams added a comment -

        Jean,

        If I understand correctly, you're suggesting making configurable the key that used to specify active profiles.

        Currently, this key is named 'spring.profiles.active'. The proposal in this JIRA issue will relax the name of this key to be 'spring_profiles_active' or 'SPRING_PROFILES_ACTIVE' when working with system environment variables.

        Your proposal is to make it fully configurable, yes? e.g. 'myapp1_profiles_active', 'myapp2_profiles_active', 'foobar_x', etc.

        Where would this configuration occur? I should think that it would be more or less hard-coded within the application somewhere, would it not? I'm not sure that this level of configurability would be widely desirable. It would probably lead to a system that is hard to reason about, as any given environment variable could potentially affect the active profiles in a system – that is, it would not necessarily be clear to the casual developer or administrator which environment variable is responsible for spring profile activation. And the only way to know which environment variables do what would be to dig through war file, which would not be pleasant.

        Keep in mind that with profiles we have already introduced a significant new level of configurability into Spring. Adding another axis of configurability would probably be too much for the majority of users and only add confusion to the effort of documentation.

        Also keep in mind that environment variables are not your only option here. 'spring.profiles.active' can be specified in any of the following locations by default when working with a web application:

        • system environment variables
        • system properties
        • JNDI
        • servlet context-params
        • servlet config init-params

        And you can contribute additional property sources at will.

        Fundamentally, however, environment variables and system properties are really good for this sort of thing. They're naturally aligned with and specific to the application itself, and they are a configuration mechanism that every operator understands. I would encourage going the simple route here.

        Show
        Chris Beams added a comment - Jean, If I understand correctly, you're suggesting making configurable the key that used to specify active profiles. Currently, this key is named 'spring.profiles.active'. The proposal in this JIRA issue will relax the name of this key to be 'spring_profiles_active' or 'SPRING_PROFILES_ACTIVE' when working with system environment variables. Your proposal is to make it fully configurable, yes? e.g. 'myapp1_profiles_active', 'myapp2_profiles_active', 'foobar_x', etc. Where would this configuration occur? I should think that it would be more or less hard-coded within the application somewhere, would it not? I'm not sure that this level of configurability would be widely desirable. It would probably lead to a system that is hard to reason about, as any given environment variable could potentially affect the active profiles in a system – that is, it would not necessarily be clear to the casual developer or administrator which environment variable is responsible for spring profile activation. And the only way to know which environment variables do what would be to dig through war file, which would not be pleasant. Keep in mind that with profiles we have already introduced a significant new level of configurability into Spring. Adding another axis of configurability would probably be too much for the majority of users and only add confusion to the effort of documentation. Also keep in mind that environment variables are not your only option here. 'spring.profiles.active' can be specified in any of the following locations by default when working with a web application: system environment variables system properties JNDI servlet context-params servlet config init-params And you can contribute additional property sources at will. Fundamentally, however, environment variables and system properties are really good for this sort of thing. They're naturally aligned with and specific to the application itself, and they are a configuration mechanism that every operator understands. I would encourage going the simple route here.
        Hide
        jean added a comment -

        Correct, my proposal is to make it fully configurable, but only when the conventional key, spring_profiles_active is not enough.

        In this case, the configuration would occur in the Spring context, through XML/Annotation.
        I'm thinking of something in the line of @ActiveProfilesPropertyName("myapp_profiles_active") and the equivalent in XML.
        Hardcoded yes, but part of the Spring configuration, which is where you expect to find it.

        I agree, it would lead to a system that is harder to reason about. But only when you wishes it to become so. You only break the convention when you really need to, knowingly making it more complex.
        And if it makes it harder for the system designer on the one hand, it would ease the application usage for all the others. It would make it easier to hide the complexity for all the ones that don't need to understand it.

        In my team for instance, this would allow for a much smoother migration to the new Spring profile dependent system.
        If it is not fully configurable, providing different profile values are needed per application, then every developer will have to add a -Dspring.profiles.active to each every run/debug configuration, and to every Maven command.

        Moreover, on the testing platform, we frequently deploy the same application in 2 different flavors - which would translate in 2 Spring profiles - and they need to run on the same app server. In this case, without the configurable key, implementing a ApplicationContextInitializer, in order to read a non conventional key, becomes mandatory.

        These are only the few use cases I can think of, but I'm sure this level of configurability will be desirable.
        As long as conventions suit the majority, higher level of configurability is always desirable imho.

        Show
        jean added a comment - Correct, my proposal is to make it fully configurable, but only when the conventional key, spring_profiles_active is not enough. In this case, the configuration would occur in the Spring context, through XML/Annotation. I'm thinking of something in the line of @ActiveProfilesPropertyName("myapp_profiles_active") and the equivalent in XML. Hardcoded yes, but part of the Spring configuration, which is where you expect to find it. I agree, it would lead to a system that is harder to reason about. But only when you wishes it to become so. You only break the convention when you really need to, knowingly making it more complex. And if it makes it harder for the system designer on the one hand, it would ease the application usage for all the others. It would make it easier to hide the complexity for all the ones that don't need to understand it. In my team for instance, this would allow for a much smoother migration to the new Spring profile dependent system. If it is not fully configurable, providing different profile values are needed per application, then every developer will have to add a -Dspring.profiles.active to each every run/debug configuration, and to every Maven command. Moreover, on the testing platform, we frequently deploy the same application in 2 different flavors - which would translate in 2 Spring profiles - and they need to run on the same app server. In this case, without the configurable key, implementing a ApplicationContextInitializer, in order to read a non conventional key, becomes mandatory. These are only the few use cases I can think of, but I'm sure this level of configurability will be desirable. As long as conventions suit the majority, higher level of configurability is always desirable imho.
        Hide
        Chris Beams added a comment -

        Jean,

        Feel free to create a separate New Feature request for this, and distill the conversation here as you see fit. In any case, it's a separate (if related) change from the more limited improvement addressed by this particular issue. The new issue can remain open for further feedback, votes, etc.

        Thanks,

        Chris

        Show
        Chris Beams added a comment - Jean, Feel free to create a separate New Feature request for this, and distill the conversation here as you see fit. In any case, it's a separate (if related) change from the more limited improvement addressed by this particular issue. The new issue can remain open for further feedback, votes, etc. Thanks, Chris
        Hide
        Chris Beams added a comment -

        This is complete.

        commit efb07b7460807c8e0147119172531ed7587ca4b5
        Author: Chris Beams <cbeams@vmware.com>
        Date:   Thu Nov 24 16:53:37 2011 -0800
        
            Introduce SystemEnvironmentPropertySource
            
            Properties such as 'spring.profiles.active' cannot be specified at the
            command line under Bash and other shells due to variable naming
            constraints. This change allows for exchanging underscores for periods
            as well as capitalizing property names for more idiomatic naming when
            dealing with environment variables.
            
            For example, Spring will respect equally either of the following:
            
                spring.profiles.active=p1 java -classpath ... MyApp
            
                SPRING_PROFILES_ACTIVE=p1 java -classpath ... MyApp
            
            The former is not possible under Bash, while the latter is. No code or
            configuration changes are required; SystemEnvironmentPropertySource
            adapts for these varations automatically.
            
            SystemEnvironmentPropertySource is added by default as
            "systemEnvironment" to StandardEnvironment and all subtypes, taking the
            place of the plain MapPropertySource that was in use before this change.
            
            Issue: SPR-8869
        
        Show
        Chris Beams added a comment - This is complete. commit efb07b7460807c8e0147119172531ed7587ca4b5 Author: Chris Beams <cbeams@vmware.com> Date: Thu Nov 24 16:53:37 2011 -0800 Introduce SystemEnvironmentPropertySource Properties such as 'spring.profiles.active' cannot be specified at the command line under Bash and other shells due to variable naming constraints. This change allows for exchanging underscores for periods as well as capitalizing property names for more idiomatic naming when dealing with environment variables. For example, Spring will respect equally either of the following: spring.profiles.active=p1 java -classpath ... MyApp SPRING_PROFILES_ACTIVE=p1 java -classpath ... MyApp The former is not possible under Bash, while the latter is. No code or configuration changes are required; SystemEnvironmentPropertySource adapts for these varations automatically. SystemEnvironmentPropertySource is added by default as "systemEnvironment" to StandardEnvironment and all subtypes, taking the place of the plain MapPropertySource that was in use before this change. Issue: SPR-8869

          People

          • Assignee:
            Chris Beams
            Reporter:
            Chris Beams
            Last updater:
            Trevor Marshall
          • Votes:
            1 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:
              Days since last comment:
              2 years, 21 weeks, 4 days ago