check database connection on startup in spring - spring

I want to check db connection while spring application is being started ie when application context is getting generated. I plan to do this in a separate class(say class Checker) which will have a reference to the connection object(or its wrapper) that needs to be checked. If the connection is successful, the startup process continues, otherwise its aborted. The question is around the instantiation of class Checker. Should this be done with new Checker() or should this be created as #Bean whose init method performs this check.

Use the helper to get the bean :
public class SpringContextHolder implements ApplicationContextAware {
public static ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) {
SpringContextHolder.applicationContext = applicationContext;
}
}
Now you can use the static context like SpringContextHolder.applicationContext.getBean(name).

Related

What is the real life use-case of the applicationContext.getBean() in Spring Boot?

The applicationContext vs beanFactory seems to be very popular job interview question.
Is there any real use case to call applicationContext.getBean(foo.class) or beanFactory.getBean(foo.class) explicitly in Spring Boot?
I have read some tutorials explaining the difference between ApplicationContext and BeanFactory, but I still don't see the real use-case. Why would any developer call getBean() explicitly?
BeanFactory is the parent interface that exposes all the basic methods of the spring container, which are closely related with beans (getBean(), containsBean(), isPrototype()...)
Here a common scenario where it could be used, is for example in the main static method that spring boot starts, in case you want to do some action after the initialization of spring container has finished. Considering that you are inside a static method autowiring will not work. But with this BeanFactory you are able to manually do such action.
Example
#SpringBootApplication
public class ServiceLauncher {
public static void main(String[] args) {
BeanFactory beanFactory = SpringApplication.run(ServiceLauncher.class, args);
//At this point the Spring Beans Context has been loaded
Activity activity = beanFactory.getBean(Activity.class); //So we are able to retrieve from the context a bean to do in this static class some more actions.
activity.doSomething();
}
}
ApplicationContext is an interface extending the above BeanFactory interface. It could be used again in the above scenario, but the reason it exists is that it exposes some more useful methods which could provide some extra functionality when needed. More commonly used are some interfaces that extend the ApplicationContext. Example the ConfigurableApplicationContext.
Here common scenarios used are the refresh() of applicationContext,
close() which closes the application context and also the registering of a shutdown hook when terminating with registerShutdownHook().
Basically the registerShutdownHook() is commonly used because when the JVM is asked to terminate maybe you want to do a graceful shutdown, where the application context will not be closed immediately but will give you some control during shutdown.
#Component
public class Activity implements DisposableBean {
#Override
public void destroy() throws Exception {
System.out.println("Destroying Activity component shutting down!!!");
}
}
and you register the hook with
#SpringBootApplication
public class ServiceLauncher {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(ServiceLauncher.class, args);
context.registerShutdownHook();
}
}
Those are just some of the most common uses I have seen in several applications and projects. But each separate method exposed by some interface could have it's own use case and that's why it exists there. I am confident though that just for interview questions, the interviewer will have in his mind the above 2 scenarios.

Implementing worker processes in a Spring Boot application

Intro
I am currently running a Spring-Boot application through Heroku on a single web dyno. Due to the large number of intensive background tasks (fetching resources from 3rd party APIs, sending mails, etc.), I would like to move all these "heavy jobs" on a second worker dyno/process. However, I am facing several difficulties in properly exposing the application components (e.g. #Repositories) to the second worker process.
What I have attempted so far
I've created a second main class (BackgroundWorker) which I specify in the Procfile as a worker process. The following class is then called in order to initialize the background tasks.
#Service
#EnableMongoRepositories("com.a.viz.db")
#ComponentScan("com.a.viz.db")
#EntityScan("com.a.viz.model")
public class TaskHandler {
#Autowired
UProductRepository productRepository;
public void initScheduler()
{
Runnable fetchProducts = () -> {
Scheduler.fetchProducts(productRepository);
};
}
}
While the main class looks like this:
public class BackgroundWorker {
static Logger logger = LoggerFactory.getLogger(BackgroundWorker.class);
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.scan("com.a.viz.workers");
context.refresh();
TaskHandler handler = context.getBean(TaskHandler.class);
handler.initScheduler();
}
}
Upon running the above snippet, I get an unsatisfied dependency error for bean MongoTemplate which I inject in the concrete implementation of UProductRepository, called UProductRepositoryImpl.
public class UProductRepositoryImpl implements UProductRepositoryCustom {
private final MongoTemplate mongoTemplate;
#Autowired
public UProductRepositoryImpl(MongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
}
}
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.data.mongodb.core.MongoTemplate'
How may I expose MongoTemplate to the second worker process? Moreover, what would be a good way to approach something like this? Should I try to organize my components such that only the relevant ones are exposed to the worker process? Thanks for your attention!
Solution
Since the worker process must also be a Spring application (in order to allow for injecting repositories and such), its application context must be initialized as such. The web parameter is to prevent a proper web server being set up, since that is not necessary.
// Other configs..
#EnableAutoConfiguration
public class BackgroundWorker implements ApplicationRunner {
#Autowired
// Repositories..
public static void main(String[] args)
{
new SpringApplicationBuilder(BackgroundWorker.class)
.web(WebApplicationType.NONE)
.run(args);
}

Spring static context accessor and integration tests

We have a spring component which sets the application context into a static field. This static field is then accessed from other parts of the application. I know static should not be used, but sometimes it is necessary to access spring context from non-spring-managed beans. E.g. the field looks like this:
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
public ApplicationContext getApplicationContext() {
return context;
}
#Override
public void setApplicationContext(ApplicationContext ctx) {
context = ctx;
}
}
(taken for http://www.dcalabresi.com/blog/java/spring-context-static-class/)
The problem is that when using JUnit (or Spock) framework in integration tests, a new spring context is created for tests that have annotations like #TestPropertySource or #ContextConfiguration, in that case the contexts are cached for other tests with the same configuration (context caching in spring test framework).
However, the static field is only updated when the spring context is created. That means, when a test context is retrieved from the cache, it does not update the static field, of course, because the context was already initialized before being cached. The static field was already overwritten by the last context created from previous test runs with different configuration and so it does not see the same context as the one that starts the test.
The consequence is that part of the test runs in one spring context and from the point it accesses the static field it runs in the other context.
Does anybody have a solution to this problem? Anybody got into the same situation?
I've faced with tha same issue.
The possible solution might be saving context before test and restoring it after.
For convinience it can be done via junit rule:
public class ContextRestoreRule extends ExternalResource {
private ApplicationContext context;
#Override
protected void before() throws Throwable {
context = ApplicationContextProvider.getContext();
}
#Override
protected void after() {
ApplicationContextProvider.setContext(context);
}
}
And in the test (wich modifies context):
#ClassRule
public static ContextRestoreRule contextRestore = new ContextRestoreRule();

Use spring application as library in non-spring application

I implemented spring-boot application and now I want to use it as a lib for non-spring application.
How can I initialize lib classes so autowired dependencies work as expected?Obviously if I create class instance with 'new', all autowired dependencies will be null.
The theory is that you need to instantiate an application context for your Spring Boot dependency to live in, then extract a bean from there and make use of it.
In practice, in your Spring Boot dependency you should have an Application.java class or similar, in which a main method starts the application. Start by adding there a method like this:
public static ApplicationContext initializeContext(final String[] args) {
return SpringApplication.run(Application.class, args);
}
Next step, in you main application, when you see fit (I'd say during startup but might as well be the first time you need to use your dependency) you need to run this code:
final String[] args = new String[0]; // configure the Spring Boot app as needed
final ApplicationContext context = Application.initializeContext(args); // createSpring application context
final YourBean yourBean = (YourBean)context.getBean("yourBean"); // get a reference of your bean from the application context
From here you can use your beans as you see fit.
I'm not sure how you will handle to wait until the context is fully loaded before you try to access some beans from your Constructor etc. But if you just want to access context without creating components manually try one of those:
1) Simply Inject ApplicationContext
#Inject
private ApplicationContext context;
or
2) Implement ApplicationContextAware
public class ApplicationContext implements ApplicationContextAware {
private ApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext context) {
this.context = context;
}
// just quick example, better to set it to your custom singleton class
public static ApplicationContext getContext() {
return context;
}
}
Then use context.getBean(SomeServiceFromLibrary.class);

Accessing Spring context from non-spring component that is loaded at the same time with Spring

The cool enterprise app I'm working on is in the process of going Spring. That's very cool and exciting exercise to all the team, but also a huge source of stress. What we do is we gradually move legacy components to Spring context. Now what we have is a huuuge, I mean it, huuuuge component that is not piece of cake to spring-ify, and at the same time it needs to get access to some of the Spring beans.
Now here comes the problem: this component is being loaded at application startup (or bootstrap, whatever you prefer!). That means that there is a race condition between this guy and a Spring itself, so sometimes when I access the context from within that non-spring monstrosity, I get sweet and nice NPE. Which basically means that at the time we need that context, it's not yet initialized!
You might be curious how exactly we're accessing the context: and the answer is - it's a standard AppContextProvider pattern.
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext ctx;
public void setApplicationContext(ApplicationContext applicationContext) {
ctx = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return ctx;
}
}
The ideal workaround for me in this case would be to tell Spring to notify that non-spring component "Okay, I'm up!", and perform all actions that require the context only after that. Is this actually possible?
Thanks in advance!
The correct way to make the application context available to non-spring beans is to use the ContextSingletonBeanFactoryLocator.
Take a look at this answer for more details.
Take a look at the mechanism of context events.
Perhaps you can block getApplicationConext() until receiving of ContextRefreshedEvent (if it wouldn't create deadlocks):
public class ApplicationContextProvider implements ApplicationListener<ContextRefreshedEvent> {
private static ApplicationContext ctx;
private static Object lock = new Object();
public void onApplicationEvent(ContextRefreshedEvent e) {
synchronized (lock) {
ctx = e.getApplicationContext();
lock.notifyAll();
}
}
public static ApplicationContext getApplicationContext() {
synchronized (lock) {
while (ctx == null) lock.wait();
return ctx;
}
}
}

Resources