Is it allowed to have instance variables in Spring Services? - java

I have a spring service that provides configuration data. When the service is invoked by the GUI, it loads the configuration data from the database. It turns out that this happens quite often during the rendering of a single request. I want to optimize this by caching the configuration data. However, I am not sure if this is a good programming style or if it is "allowed" to have an instance variable in a service.
Here is some example code of what I am thinking of doing:
#Serivce("MyConfigService")
public class MyConfigServiceImpl implements MyConfigService {
private Config cachedConfig;
#Override
public Config loadConfig() {
if (cachedConfig != null) {
// load config
cachedConfig = loadedConfig;
}
return cachedConfig;
}
#Override
public saveConfig(Config config) {
cachedConfig = null;
// save the configuration
}
}

Having a instance variable (not managed by spring) introduces the possibility of the service becoming thread unsafe. So I try to avoid them, or make sure they are thread safe.
You may want to look at #configurable and #postconstuct annotations to achieve your goals.

Are instance variables allowed in Spring service layer classes? Sure.
Is it a good idea to use one to save a reference to the Config object here?
Maybe, maybe not.
You're not showing how Config normally gets loaded... Does the same Config instance get returned to all users? i.e. - When User1 calls saveConfig then User2 calls loadConfig User2 gets the Config object User1 saved.
If so, you should be able to cache the value with no problems.
Also, instead of implementing it yourself, you could use Spring's annotation-based caching.

Instance variables is what Spring IoC container is all about; what is dubious in your design is that you have your own lazy-loading logic in loadConfig—that's the concern you must leave to Spring via lazy-init=true (or similar, I don't remember exactly). The design will also probably involve lookup methods and posibly request-scoped beans.

Related

Options for dynamic properties in Spring Boot

I have an application with some externalized configuration in the form of properties. I would like the application to react to a change of such properties without a restart or full context refresh.
I am not clear what my options are.
Artificial example: the application implements a service that receives requests and decides whether to queue or reject them. The maximum size of the queue is a property.
final int queueMaxSize = queueProperties.getMaxSize();
if (queue.size() >= queueMaxSize) { //reject }
Where QueueProperties is a class annotated with #ConfigurationProperties.
#ConfigurationProperties(prefix = "myapp.limits.queue")
#Getter
#Setter
public class QueueProperties {
public int maxSize = 10;
}
This works as far as allowing me to control behavior via system properties, profiles, etc.
However, I would like to be able to change this value without releasing/deploying/restarting/refreshing the application.
My application already uses Archaius.
If I push a new value for this property using our internal infrastructure, i can see the application Spring Environment does receive the new value.
(e.g., /admin/env reflects the value and changes dynamically).
The part I'm not clear on is: how to make my service react to the change of value in the environment?
I found two ways, but they seem hairy, I wonder if there are better options. I expected this to be a common problem with a first class solution in the Spring ecosystem.
Hacky solution #1:
#Bean
#Scope("prototype")
#ConfigurationProperties(prefix = "myapp.limits.queue")
QueueProperties queueProperties() {
return new QueueProperties();
}
And inject this into the service using the properties as Provider<QueueProperties> and use it as queuePropertiesProvider.get().getMaxSize().
This works but has a few side-effects I'm not a fan of:
ConfigurationProperties annotation moved from the class to the bean definition
A new QueueProperties object is created and bound to values for every request coming in
Provider might throw on get()
Invalid values are not detected until the first request comes in
Hacky solution #2:
Don't annotate my properties class with ConfigurationProperties, inject the Spring environment at construction time. Implement the getters as such:
int getMaxSize() {
return environment.getProperty("myapp.limits.queue", 10);
}
This also works ok in terms of behavior. However
- This is not annotated as property (unlike the rest of the properties classes in this large project, makes it harder to find)
- This class does not show up in /admin/configprops
Hacky solution #3:
Schedule a recurring task that uses Environment to update my singleton QueueProperties bean.
Any further ideas/suggestions/pointers?
Is there a canonical/recommended way to do this that does not have the shortcoming of my solutions above?

Spring lazy loading after bean is really called

I would like to have a (singleton) bean initialized only after it is actually used (instead of when it is only autowired). Let say I have a Client that I want to initialize only when I want to call any of its methods
#Component
#Lazy(true)
public class Client {
#PostConstruct
void init() {}
void action(){}
}
And I have a Service class that sometimes use it (and maybe sometimes not).
#Service
public class Service {
#Autowired
Client client;
void action1WithClient(){}
void action2WithClient(){}
void actionWithoutClient(){}
}
As it is now, the client is initialized right on the application startup without actually being used due to #Autowired and the fact that Service is eagerly loaded.
Currently only solution that comes to my mind is to do kind of double-checked locking with explicitly asking for Client bean from spring application context when someone tries to use (ie. without #Autowired) or (maybe even better) to do "manual" lazy loading inside the Client.
Question: Is there a "spring" way to postpone the initialization of client until any of its method is actually called (e.g. something like lazy loading is working for hibernate collections)?
I am using Spring 4.
Ah, ok, I should read the javadoc more properly... Solution seems to add anotation "each" autowired dependeny:
#Autowired
#Lazy
Client client;
Anyway - if anybody knows if it is possible to omit such declarations, since it might be error prone - one can easily forget to use #Lazy at each injection point.
Edit:
The easiest way is #ComponentScan(lazyInit = true, basePackages=...).
Previous answer:
There is http://docs.spring.io/spring/docs/3.0.x/javadoc-api/org/springframework/aop/target/LazyInitTargetSource.html
A bean wrapped with LazyInitTargetSource will not be created until the first actual usage.
How to nicely wrap most of your beans with this wrapper? One possible way is to create your own BeanFactoryPostProcessor...

Global object in Grails

Writing a small web-app in Grails I encountered a problem with global objects. I have a class which runs threads - ExecutorService with queuing.
The problem is where to create an object of this class, to have it available in Controller?
I've tried at init (BootStrap) but there's no chance then of getting its instance anywhere else.
In general - what I need is an object in one single instance for whole application, with access from Model and/or Controller.
In general - what I need is an object in one single instance for whole application, with access from Model and/or Controller.
The standard way to achieve this is to declare the object as a Spring bean in grails-app/conf/spring/resources.groovy
threadPool(java.util.concurrent.Executors) { bean ->
bean.factoryMethod = "newCachedThreadPool"
}
Then in controllers/services/etc. you can inject this bean the same as you would with grails services, i.e.
def threadPool
But in this case you may find it easier simply to use the executor plugin, which defines such a bean for you and handles the intricacies of ensuring there is a valid GORM session available to the background tasks.
Why not wrap your Executorservice inside a Spring Bean, or using something like:
grailsApplication.controllerClasses.each {controller ->
controller.metaClass.executorService = { ->
executorService
}
}
Actually I have come to something before checking answers.
For a given domain class (Example) and controller (ExampleController) create
ExampleService
and simply include all the needed things there. Set behaviour to #Singleton (default).
Then in Controller inject the instance as follows:
def exampleService

Should dependency be injected once or in every object

I'm trying to change some legacy code to use DI with Spring framework. I have a concrete case for which I'm wondering which is the most proper way to implement it.
It is a java desktop application. There is a DataManager interface used to query / change data from the data store. Currently there is only one implementation using a XML file for store, but in the future it is possible to add SQL implementation. Also for unit testing I may need to mock it.
Currently every peace of code that needs the data manager retrieves it by using a factory. Here is the source code of the factory:
public class DataManagerFactory
{
private static DataManagerIfc dataManager;
public static DataManagerIfc getInstance()
{
// Let assume synchronization is not needed
if(dataManager == null)
dataManager = new XMLFileDataManager();
return dataManager;
}
}
Now I see 3 ways to change the application to use DI and Spring.
I. Inject the dependency only in the factory and do not change any other code.
Here is the new code:
public class DataManagerFactory
{
private DataManagerIfc dataManager;
public DataManagerFactory(DataManagerIfc dataManager)
{
this.dataManager = dataManager;
}
public DataManagerIfc getDataManager()
{
return dataManager;
}
public static DataManagerIfc getInstance()
{
return getFactoryInstance().getDataManager();
}
public static DataManagerFactory getFactoryInstance()
{
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"com/mypackage/SpringConfig.xml"});
return context.getBean(DataManagerFactory.class);
}
}
And the XML with the bean description:
<bean id="dataManagerFactory"
class="com.mypackage.DataManagerFactory">
<constructor-arg ref="xmlFileDataManager"/>
</bean>
<bean id="xmlFileDataManager"
class="com.mypackage.datamanagers.xmlfiledatamanager.XMLFileDataManager">
</bean>
II. Change every class that is using the data manager so it takes it through the constructor and store it as a class variable. Make Spring bean definitions only for the "root" classes from where the chain of creation starts.
III. Same as II. but for every class that is using the data manager create a Spring bean definition and instantiate every such class by using the Spring Ioc container.
As I'm new to the DI concept, I will appreciate every advice what will be the correct and "best practice" solution.
Many thanks in advance.
Use option 3.
The first option keeps your code untestable. You won't be able to easily mock the static factory method so that it returns a mock DataManager.
The second option will force you to have the root classes know all the dependencies of all the non-root classes in order to make the code testable.
The third option really uses dependency injection, where each bean only know about its direct dependencies, and is injected by the DI container.
Well... why did you write the factory in the first place? Spring is not intended to make you change how you write code (not just to suit Spring that is), so keeping the factory is correct as it uses well-known pattern. Injecting the dependency into the factory will retain that behaviour.
Option 3 is the correct route to take. By using such a configuration you can usefully take components of your configuration and use them in new configurations, and everything will work as expected.
As a rule of thumb, I would expect one call to Spring to instantiate the application context and get the top-level bean. I wouldn't expect to make repeated calls to the Spring framework to get multiple beans. Everything should be injected at the correct level to reflect responsibilities etc.
Beware (since you're new to this) that you don't plumb in your data manager into every class available! This is quite a common mistake to make, and if you've not abstracted out and centralised responsibilities sufficiently, you'll find you're configuring classes with lots of managers. When you see you're doing this it's a good time to step back and look at your abstractions and componentisation.

SpringMVC How to obtain a bean from session scope when it's constructor is called

I'm pretty new to the Springframework (as you will guess) and ran into a situation, where help is desperatly needed.
I do hava a J2EE application here, running on tomcat with lots of old code. Anyway, we decided to use the Spring framework for certain tasks. For example we want to store a security object (containing the username and other authentication related properties) as a session scoped bean.
As there is plenty of old code calling the constructor of this "security object" my question is as following:
Will that object be obtained from the session (in any magic way spring is capable of) or will the constructor call generate a completely new object?
I've read something about "autowire mechanism"... would that help me any further?
Thanks for your answers and time!
If you use the new operator, then you are constructed the object yourself and the constructor is called. Spring is not involved when creating an object via new.
If your code creates an instance of the security object by calling the constructor of the class i.e. by calling new Security(), it will get a new instance everytime.
Declare a bean for your security object in your spring applicationContext.xml file. To make the security object session scoped, you'll need to declare its scope as session and make it a proxy:
<bean id="securityObject" class="com.xyz.Security" scope="session">
<aop:scoped-proxy /> <!-- important -->
</bean>
Now, instead of calling new Security(), the client will get the Security object from Spring application context (see line 1):
void someMethod() {
//...
Security securityObject = applicationContext.getBean("securityObject"); // 1
securityObject.doSomething(); // 2
//...
}
Spring will take care of creating instances of Security for each session. The object returned by the call at line 1 is not an actual Security object but instead it is a proxy object. When securityObject.doSomething() is called on line 2, the proxy object will look up the actual object created for that session and delegate the call to it. This will be managed by Spring.
Note that to get the bean at line 2, you will first need a handle to the ApplicationContext object. How you will get that object will depend on where the calling code is. Edit: An easy way to get it uniformly is by implementing the ApplicationContextAware interface.
Note: Instead of getting the bean from application context, you can get it wired by Spring, but that will require you to declare beans for all the clients that need the security object. Since you are modifying an existing application, I think the above approach is better.

Categories