Currently I am using a singleton class to read and load the propertied file. I get an instance of this in any class where I want to use a property value.
Would not it be better to use a static class instead which can be loaded once (when server started or something .. ) instead of using a singleton ? Why and why not ?
Moreover how can we load a static class OnServerStart or when war gets deployed.
PS: Project is web application
Singleton is better for dependency injection and unit testing than statics.
You may inject an instance of singleton class or a Mock of that type to any other class under test.
public class PropertiesHolder {
private static final PropertiesHolder INSTANCE = new PropertiesHolder();
private final Properties props;
private PropertiesHolder() {
props = load();
}
public static PropertiesHolder getInstance() {
return INSTANCE;
}
public String getProperty(String key) {
return props.getProperty(key);
}
private Properties load() {
...
}
}
Then you may mock PropertiesHolder in your test:
#RunWith(MockitoJUnitRunner.class)
public class MyTest {
#Mock private PropertiesHolder holder;
#Test
public void testSomething() {
SomeService service = new SomeService(holder);
when(holder.getProperty("foo")).thenReturn("bar");
String result = service.doSomething();
assertEquals(...)
}
}
For production code you may use:
new SomeService(PropertiesHolder.getInstance());
Or even better, use DI framework, e.g. Spring, for wiring a beans. PropertiesHolder would be a generic bean with factory method getInstance() and the scope 'singleton'.
If you're using Spring in your web application I'd suggest using with it's PropertyPlaceholderConfigurer.
If you don't want to use Spring for that and need to do some actions (e.g. loading property file) on servlet when webapp is started then use ServletContextListener as Bhesh Gurung has suggested.
Related
I am new to spring framework. I have to use spring boot and have a rest controller as below :-
#RestController
public class StatisticsController {
private TransactionCache transactionCache;
public StatisticsController(TransactionCache transactionCache) {
this.transactionCache = transactionCache;
}
#PostMapping("/tick")
public ResponseEntity<Object> addInstrumentTransaction(#Valid #RequestBody InstrumentTransaction instrumentTransaction) {
transactionCache.addTransaction(instrumentTransaction);
return new ResponseEntity<>(HttpStatus.CREATED);
}
and I have a class which needs to be singleton :-
#Component
public class TransactionStatisticsCacheImpl implements TransactionCache {
private static TransactionStatisticsCacheImpl instance;
public static TransactionStatisticsCacheImpl getInstance(){
if(Objects.isNull(instance)){
synchronized (TransactionStatisticsCacheImpl.class) {
if(Objects.isNull(instance)){
instance = new TransactionStatisticsCacheImpl();
}
}
}
return instance;
}
private TransactionStatisticsCacheImpl() {}
I want to know the correct way to call this singleton class in my rest controller. I know that by default the scope of a bean in spring is singleton. Is this the correct way to call the singleton class in rest controller?
#RestController
public class StatisticsController {
private TransactionCache transactionCache;
public StatisticsController(TransactionCache transactionCache) {
this.transactionCache = transactionCache;
}
#PostMapping("/tick")
public ResponseEntity<Object> addInstrumentTransaction(#Valid #RequestBody InstrumentTransaction instrumentTransaction) {
transactionCache.addTransaction(instrumentTransaction);
return new ResponseEntity<>(HttpStatus.CREATED);
}
or
We need to call it using the getInstance() method? Also do we need to explicitly have the getInstance method in the TransactionStatisticsCacheImpl class?
One of the major advantages of container injection is that you can get the benefits of singleton semantics without all the serious problems of "hard" singletons (such as difficulty testing). Get rid of the getInstance manual business and let Spring take care of ensuring that a single instance is created and used for the context.
Just for clarification: By default, the spring IOC container will create only one instance per bean definition, unless if you specified otherwise using the #Scope stereotype. But if you create an instance using getInstance() the bean pre-processors and post-processors will not work correctly on that bean definition. And also you can use the #Autowired stereotype to inject a bean definition as needed and if you have different implementations for the same definition you can use the #Qualifier stereotype to specify the implementation that you need to inject, alternatively, you can use the constructor injection to inject your bean definition as needed without auto wiring as mentioned here Spring #Autowire on Properties vs Constructor
I would stick to the answers above. However, if you want to preserve further instantiation of the class in your code (or you want to keep your specific implementation of singleton), you can do it with getInstance().
Firstly, get rid of #Component annotation in your class:
// #Component
public class TransactionStatisticsCacheImpl implements TransactionCache {
private static TransactionStatisticsCacheImpl instance;
public static TransactionStatisticsCacheImpl getInstance(){
if(Objects.isNull(instance)){
synchronized (TransactionStatisticsCacheImpl.class) {
if(Objects.isNull(instance)){
instance = new TransactionStatisticsCacheImpl();
}
}
}
return instance;
}
private TransactionStatisticsCacheImpl() {}
}
Then, you may instantiate your singleton #Bean by defining #Configuration class - this way your bean would get managed by spring container.
#Configuration
public class SingletonConfiguration {
#Bean
public TransactionCache transactionCache() {
return TransactionCacheImpl.getInstance();
}
}
Eventually, you can have your singleton injected in your RestController using #Autowired.
#RestController
public class StatisticsController {
private TransactionCache transactionCache;
#Autowired
public StatisticsController(TransactionCache transactionCache) {
this.transactionCache = transactionCache;
}
#PostMapping("/tick")
public ResponseEntity<Object> addInstrumentTransaction(#Valid #RequestBody InstrumentTransaction instrumentTransaction) {
transactionCache.addTransaction(instrumentTransaction);
return new ResponseEntity<>(HttpStatus.CREATED);
}
}
I have this web application built with Spring and Vaadin, in which I wanted to do this, for the sake of convenience:
Create a utility class that wraps a Spring service, and allows the use of its static methods throughout the application, without having to worry about injecting this service everywhere, like so:
String configurationValue = ConfigurationUtil.getString("some.property.key");
If you work with Vaadin, you might see how convenient this is, because the whole presentation layer is written in Java and you can't always inject Spring services into your Vaadin components as these Vaadin components are not always Spring components themselves.
So this is my utility class:
public final class ConfigurationUtil {
// this is the spring service:
private static ConfigurationService configurationService;
public static void setConfigurationService(final ConfigurationService configurationService) {
ConfigurationUtil.configurationService = configurationService;
}
public static String getString(final String key) {
return configurationService.getString(key);
}
}
This is my service:
#Service("configurationService")
public class ConfigurationServiceImpl implements ConfigurationService, BeanFactoryAware {
private final FrameworkService frameworkService;
#Autowired
public ConfigurationServiceImpl(final FrameworkService frameworkService) throws IOException, ConfigurationException {
// this is where I set this service bean to the utility class
ConfigurationUtil.setConfigurationService(this);
this.frameworkService = frameworkService;
}
public String getString(String key) {
// code that retrieves a configuration value from our configuration files
}
}
My question here is: I'm a bit worried about this causing a bottleneck to access the configuration service, as multiple threads will be calling it, from multiple user sessions. Would this be a problem? Please explain why. Also, feel free to point out other problems with this solution.
I suggest to create a bean that implements ApplicationContextAware like this:
#Component
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext ac) {
context = ac;
}
public static String getString(final String key) {
ConfigurationService configurationService = context.getBean(ConfigurationService.class);
return configurationService.getString(key);
}
public static <T> T bean(Class<T> beanType) {
return context.getBean(beanType);
}
}
You can create a method like in the example to give static access to Spring Beans or what you requested to get a String from your ConfigurationService.
Btw. I use this a lot in Vaadin applications because I don't want to make every component a Spring Bean.
Currently I'm trying to Implement a utility Class that generates an invoice in a PDF Format and I predict that I'll need spring beans to be injected in my Utility Class Afterwards.
But I don't need the class to be instanciated, I only need the methods. So for me it's a dilemma
So I did some research and I still haven't made my mind If I want a spring singleton bean or .
Spring Singleton : Source
#Service
public class Singleton {
private static AtomicReference<Singleton> INSTANCE = new AtomicReference<Singleton>();
public Singleton() {
final Singleton previous = INSTANCE.getAndSet(this);
if(previous != null)
throw new IllegalStateException("Second singleton " + this + " created after " + previous);
}
public static Singleton getInstance() {
return INSTANCE.get();
}
}
Or A final Class :
public final InvoiceUtil {
private InvoiceUtil() {}
public static String convertToPDF (Template template) {
//Do the work
}
}
but with the second approach, my class isn't managed by Spring so I can not inject beans to it.
Make me undrestand !! :p
If you use a Spring bean, do not implement Spring Service as a Singleton with getInstance(). Just add #Service and Spring will only instantiate it once.
You can use static methods, and later pass any dependency also to these methods (if those are few dependencies):
public static String convertToPDF (Template template, NeededHelper helper) {
...
}
I am using Spring MVC. I have a UserService class annotated with #Service that has a lot of static variables. I would like to instantiate them with values from the application.properties file.
For example in application.properties I have: SVN_URL = http://some.url/repositories
Then in the class there is: #Value("${SVN_URL}") private static String SVN_URL
I get the Instantiation of bean failed; nested exception is java.lang.ExceptionInInitializerError
I have also tried #Autowired private static Environment env;
And then: private static String SVN_URL=env.getProperty("SVN_URL");
It gives the same error.
Think about your problem for a second. You don't have to keep any properties from application.properties in static fields. The "workaround" suggested by Patrick is very dirty:
you have no idea when this static field is modified
you don't know which thread modifies it's value
any thread at any time can change value of this static field and you are screwed
initializing private static field that way has no sense to me
Keep in mind that when you have bean controlled by #Service annotation you delegate its creation to Spring container. Spring controls this bean lifecycle by creating only one bean that is shared across the whole application (of course you can change this behavior, but I refer to a default one here). In this case any static field has no sense - Spring makes sure that there is only one instance of UserService. And you get the error you have described, because static fields initialization happens many processor-cycles before Spring containers starts up. Here you can find more about when static fields are initialized.
Suggestion
It would be much better to do something like this:
#Service
public class UserService {
private final String svnUrl;
#Autowired
public UserService(#Value("${SVN_URL}") String svnUrl) {
this.svnUrl = svnUrl;
}
}
This approach is better for a few reasons:
constructor injection describes directly what values are needed to initialize the object
final field means that this value wont be changed after it gets initialized in a constructor call (you are thread safe)
Using #ConfigurationProperties
There is also another way to load multiple properties to a single class. It requires using prefix for all values you want to load to your configuration class. Consider following example:
#ConfigurationProperties(prefix = "test")
public class TestProperties {
private String svnUrl;
private int somePort;
// ... getters and setters
}
Spring will handle TestProperties class initialization (it will create a testProperties bean) and you can inject this object to any other bean initialized by Spring container. And here is what exemplary application.properties file look like:
test.svnUrl=https://svn.localhost.com/repo/
test.somePort=8080
Baeldung created a great post on this subject on his blog, I recommend reading it for more information.
Alternative solution
If you need somehow to use values in static context it's better to define some public class with public static final fields inside - those values will be instantiated when classloader loads this class and they wont be modified during application lifetime. The only problem is that you won't be able to load these values from Spring's application.properties file, you will have to maintain them directly in the code (or you could implement some class that loads values for these constants from properties file, but this sounds so verbose to the problem you are trying to solve).
Spring does not allow to inject value into static variables.
A workaround is to create a non static setter to assign your value into the static variable:
#Service
public class UserService {
private static String SVN_URL;
#Value("${SVN_URL}")
public void setSvnUrl(String svnUrl) {
SVN_URL = svnUrl;
}
}
Accessing application.properties in static member functions is not allowed but here is a work around,
application.properties
server.ip = 127.0.0.1
PropertiesExtractor.java
public class PropertiesExtractor {
private static Properties properties;
static {
properties = new Properties();
URL url = new PropertiesExtractor().getClass().getClassLoader().getResource("application.properties");
try{
properties.load(new FileInputStream(url.getPath()));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public static String getProperty(String key){
return properties.getProperty(key);
}
}
Main.class
public class Main {
private static PropertiesExtractor propertiesExtractor;
static{
try {
propertiesExtractor = new PropertiesExtractor();
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
public static getServerIP(){
System.out.println(propertiesExtractor.getProperty("server.ip")
}
}
static String profile;
#Value("${spring.profiles.active:Unknown}")
private void activeProfile(String newprofile) {
profile = newprofile;
};
In order to gain static access to Spring Boot properties you can create a Properties Holder Component which implements the Command Line Runner interface. The command line runner interface executes run() upon component instantiation by Spring Boot.
Since we have autowired access to our properties object in the PropertiesHolder component, it is possible to assign the autowired properties to a static Properties class variable upon CommandLineRunner execution of the run() method.
At this point any class can statically call PropertiesHolder.getProperties() to access the contents of Spring Boot properties values.
PropertiesHolder.class:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
#Component
public class PropertiesHolder implements CommandLineRunner {
//Spring Boot Autowired Properties Object
#Autowired MyProperties myAutowiredProperties;
//Statically assigned Properties Object
private static MyProperties properties;
//Hide constructor (optional)
private PropertiesHolder(){}
public static MyProperties getProperties() throws NullPointerException{
if(PropertiesHolder.properties == null)
throw new NullPointerException("Properites have not been initialized by Spring Application before call.");
return PropertiesHolder.properties;
}
//Use to assign autowired properties to statically allocated properties
public static void makeAvailable(MyProperties myAutowiredProperties){
PropertiesHolder.properties = myAutowiredProperties;
}
//Spring Boot command line runner autoexecuted upon component creation
//which initializes the static properties access
public void run(String... args) {
PropertiesHolder.makeAvailable(myAutowiredProperties);
}
}
MyProperties.class
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
//Example: your_properties_file_prefix.properties
#ConfigurationProperties(prefix = "YOUR_PROPERTIES_FILE_PREFIX")
#Component
#Data
public class MyProperties {
private String property1;
private String property2;
private String property3;
}
At least one more simple solution with configuration file:
#Configuration
public class YourStaticPropertyConfiuration {
public static String PROPERTY_NAME;
#Value("${propertyName}")
public void setProperty(final String propertyName) {
PROPERTY_NAME = propertyName;
}
}
Use PROPERTY_NAME anywhere as static variable
For all those who, for whatever reason, want to provide setting properties imported from files as static properties, here is a solution that is as simple and safe as possible.
The Problem:
Spring Boot unfortunately doesn't provide a simple way to import properties from a file and bind them as static properties to a class. One possible solution to achieve that anyway would be to set the static properties using `#Value` annotations like this:
public class GlobalProperties {
public static String NAME;
#Value("${configs.boss.name}")
public void setName(String name) {
NAME = name;
}
}
However, this approach would mean that the static properties cannot be declared as final.And we certainly don't want that.
The Solution:
application.yml:
configs:
boss:
name: "Leeloo Multipass"
ConfigProperties.java:
#Validated
#ConfigurationProperties(prefix = "configs")
public record ConfigProperties(#NotNull Boss boss) {
public static final String BOSS_NAME = BOSS.NAME;
private static class Boss {
private static String NAME;
public Boss(String name) {
NAME = name;
}
}
}
The solution is based on the assumption that Spring Boot builds the configuration objects first, and the properties' configuration objects first of all. So at the time Spring Boot adds the prepared objects as Bean to the context, the nested classes are already setup and the static properties initialization of ConfigProperties can access the static properties of the nested classes (which still are not final, but also not accessible from outside). This way it is possible to provide all properties declared as static final. Unless Spring Boot doesn't decide to change its internal initialization process, everything is cream & cookie.
This approach was tested with Spring Boot 3 and Java 17. It is of course possible to provide the properties additionally via the configs-bean. For that, the properties of the nested classes must be explicitly specified and their corresponding getters must be implemented. In this case, some simplification can be achieved by using records instead of classes.
I am developing a Java API for a service and I want to extract it to a library.
I am using spring 4.3.3
Right now there is a bean called ApiConfig which is simple pojo.
public class ApiConfig {
private String host;
private String username;
private String password;
}
and the values are read from a properties file.
I would like to be able to construct and provide this class before the context starts (several components have this class as #Autowired dependency).
For instance:
public class LoginService {
#Autowired
private ApiConfig apiConfig
[...]
}
Basically, I would like to do something like this:
public static MyApi get(ApiConfig apiConfig) {
//Here I want to provide this apiConfig as singleton bean that would be used everywhere
provide somehow this class as bean
// here all beans are loaded and the it fails because it cannot resolve ApiConfig
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ContextConfig.class);
MyApi myApi= context.getBean(MyApi.class);
return myApi;
}
The method MyApi.get(AppConfig) would be used by other java applications by adding dependency in pom.xml
Is there a way I can do this? Providing the ApiConfig bean and then initialize all the application?
Basically to let Spring know that there is also this bean, before starting context with new AnnotationConfigApplicationContext(ContextConfig.class)
UPDATE
The idea would be this, in any application using this library.
public static void main(String asdas[]) {
ApiConfig config = new ApiConfig();
config.setUsername("BOBTHEUSER");
//config.set etc
MyApi api = MyApi.get(config);
api.doOperation();
Actually #Autowire is enough. Make the ApiConfig a Bean and autowire it where it's is necessary. Spring resolves the proper order.
If you have two beans and one need the second to be initialized before creation use #DependsOn annotation
#Configuration
public class MainConfig {
#Autowired
private ApiConfig apiConfig
#Bean(name="apiConfig")
public ApiConfig apiConfig(){
... init the config ...
return apiConfigInstance;
}
#Bean(name="myApi")
#DependsOn("apiConfig")
public MyApi myApi(){
MyApi api = new MyApi(apiConfig);
return api;
}
}
Code from the example modified