Database initialisation before bean creation - java

I am creating a timer application that uses Quartz, also am using spring to initialise my DB from schema.sql file. When application starts I want to DB be initialised before my Scheduler bean is created.
#Bean
public Scheduler scheduler() throws SchedulerException {
Scheduler scheduler;
final StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory("application.properties");
stdSchedulerFactory.initialize();
scheduler = stdSchedulerFactory.getScheduler();
scheduler.start();
return scheduler;
}
Scheduler bean is inside TimerConfiguration.java which is added to TimerApplication like
#SpringBootApplication #Import({TimerConfiguration.class})
public class TimerApplication {
Is there a way to achieve this ?

The #DependsOn annotation specifies a bean which should be initialized after another bean got initialized.
It's recommended to set the name of the waiting bean as value in the annotation.
In your case its #DependsOn("datasource").
More infos from the docs:
Beans on which the current bean depends. Any beans specified are
guaranteed to be created by the container before this bean. Used
infrequently in cases where a bean does not explicitly depend on
another through properties or constructor arguments, but rather
depends on the side effects of another bean's initialization.
May be used on any class directly or indirectly annotated with Component or
on methods annotated with Bean.

Related

How does spring recognize the param inside a constructor

I was trying to configure promethues in my code and I just had to create a bean like below. I was wondering how spring recognised CollectorRegistry. How did spring instantiate all the necessary variable for CollectorRegistry and setup all the necessary cofnfiguration?
#Component
public class TestProm{
public TestProm(CollectorRegistry registry){
// Some initialization code here
}
}
However, when I tried to define it in another way by defining a #Bean in my #Configuration class, it didn't seem to work properly as my own constructor for CollectorRegistry didn't have all the necessary properties.
#Configuration
public class PromConfiguration{
#Bean
public TestProm getTestProm() {
return new TestProm(new CollectorRegistry());
}
}
public class TestProm{
public TestProm(CollectorRegistry registry){
//Some code here
}
}
How do I recognise/replicate the initialization of CollectorRegistry done by spring when I do my custome implementation.
How did spring instantiate all the necessary variable for CollectorRegistry and setup all the necessary cofnfiguration?
In the first example you require a Bean of type CollectorRegistry and Spring will actually create such bean for you if you have spring-boot-starter-actuator and Prometheus dependencies on your classpath and you have autoconfiguration enabled :
if you use #EnableAutoConfiguration
if you are using Spring Boot and #SpringBootApplication annotation (#EnableAutoConfiguration is part of this annotation underneath) :
...
#EnableAutoConfiguration
#ConfigurationPropertiesScan
...
public #interface SpringBootApplication
In this case Spring will scan the classpath and load all configurations. The bean that you are interested in is part of PrometheusMetricsExportAutoConfiguration :
#Bean
#ConditionalOnMissingBean
public CollectorRegistry collectorRegistry() {
return new CollectorRegistry(true);
}
In the second example the instance of CollectorRegistry is not managed by Spring because you create it through new keyword. However it should work as CollectorRegistry has default constructor which initializes autoDescribe field to false. And the default Bean of this class which is created by Spring (in a way described above) has this field set to true. So the value of this field is the source of your differences.
Also if this instance is not managed by Spring - it prevents it to be injected into other components which require it. As the scope of CollectorRegistry is Singleton (shown above) other beans might require to share the instance to work properly (for example some beans might want to register/deregister collectors) but if you create CollectorRegistry like that with new keyword - you will not get the singleton instance but a new instance which cannot be shared across other beans.
How do I recognise/replicate the initialization of CollectorRegistry done by spring when I do my custom implementation?
If you want to use the default CollectorRegistry (assuming you want to use the bean that is created by default in the way described above) just inject bean of this type to your beans and it should be enough.

#PostConstruct annotation and spring lifecycle

I'm new to Spring, I would like to know:
I have a java class annotated with #Component (spring) and inside I have a method annotated with #PostConstruct. The class is then referenced by #Autowired annotated field in another class. Can I assume that the class is only injected after #PostConstruct is called?
#Component
class AuthenticationMetrics {
private static final MetricRegistry metrics = new MetricRegistry();
final Counter requestsTotal;
final Meter guestLogins;
final Meter kfUserLogins;
final Timer guestLoginResponseTime;
final Timer kfLoginResponseTime;
#PostConstruct
public void populateMetricsRegistry() {
metrics.counter("authentication.requests.totals");
}
}
If you are asking is injection of given class happening after #PostConstruct in that bean is called, then the answer is yes - #PostConstruct is executed before bean is considered as "injectable"
If you are asking if #PostConstruct on given bean is executed after all injections has been done (on the same bean) - then yes - #PostConstruct is executed after injections are commited to given bean. This is the reason it exists. Normally you could put #PostConstruct actions into the constructor. However, when new object is created (constructor is called) injections are not performed yet - so any initialization that depends on injected objects would fail due to NPE. That is why you need #PostConstruct
The handling of annotations such as #PostConstruct, #Resource, #PreDestroy is done via a BeanPostProcessor, in this case the CommonAnnotationBeanPostProcessor. You can see in the following diagram from Spring that these BPP's are handled after Dependency Injection but before Bean Ready For Use (Which means as much as injectable).
Yes. Bean creation workflow is:
constructior call
#Autowired fields
#Autowired setters
BeanPostProcessor's postProcessBeforeInitialization(), i.e. #PostConstruct called by CommonAnnotationBeanPostProcessor
InitializingBean.afterPropertiesSet()
BeanPostProcessor's postProcessAfterInitialization()
Bean is ready and can be injected to other bean

Inject list of initialized beans

I need to inject list of already initialized beans into some another one.
I have class with definitions of some lazy beans which are used depending on environment - like on server 1 only impl1 and impl2 will be used and on server 2 impl3 and impl1
#Component
class Definitions {
#Bean
#Lazy
public A impl1() { /* ... */ }
#Bean
#Lazy
public A impl2() { /* ... */ }
#Bean
#Lazy
public A impl3() { /* ... */ }
}
And I have some monitoring bean which don't know anything about environment and just collects all those A beans exposing some health information for actuator:
#Component
class Monitoring implements HealthIndicator {
#Autowired
private List<A> monitored;
}
Problem is that spring wires all beans into monitored even if they were not initialized before (which crashes the whole thing, cause there is no suitable environment). And I need to somehow explain to spring that I only need already initialized beans - something like #AutowireOnlyThoseLazyBeansWhichAlreadyBeenUsedSomewhereElse
P.S. I know that I can use dirty hack and declare a list property inside Definitions, fill it in bean factory methods and register another one bean with reference to that list but it is too dirty.
Solution was to just write custom OSGi-like "ServiceTracker" through monitoring beans of some specific type via BeanPostProcessor and registering dynamic bean with all tracked beans in concurrent map into context.

How do i eagerly initialize beans per tenant?

I'm trying to write a multi-tenant Spring Boot application but having trouble to eager initialize beans when the server starts (i.e. not lazily once the tenant requests the bean)
To support multi-tenancy, i created a #CustomerScoped annotation that creates objects based on a ThreadLocal String value.
My configuration provides a bean like this and lazily initializes it:
#Autowired
private AutowireCapableBeanFactory beanFactory;
#Bean
#CustomerScoped
public Scheduler getScheduler() {
CreateDefaults job = factory.createBean(CreateDefaults.class));
Scheduler scheduler = new Scheduler();
scheduler.schedule(job);
return scheduler;
}
#PostConstruct
public void init() {
CustomerScope.setCustomer("tenant1");
getScheduler();
CustomerScope.setCustomer("tenant2");
getScheduler();
CustomerScope.clearCustomer();
}
When starting the server, two Schedulers should be created, each of which would execute their own instance of "Create Defaults".
When tenants access the application themselves, they should be getting their own instance of this Scheduler.
This seems to work but i wonder whether this is the correct way of doing things.
In particular, i am worried about the fact that the beanFactory isn't scoped itself.
Would this approach work and scale for more complex systems?
My code sample was actually correct.
The Beanfactory doesn't need to be scoped itself, it just has to be made aware of the scope, which in my case can be achieved in the configuration:
#Bean
public static CustomScopeConfigurer customScope() {
CustomScopeConfigurer configurer = new CustomScopeConfigurer();
configurer.addScope(CustomerScope.CUSTOMER_SCOPE_NAME, new CustomerScope());
return configurer;
}

Autowire of prototype bean into prototype bean?

I'm working with some existing code and it is doing things I haven't seen before. I've dealt with autowiring prototype beans into singletons using method injection or getting the bean from the context using getBean(). What I am seeing in this code I am working on is a bean that is a prototype and retrieved using getBean(), and it has autowired dependencies. Most of these are singleton beans, which makes sense. But there is an autowire of another prototype bean, and from what I see, it does seem like it is getting a new bean. My question is when you autowire a prototype into a prototype, will that give you a new instance? Since the autowire request is not at startup but rather when this bean is created, does it go and create a new instance? This goes against what I thought about autowire and prototype beans and I wanted to hear an answer from out in the wild. Thanks for any insight. I'm trying to minimize my refactoring of this code as it is a bit spaghetti-ish.
example:
#Scope("prototype")
public class MyPrototypeClass {
#Autowired
private ReallyGoodSingletonService svc;
#Autowired
private APrototypeBean bean;
public void doSomething() {
bean.doAThing();
}
}
#Scope("prototype)
public class APrototypeBean {
private int stuffgoeshere;
public void doAThing() {
}
}
So when doSomething() in MyPrototypeClass is called, is that "bean" a singleton or a new one for each instance of MyPrototypeClass?
In your example, the APrototypeBean bean will be set to a brand new bean which will live through until the instance of MyPrototypeClass that you created is destroyed.
If you create a second instance of MyPrototypeClass then that second instance will receive its own APrototypeBean. With your current configuration, every time you call doSomething(), the method will be invoked on an instance of APrototypeBean that is unique for that MyPrototypeClass object.
Your understanding of #Autowired or autowiring in general is flawed. Autowiring occurs when an instance of the bean is created and not at startup.
If you would have a singleton bean that is lazy and that bean isn't directly used nothing would happen as soon as you would retrieve the bean using for instance getBean on the application context an instance would be created, dependencies get wired, BeanPostProcessors get applied etc.
This is the same for each and every type of bean it will be processed as soon as it is created not before that.
Now to answer your question a prototype bean is a prototype bean so yes you will receive fresh instances with each call to getBean.
Adding more explanation to #Mark Laren's answer.
As explained in Spring 4.1.6 docs
In most application scenarios, most beans in the container are
singletons. When a singleton bean needs to collaborate with another
singleton bean, or a non-singleton bean needs to collaborate with
another non-singleton bean, you typically handle the dependency by
defining one bean as a property of the other. A problem arises when
the bean lifecycles are different. Suppose singleton bean A needs to
use non-singleton (prototype) bean B, perhaps on each method
invocation on A. The container only creates the singleton bean A once,
and thus only gets one opportunity to set the properties. The
container cannot provide bean A with a new instance of bean B every
time one is needed.
Below approach will solve this problem, but this is not desirable because this code couples business code with Spring framework and violating IOC pattern. The following is an example of this approach:
// a class that uses a stateful Command-style class to perform some processing
package fiona.apple;
// Spring-API imports
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class CommandManager implements ApplicationContextAware {
private ApplicationContext applicationContext;
public Object process(Map commandState) {
// grab a new instance of the appropriate Command
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
protected Command createCommand() {
// notice the Spring API dependency!
return this.applicationContext.getBean("command", Command.class);
}
public void setApplicationContext(
ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
So, there are 2 desirable ways to solve this problem.
1. Using Spring's method injection
As name suggests, Spring will implement & inject our abstract method by using #Lookup annotation from Spring 4 or tag if you use xml version. Refer this DZone article.
By using #Lookup.
from Java Doc...
An annotation that indicates 'lookup' methods, to be overridden by the
container to redirect them back to the BeanFactory for a getBean call.
This is essentially an annotation-based version of the XML
lookup-method attribute, resulting in the same runtime arrangement.
Since:
4.1
#Component
public class MyClass1 {
doSomething() {
myClass2();
}
//I want this method to return MyClass2 prototype
#Lookup
public MyClass2 myClass2(){
return null; // No need to declare this method as "abstract" method as
//we were doing with earlier versions of Spring & <lookup-method> xml version.
//Spring will treat this method as abstract method and spring itself will provide implementation for this method dynamically.
}
}
The above example will create new myClass2 instance each time.
2. Using Provider from Java EE (Dependency Injection for Java (JSR 330)).
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
#Component
public static class SomeRequest {}
#Service
public static class SomeService {
#Autowired
javax.inject.Provider<SomeRequest> someRequestProvider;
SomeRequest doSomething() {
return someRequestProvider.get();
}
}
The above example will create new SomeRequest instance each time.

Categories

Resources