tags:

views:

167

answers:

2

As I already have application.properties, where the database connection settings are defined, I decided it is good to put my application-specific settings in that file too. A step further - as spring reads those properties, I declared my Settings bean as follows

<bean name="settingsBean" class="com.tickets.constants.Settings">
    <property name="settings">
        <props>
            <prop key="backup.dir">${backup.dir}</prop>
            <prop key="smtp.host">${smtp.host}</prop>
        </props>
    <property>
 </bean>

Now, it happens sometimes, that I need some of those properties in classes that aren't directly in the spring context. Yes - I can either get the spring context from my web application context, or pass the settings as a method parameter to the utility classes, but here's my alternative approach (this is the Settings class):

private static Properties staticSettings;

@PostConstruct
public void init() {
    // making the settings available for static access
    staticSettings = settings;
}

Now, this looks a bit wrong. But I can't think of a strong reason for not using it. So to formulate the question - is there any reason not to use my approach, and is there a better one.

A: 

This is a good question, and I hope you get several informed and well-reasoned responses (better than the one I expect I'm writing).

The reasons for not using this approach are the same as for adopting the Spring framework in the first place: inversion of control, loose coupling, etc. That said, I feel that if you've considered those points in this context and nevertheless feel that this approach elegantly satisfies your actual needs, go right ahead.

Sometimes I feel that Spring -- indeed many leading frameworks & techniques -- allow themselves to slip into "my way or the highway" API design, where the only way to overcome the limitations of Spring is with more Spring.

It shouldn't be that way. You should be able to adopt a thing like Spring in an existing project without signing up to re-architect every bit of your app.

And in fact there are 365236 ways (yours in one) to share objects between the Spring and non-Spring worlds. There's no technical limitation; but the zealots will give you grief.

Drew Wills
Well, I'm a spring-zealot myself. Previously I've been using my own class that loads the properties from my file, but then I realized I have 2 files with settings, and the general principle is I should have one. So I rested upon spring's already-developed solution.
Bozho
It's no foul (IMHO) to have 2 files with config settings if each has a well-defined scope. But I suspect you're saying you had 2 files with the same info, in which case I share your view.I'm a big supporter of Spring too. I use it in everything.
Drew Wills
+1  A: 

You're right, your solution "feels" wrong - the interaction of statics and instance looks like an anti-pattern, but it's a bit of a slippery one to get a grip on.

My gut feeling would be to push the statics a bit further, and make the class itself more internally-consistent, without sacrificing the Spring integration:

public class Settings {

    private static Settings instance;

    public static Settings initialise(Properties settings) {
     instance = new Settings(settings);
     return instance;
    }

    public static Settings get() {
     return instance;
    }

    private final Properties settings;

    private Settings(Properties settings) {
     this.settings = settings;
    }

    public String getProperty(String key) {
     return settings.getProperty(key);
    }
}

Your Spring config would then use factory-method="initialise" rather than the constructor, and other code can use the static get() method to retrieve the singleton. You avoid duplication of the Properties object, and while the static singleton is a bit of an anti-pattern itself, the code makes rather more sense.

But that's the best I can come up with on a freezing cold Saturday morning :)

skaffman
and a snowy one, too? ;)I did it similar to your suggestion. But instead of using a factory-method, I used a @PostConstruct method, saying instance = this.
Bozho