We are actually using Spring Boot's #ConfigurationProperties as basically a configuration mapper : it provides us an easy shortcut to map properties on objects.
#ConfigurationProperties("my.service")
public class MyService {
private String filePrefix;
private Boolean coefficient;
private Date beginDate;
// getters/setters mandatory at the time of writing
public void doBusinessStuff() {
// ...
}
}
Although this was a nice productivity boost when we were prototyping the app, we came to question if this was right usage.
I mean, configuration properties have a different status in Spring Boot's context, they're exposed through actuator endpoints, they can be used to trigger conditional beans, and seem more oriented toward technical configuration properties.
Question : Is it "correct" to use this mechanism on any business property/value, or is it plain misuse ?
Any potential drawback we missed ?
Right now our only concern is that we cannot use #ConfigurationProperties on immutable classes, which is closely related to this issue on Spring Boot's tracker : Allow field based #ConfigurationProperties binding
If your property represents something that is configurable based on the environment/profile that is what the mechanism is there for. Though I'm a little unclear what you mean by
"map properities on objects".
I would not favor this style in general, especially if your bean has multiple properties to set. A more standard idiom is to have a class that encapsulates the properties/settings used to create your bean:
#ConfigurationProperties("my.service")
public class MyServiceProperties {
private String filePrefix;
private Boolean coefficient;
private Date beginDate;
// getters/setters mandatory at the time of writing
}
then your Service class would look like this:
#EnableConfigurationProperties(MyServiceProperties.class)
public class MyService {
#Autowired
private MyServiceProperties properties;
//do stuff with properties
public void doBusinessStuff() {
// ...
}
}
This would at least allow you to pass the properties easily into an immutable class through it's constructor (make copies of any mutable properties). Also having the properties bean can be reused if you find other parts of your app need some shared configuration.
Related
Assume I have a configuration class accessible via the stock CDI that defines some application-wide parameters:
#ApplicationScoped
class AppConfig {
public double getMaxAllowedBrightness() { ... }
};
And I have a simple class for my data objects:
class LightSource {
double brightness;
...
boolean isValid() {
double maxAllowedBrightness = ...; // Somehow use AppConfig#getMaxAllowedBrightness() here
return brightness <= maxAllowedBrightness;
}
}
How can my data object access the single AppConfig instance?
Somehow I hate the idea of autowiring AppConfig into every single data object (there are lots of them). Is there any other way to get access to AppConfig in the above example from my data object?
What's the best pattern to use here?
The simplest example is a runtime lookup akin to:
import jakarta.enterprise.inject.spi.CDI;
CDI.current().select(cls).get();
With cls being the class that you're looking up. (Note the package name, this is the latest version of CDI 2.x in the new jakarta namespace, the original is in javax.)
It gets more detailed from there, but that's the gist of it.
Note, that semantically there's little difference between autowiring something and doing a runtime lookup, especially for something mostly static at the instance level. It's still a dependency. You still have to touch the code of the classes to pull it off.
A nice thing of relying on the autowiring is that you can disable it situationally, and the class reverts to a simple bean, that you can do with what you will. Coding in the lookup, it's a little bit more than that.
Dynamic lookup is more for special circumstances.
On my current project, our team has been doing this using the #Value annotation. In our case, we have all the properties in a properties bean, which I'll call mainAppConfiguration. The bean is populated from a properties file like main-app-config.properties (which was read into the bean with a Properties prop = new Properties().load(mainAppConfigFilePath) method.
Assuming you have something like that set up, then we inject the properties into the classes that need them using a little SpEL magic something like:
private Integer refreshRateSeconds;
#Value("#{ mainAppConfiguration.getProperties()['funny-property-base-name.refreshRateSeconds'] }")
public void setRefreshRateSeconds(Integer refreshRateSeconds) {
if (refreshRateSeconds == null) {
throw new IllegalArgumentException("Required config property 'funny-property-base-name.refreshRateSeconds' was not found"));
}
this.refreshRateSeconds = refreshRateSeconds;
}
Baeldung has examples (without defaults) and more with defaults.
Currently I'm working on a JSF2 + Spring application. And I need to have one component, which I would be able to autowire when needed and read/write the state (safely) from/to it.
In EJB I would do it as follows:
#Singleton
#ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class LocaleManager {
private String currentLanguage;
#Lock(LockType.READ)
public String getCurrentLanguage() {
return currentLanguage;
}
#Lock(LockType.WRITE)
public void setCurrentLanguage(String currentLanguage) {
this.currentLanguage = currentLanguage;
}
}
How can I achieve this in Spring? Thanks!
EDIT: One important thing is that application has multiple Maven modules and I need this in "core" module which doesn't depend on spring-web. I need the language information in DTO assemblers, where I would like to use only string values relevant to the current locale set in JSF. Entity has a set of translations for various languages (each DB table has own translation table). In the corresponding DTO I would like to have just e.g. "String description", instead of "Set<ItemTranslation> description".
In Spring the scope of the bean says how the instances are created. I suggest you to check out the following tutorial:
http://www.mkyong.com/spring/spring-bean-scopes-examples/
Probably i'll get a lot of downvotes, but it's so confusing for me all this fact of whether use beans or not. Lets suppose this example
interface ICurrency {
String getSymbol();
}
public class CurrencyProcessor {
private ICurrency currency ;
public CurrencyProcessor(ICurrency currency) {
this.currency = currency;
}
public void doOperation(){
String symbol = currency.getSymbol();
System.out.println("Doing process with " + symbol + " currency");
// Some process...
}
}
So, to inject the ICurrency impl injection i think that i can do it by two ways:
Way 1: Without Spring beans
public class CurrencyOperator {
private ICurrency currency ;
private CurrencyProcessor processor;
public void operateDefault(){
currency = new USDollarCurrency();
processor = new CurrencyProcessor(currency)
this.processor.doOperation();
}
}
Where USDollarCurrency is an ICurrency interface implementation
Way 2: Using Spring beans
#ContextConfiguration(classes = CurrencyConfig.class)
public class CurrencyOperator {
#Autowired private ICurrency currency ;
#Autowired private CurrencyProcessor processor;
public void operateDefault(){
this.processor.doOperation();
}
}
#Configuration
public class CurrencyConfig {
#Bean
public CurrencyProcessor currencyProcessor() {
return new CurrencyProcessor(currency());
}
#Bean
public ICurrency currency() {
return new USDollarCurrency();
}
I really don't understand what would be the benefits of using Spring's beans. I read some things but what i most found was about the benefits of using DI, and as i understand, both ways are injecting the dependency that CurrencyProcessor require, what is changing is the way that i am creating and using objets, am i wrong? So in concrete, my questions are:
1. What are the benefits of using Beans at this case?
2. Why should i use Spring instead of doing it manually like first way?
3. Talking about performance, which of this cases is better?
Suppose you have 2 DAO classes one for Oracle, the seconde for MySQL, and both classes are implementing a DAO interface. You define an implementation as a bean in Spring configuration file. In the business class you have an attribut of type DAO, while in the spring configuration file you choose the real type wheather Oracle or MySQL to inject or using spring annotation #Autowired
This reduce coupling and it will be easy to move from Oracle to MySQL.
#Service
public class Business {
#Autowired
private Dao daoImpl;
//Business methods that invoks Dao methods
}
In the Spring configuration file (XML file) you use the following:
<bean id="daoImpl" class="app.com.MySQLDaoImpl OR app.com.OracleDaoImpl"/>
By just changing the class attribut of your bean you change the whole implementation, without any change in your business class ! Good luck.
Your example without Spring doesn't dependency injection!
With dependency injection, the actual implementation of the interface is determined outside the code itself in order to reduce the coupling!
You should be able to need another implementation (you could for example switch from one JMS client to another...).
To answer to your last question, using Spring is (a very little bit) less performant but much more flexible.
EDIT :
Spring is not the only tool that can be used for DI but it is the most popular and it contains a lot of features. Note that many Java standards also (such as JPA) use DI.
Consider this example
#Stateless
public class UniqueIdGenerator {
private static final String COLON = ":";
private String serverPrivateKey;
#SuppressWarnings("UnusedDeclaration")
public UniqueIdGenerator() {
}
#Inject
public UniqueIdGenerator(#Nonnull final String serverPrivateKey) {
this.serverPrivateKey = serverPrivateKey;
}
...
}
I would like to #Inject value of serverPrivateKey based on an environment variable available in different environments.
What is the best way to inject it here?
To inject values from the environment, rather than writing your own producer methods, you may want to have a look at the Configuration API of Apache DeltaSpike.
Using a #ConfigProperty qualifier, you can inject values from a number of different property sources, like system properties, environment variables or JNDI.
Example:
#Inject
#ConfigProperty(name = "SERVER_PRIVATE_KEY")
private String serverPrivateKey;
We use the following pattern: There is a bean which gives us the value which we need. The bean knows how to get the value (environment, System property, whatever). To make things easier later, the type of the bean should be an interface (in your case that might be IPrivateKeyProvider).
The UniqueIdGenerator is then created and we inject the first bean. The setup then decides which bean this will be (some kind of mock for tests and a real implementation for production code).
You will have to use producer Method :
According to related oracle documentation :
A producer method generates an object that can then be injected. Typically, you use producer
methods in the following situations:
[...]
When the concrete type of the object to be injected may vary at runtime
See an example here
So I have a class like so:
public class HBaseUtil {
private final String fileName = "hbase.properties";
private Configuration config;
private HBaseUtil() {
try {
config = new PropertiesConfiguration(fileName);
} catch (ConfigurationException e) {
// some exception handling logging
}
}
// now some getters pulling data out of the config object
public static String getProperty(String fieldKeyName) {...}
public static String getColumnFamily(String fieldName) {...}
// ... some more getters
// NO setters (thus making this a read-only class)
}
Thus, basically I have for myself a Singleton class, that the very first time that it is put to use, sets up a configuration object, and then simply keeps listening for get calls. There are a number of problems with this class:
Unit testing the static methods within class HBaseUtil becomes difficult because of a tight-knit coupling between the Singleton and the configurations file.
What I really want is me being able to supply the filename/filename+path to the class so that it can go in there, read the configuration properties from that file and offer them to incoming read requests. One important note here though: I need this flexibility in specifying the properties file ONLY ONCE per JVM launch. So I certainly don't need to maintain state.
Here is what I was able to come up with:
Instead of a Singleton, I have a normal class with all static methods and no explicit constructor defined.
public class HBaseUtil {
// directly start with getters
public static String getProperty(Configuration config, String fieldKeyName) {...}
public static String getColumnFamily(Configuration config, String fieldKeyName) {...}
// ...and so on
}
And then, instead of using the class in my other code like such:
HBaseUtil.getProperty(String fieldKeyName)
I'd use it like so:
Configuration externalConfig = new PropertiesConfiguration("my-custom-hbase.properties");
HbaseUtil.getProperty(externalConfig, fieldKeyName)
My questions:
Am I even thinking in the right direction? My requirement is to have the flexibility in the class only ONCE per JVM. All that needs to be configurable in my project for this, is the location/contents of the HBase .properties file. I was thinking having a Singleton is overkill for this requirement.
What other better approaches are there for my requirement (stated in above point)?
Thanks!
Note: I've read this StackOverflow discussion, but now it's gotten me even more confused.
You should avoid all static methods and instead design a class which does not mandate its lifecycle: it can be a typical immutable POJO with a public constructor.
Then, when you need it as a singleton, use it as a singleton. For testing, use it in some other way.
Usually, dependency injection is the preferred avenue to solve these problems: instead of hard-coding a pulling mechanism for your configuration object, you have the object delivered to any class which needs it. Then you can decide late what bean you will deliver.
Since you are probably not using Spring (otherwise dependency injection would be your default), consider using Guice, which is a very lightweight and non-intrusive approach to dependency injection.