What happens when Spring #Bean is stored in a ThreadLocal? - spring

Given the following configuration:
#Configuration
class TLConfig {
#Bean
fun foo() = tl.getOrSet { Foo("something") }
private val tl = ThreadLocal<Foo>()
}
Will there only be one instance of Foo created or will there be an instance created for each thread that wants the bean?
If only one instance created, what happens when different threads try to use it?
DISCLAIMER: I am not looking for suggestions of what to do instead. I just want to know how this code would behave. I am not suggesting that this is a good or bad way to do things, it is just something I found, and I have no idea what the behavior is.

It creates one instance (default scope is singleton) and put it into the application context. So when you inject it, it will comes from there, no matter which thread ask the dependency. The foo function only called once, when the bean is initialized.

Related

Spring 5 State Based Bean Injection - possible?

I am trying to find some 'controller' (not #Controller) within Spring 5.0 that is responsible to resolve what instance of an implementation to inject within Spring. I want to provide my own implementation of that controller (or to extend it), so that I can add my own logic for state-based bean resolution.
For example, given some interface Foo, with implementation FooImpl1 and FooImpl2, and some state Baz.
Then, when Baz = 1, I want to step into my own logic to decide to provide FooImpl1 instead of FooImpl2 for the required inject of Foo implementation.
Spring does this today, the logic seems to be:
Given the need to inject class X, find its implementations
If only one of X is found, use that
If more than one X is found, use Primary
If more than one X is found and no Primary, find Qualifier
If more than one X if found and no Primary and no Qualifier, attempt to match X with property or parameter X by name (ie: don't inject Y if the parameter or property is x and not y).
What I want to do is at some point in the logic above, to invoke my own disambiguation/resolution of the required implementation to be injected, based on my own logic and state.
So, before I go and dig into Spring to locate where that logic is implemented, I am hoping to find that it is implemented in some controller/service that I can extend, best still if this is backed by some configuration...
You can implement your own #Configuration that returns a Spring #Bean:
#Configuration
public class Config {
private final Baz baz;
#Autowired
Config(Baz baz) {
this.baz = baz
}
#Bean
public Foo getFoo() {
switch (baz) {
case 1:
return new FooImpl1();
default:
return new FooImpl2();
}
}
}
Please also read the paragraph about Full #Configuration vs “lite” #Bean mode?. The last paragraph states that:
In common scenarios, #Bean methods are to be declared within #Configuration classes, ensuring that “full” mode is always used and that cross-method references therefore get redirected to the container’s lifecycle management. This prevents the same #Bean method from accidentally being invoked through a regular Java call, which helps to reduce subtle bugs that can be hard to track down when operating in “lite” mode.
It seems what I am looking for are the interfaces BeanFactory and most likely ConfigurableBeanFactory. There are still some things to work through off-course, but this definitely is the right direction.
For those immediately curious as to what I am talking about ... see https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/config/ConfigurableBeanFactory.html

How to use #Autowired correctly in spring boot standalone app

I've learned a lot recently about Spring and one thing i think i might be misunderstanding is the #Autowired annotation, especially when using it in constructors. You see, the app i'm developing is a service so basically EVERYTHING is initialized within a constructor. The only actual user-driven events that happen are buttons that restart certain modules of the service. This is my main method :
ConfigurableApplicationContext ctx = new SpringApplicationBuilder(MDHIS_Service.class)
.headless(false).web(false).run(args);
java.awt.EventQueue.invokeLater(() ->
{
MDHIS_Service frame = ctx.getBean(MDHIS_Service.class);
frame.setSize(1024, 768);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
This is the constructor of my main class, where basically everything happens. I have omitted the calls to the methods initializing each module to shorten it :
#Autowired
public MDHIS_Service(GlobalParamService globalParamService, LogEntryService logentryService, InterfaceService interfaceService,
ConnectionService connectionService, OutboundMessageService outboundMessageService, OutboundMessageHistoryService outboundMessageHistoryService,
InboundMessageService inboundMessageService, FacilityService facilityService, ModuleStatusService moduleStatusService,
SequenceService sequenceService)
{
this.globalParamService = globalParamService;
this.logEntryService = logentryService;
this.interfaceService = interfaceService;
this.connectionService = connectionService;
this.outboundMessageService = outboundMessageService;
this.outboundMessageHistoryService = outboundMessageHistoryService;
this.inboundMessageService = inboundMessageService;
this.facilityService = facilityService;
this.moduleStatusService = moduleStatusService;
this.sequenceService = sequenceService;
}
My main class has a private final global variable for each service. Each module is a separate thread and i'm finding myself having to pass those variables to the constructor of each module which in term stores them into it own private final variables. The way i'm doing things right now #Autowired is pretty much useless since i'm having to pass the instance around. Is there a way to better use #Autowired? This service is used as the backend for a large web app and i find myself making much better use of the annotation in there. I did a lot of research on this topic and i did try the #PostContruct annotation but all i ever got was null services.
Any help would be appreciated.
Thanks!
I figured out my problem, and it was a pretty dumb one. First off, i had not annotated my main class with #Component so Spring never bothered to inject the dependencies in it. Secondly, I did not realize that a method annotated with #PostContruct would run by itself after the constructor runs WITHOUT NEEDING TO EXPLICITELY BE CALLED!
I moved all my initialization code to an init method annotated with #PostConstruct and annotated my main class with #Component, everything is working now!
You typicall don't have to use a constructor + #Autorwired, you can directly use autowired on fields and spring would fill the dependencies for you:
#Component
public class MDHIS_Service {
#Autowired
private GlobalParamService globalParamService;
}
What is important to understand is that for spring to work, you must let it create the objects for you, and not calling the constructors explicitely. It would then fill the dependencies as needed. This is done by declaring the service as a component (for example with the #Component annotation) and never create the service yourself but getting them from dependency injection.
The first object you start with has to have been created by spring and returned by the application context.
What you gain in exchange is that you don't have to forwared everything explicitely. A sub-sub-sub service quite distant from the root of the application can depend on anything it has visibility without you having to forward the reference all the way.
I would advise to take a look a the spring reference documentation, it quite detailled and complete:
https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#spring-core
Edit: I'll try to clarify a bit with an example... What do the init code of the various service actually does ?
Maybe it set the dependencies. Then just autowire them:
#Component
MySubService {
#Autowired MySubSubService mySubSubService;
}
Maybe it does some more thing than setting fields so you can add on top an init method that do it and this init method can eventually call the other services.
#Component
MySubService {
#Autowired MySubSubService mySubSubService;
#PostConstruct
public void init() {
//Init code that may use mySubSubService.
}
}
You don't have to declare a constructor and forward dependencies yourself, sprint does it for you.
The only case where you'd have problem is if finally you need some parameters that are not dependency to the init method. But even in that case you could do it from you main code. That's actually what you did with the main service calling the various setters rather than messing with the constructor to set theses values.

Spring autowiring based on service availability

I have a need of conditionally creating one of three possible implementations of a service depending upon the environment detected by a Spring application at runtime. If Service A is available, then I want to create a concrete implementation class that uses Service A as a dependency. If Service A is not available, then I want to create an implementation using Service B as a dependency. And so-on.
Classes which depend on the implementation will Autowire the Interface and not care what the underlying Service was that got selected for the particular environment.
My first stab at this was to implement multiple #Bean methods which either return a bean or null, depending on whether the Service is available, and to then have a separate #Configuration class which #Autowire(required=false) the two possible services, conditionally creating the implementation depending on which of the #Autowired fields was not-null.
The problem here is that when required=false, Spring doesn't appear to care whether it waits around for candidates to be constructed; that is to say, the class which tries to pick the implementation might be constructed before one or both of the required=false Beans gets constructed, thus ensuring that one or both might always be null, regardless of whether it may manage to initialize correctly.
It kind of feels like I'm going against the grain at this point, so I'm looking for advice on the "right" way to do this sort of thing, where a whole set of beans might get switched out based on the availability of some outside service or environment.
Profiles don't look like the right answer, because I won't know until after my Service beans try to initialize which implementation I want to choose; I certainly won't know it at the time I create the context.
#Order doesn't achieve the goal either. Nor does #Conditional and testing on the existence of the bean (because it still might not be constructed yet). Same problem with FactoryBean- it does no good to check for the existence of beans that might not have been constructed at the time the FactoryBean is asked to create an instance.
What I really need to do is create a Bean based on the availability of other beans, but only AFTER those beans have at least had a chance to try to initialize.
Spring Profiles is your friend. You can set the current profile by way of environmental variable, command-line argument, and other methods. You can annotate a Spring-managed component so that it's created for a certain profile.
Spring Profiles from the Spring Documentation
Well in this case it turned out to be a tangential mistake that influenced the whole wrong behavior.
To give some background, my first, naive (but workable) approach looked like this:
#Autowired(required=false)
#Qualifier(RedisConfig.HISTORY)
private RLocalCachedMap<String, History> redisHistoryMap;
#Autowired(required=false)
#Qualifier(HazelcastConfig.HISTORY)
private IMap<String, History> hazelcastHistoryMap;
// RequestHistory is an interface
#Bean
public RequestHistory requestHistory() {
if (redisHistoryMap != null) {
return new RedisClusteredHistory(redisHistoryMap);
} else if (hazelcastHistoryMap != null) {
return new HazelcastClusteredHistory(hazelcastHistoryMap);
} else {
return new LocalRequestHistory(); // dumb hashmap
}
}
In other #Configuration classes, if the beans that get #Autowired here aren't available (due to missing configuration, exceptions during initialization, etc), the #Bean methods that create them return null.
The observed behavior was that this #Bean method was getting called after the RLocalCachedMap<> #Bean method got called, but before Spring attempted to create the IMap<> by calling its #Bean method. I had incorrectly thought that this had something to do with required=false but in fact that had nothing to do with it.
What actually happened was I accidentally used the same constant for both #Bean names (and consequently #Qualifiers), so presumably Spring couldn't tell the difference when it was calculating its dependency graph for this #Configuration class... because the two #Autowired beans appeared to be the same thing (because they had the same name).
(There's a secondary reason for using #Qualifier in this case, which I won't go into here, but suffice it to say it's possible to have many maps of the same type.)
Once I qualified the names better, the code did exactly what I wanted it to, albeit in a way that's somewhat inelegant/ugly.
At some point I'll go back and see if it looks more elegant / less ugly and works just as well to use #Conditional and #Primary instead of the if/else foulness.
The lesson here is that if you explicitly name beans, make absolutely sure your names are unique across your application, even if you plan to swap things around like this.

#PostConstruct fails silently on a Grails Service

I thought the Spring annotations were supposed to work out of the box in a Grails environment, but I cannot get it to work at all. I also tried the afterProperties method, which did not work either.
Can anyone spot a mistake? Is there some configuration I need to do?
package dashboard
import javax.annotation.PostConstruct
class EmailJobSchedulerService
{
def grailsApplication
#PostConstruct
def init() {
def cronExpression = grailsApplication.config.emailAt8AmTrigger
println(cronExpression)
EmailSubscribersJob.schedule(cronExpression, new HashMap())
}
}
Try changing it to
#PostConstruct
void init() {
(i.e. void instead of def). I'm not sure whether Spring specifically enforces this but the specification of #PostConstruct states that among other things "The return type of the method MUST be void".
Edit: uchamp's comment is correct, I just tried the same test and indeed the #PostConstruct annotated method is called only the first time the service bean is used and, not necessarily immediately at startup. You can add
static lazyInit = false
to the service class to force it to be initialized eagerly at startup. This doesn't appear to be documented in the user guide, I deduced it by reading the code.
Note that "used" in the previous paragraph doesn't necessarily mean you have to call a method on it. The service bean will be initialized the first time it is fetched from the application context, either directly or because it has been autowired into another bean that is being initialized. For example, injecting the service into BootStrap using
def emailJobSchedulerService
would be enough to fire the #PostConstruct method, you don't have to actually call any of the service's methods from the BootStrap.init closure. Similarly, if your service were injected into any controllers then the init would fire the first time one of those controllers handled a request (any request, it doesn't have to be an action that calls the service).
Just adding on the answer from #Ian - For some reason i had:
#PostConstruct
private void init() {
This also failed silently and gave strange behavior. Solution was to remove "private":
#PostConstruct
void init() {

Ask Spring for a Prototype instance of a Singleton Bean?

I have a number of Grails Services that are singleton Spring beans, not prototypes.
Is there any way to retrieve a prototype instance (fully injected with any dependencies) of what is normally a singleton bean?
I'd like this for testing purposes so that I can mess with the prototype instance (potentially changing it's metaClass to mock things out) without the risk of forgetting to clean up after any changes I make to the instance and having them leak into other tests.
I've been playing around with this a little bit and haven't had any luck. I've tried doing something like this:
def ctx = grailsApplication.mainContext
ctx.registerPrototype("foo", MyService)
I'm then able to ask Spring for an instance of MyService
def myServicePrototype = ctx.getBean("foo")
and it does give a new instance every time, but none of the instances have had their properties autowired up so they're all null. I'm guessing theres some way to create a BeanDefinition and feed it to the BeanFactory with some of the autowire stuff that I must be missing turned on.
I'm hoping to come up with some generic solution that doesn't force me to explicitly annotate the target services in any way.
Is there any way to directly ask the Spring applicationContext for a prototype version of what's normally a singleton?
Figured out how to do it using the Grails BeanBuilder to create a temporary ApplicationContext that has the main app context as a parent. This won't work if any unusual wiring/spring configuration has been done to the service, but that's not normally the case with Grails services, so seems like a good default pattern:
// this works in the grails console where grailsApplication is in the binding,
// need to inject in other situations
import org.springframework.context.ApplicationContext
import grails.spring.BeanBuilder
import com.example.service.MyService
def getPrototypeInstanceOf(Class clazz) {
BeanBuilder beanBuilder = new BeanBuilder(grailsApplication.mainContext)
String beanName = "prototype${clazz.name}"
beanBuilder.beans {
"$beanName"(clazz) { bean ->
bean.autowire = 'byName'
}
}
ApplicationContext applicationContext = beanBuilder.createApplicationContext()
return applicationContext.getBean(beanName)
}
def prototypeService = getPrototypeInstanceOf(MyService)
def singletonService = grailsApplication.mainContext.getBean("myService")
assert singletonService != prototypeService
assert singletonService.injectedService == prototypeService.injectedService
If it is only for testing purposes and there are no conflicting dependencies (e.g. some beans that must only be singltons), then you can just create your Spring context twice.
EDIT: Another aproach could be that you define a factory interface for your singleton service and provide 2 implementations of that factory interface: 1 for singleton only and second for having multiple instances depending on your testing situation.

Resources