Will Spring circular dependency delay application start time? - spring

I have a monolithic Spring MVC application consists of about 1,000 beans and it will cost about two minutes to startup.
Now I am researching to find out why it startup too slow. I added a BeanFactoryPostProcessor to record the launch time and use ApplicationListener to listen to the ContextRefreshedEvent and record the time that the ApplicationContext has refreshed. Then the result shows that the application takes about 80 seconds to finish initializing the ApplicationContext.
After reviewing the code, I found there are two many circular dependencies in the code.
I am wondering if it is the circular dependencies that cause the ApplicationContext start too slow? What I can do to speed up the startup time?
The approaches I have tried include:
Check the #PostConstruct to find out if it is asynchronous.
Adjust the -Xmx and -Xms options.
Add lazy-init to the beans.
Seems not working.
Any help will be appreciated.

I assume you are using Spring Boot and then you are implicitly using the annotation component scan. So, Spring will scan each class in order to create Bean. A possible solution could be use #ComponentScan("packageToScan") instead of #ComponentScan.
However, I do not know your goal but think if you really need to speed up the startup.

Related

Spring Boot Scheduler

I have used a Spring Boot Scheduler with #Scheduled annotation along with fixedRateString of 1 sec. This scheduler intermittently stops working for approx 2 min and then starts working automatically. What can be the possible reasons for this behavior and do we have any resolution to this?
Below is the code snippet for the scheduler.
1st) Please read SO guidelines
DO NOT post images of code, data, error messages, etc. - copy or type
the text into the question. Please reserve the use of images for
diagrams or demonstrating rendering bugs, things that are impossible
to describe accurately via text.
2nd) To your problem
You use a xml spring based configuration where you have configured your sheduler. Then you also use the annotation #Scheduled. You should not mix those 2 different types of configuring beans.
Also you use some type of thread synchronization into this method. Probably some thread is stuck outside of the method because of the lock and this messes the functionality that you want.
Clean either the xml configuration or the annotation for scheduling and try with debug to see why the method behaves as it does which most probable would be from what I have mentioned above about the locks and the multiple configurations.

Connections are not closed and piling up when running #SpringBootTest classes

We have Spring Boot integration tests, and keep writing new ones regularly.
I noticed database connections have been piling up: the more tests I run, the higher the connection peak to my PostgreSQL instance.
It reached a point where there are more than 300 connections requested by Spring Boot when running all tests, and it started failing the build (our max_connection is set to 300).
After some research, it came to my understanding that connections are not being released after tests have been run, because of Spring Boot test: if context is not explicitly destroyed, connections are not closed.
I find it quite weird, but tried using #DirtiesContext to prove a point, on all of our test classes, it indeed fixed the issue in a sense that it avoided peaks (no more than 30 connections at once, not piling up to 300 like before) but since this annotation forces context recreation before each test class, the build got much slower and I find it not very satisfactory to need to recreate a Spring context every time just to make sure connections are closed properly.
Data source is a HikariDataSource, configured using a configuration class.
Another workaround I found is to change maximum pool size for Hikari. I set it to something lower than the default value of 10 (I'm not sure it's useful to reserve 10 connections for each test class).
This change effectively lowers the total number of connections when I run all tests but they are still piling up (only lower!)
I think I'm missing something, how can I ensure that connections are closed after each test class? There has to be a better way than #DirtiesContext, I just can't find it. Thanks for your help.
It turns out that context was recreated almost with every test class because I was extensively using #MockBean annotation in my tests. Since it affects Spring context, each #MockBean/No MockBean combination in different test classes counts as a different context, i.e.:
Test class 1: bean MyService is a MockBean, MyOtherService is not
Test class 2: bean MyService is a MockBean, MyOtherService is also a MockBean
Test class 3: none of these two beans is a MockBean
In such case, a new Spring context will created for each class because the bean configuration is different, resulting in an increasing number of connections to the datasource.
To (partially) solve this, I looked for patterns in the beans combinations of my test classes and created a new class I called TestMockBeans.
Its sole purpose is to declare as many MockBeans and/or SpyBeans as possible to re-use in similar test configurations. I extend corresponding test classes with TestMockBeans, and then, because they share this similar setup, Spring identifies their contexts as similar and does not recreate a new one for every test class.
As you can guess, not all of my tests throughout the Spring boot app share the same need for Mockbeans (or absence of Mockbeans) so it's only a partial solution, but I hope it will help someone experiencing the same issue to mitigate it.

Reusing expensive beans in Spring Boot Tests

I am trying to improve performance of medium tests in Spring Boot.
I am using the Spring Boot - testcontainers library.
For an individual test this works really well, with a few annotations I can get access to kafka, zookeeper, and schema-registry. These are full services so it takes a few seconds to start everything up, all together setup takes about 40 seconds. The test accurately recreates a realistic deployment, it's beautifully simple.
This would be fine if it just happened once but it happens every time a Spring Context is created. That means every test that uses #MockBean incurs that 40 second cost.
I've tried refactoring into a single TestConfiguration class and referencing that. I've looked into using ContextHierarchy but I think that means I'll lose all of the Spring Boot niceties and I'll need to recreate the context (which means it won't look exactly like the context created by the production app).
Is there a better way to do this?
Spring framework already took care of this scenario.
There is a concept of caching the application context for test class/classes.
See the documentation.
Few lines from the documentation:
The Spring TestContext framework stores application contexts in a
static cache. This means that the context is literally stored in a
static variable. In other words, if tests run in separate processes,
the static cache is cleared between each test execution, which
effectively disables the caching mechanism.
So essentially you need to structure your code or context configuration in such a way that you use cached context in your desired test cases.
But use this capability wisely, if not thought through properly this could lead to undesired side-effects

Spring boot applications consume 100% CPU at startup

We have 40+ spring boot apps and when we try to start all of them together parallel, it takes about 9 to 10 minutes. And we notice that CPU usage is always 100% throughout this entire duration.
After all apps come up successfully and registered with Eureka, CPU usage is back to normal (on average ~30-40% CPU usage after startup).
It seems each spring boot app is taking at least about 15-20 seconds to startup, which we are not happy with since application is relatively small to start with.
We also disabled spring boot auto-configuration so to make sure only required "matching" classes are loaded at start up by spring boot. And we only gained about 1 or 2 seconds at startup after this change.
We seem to have enough system resources with 8 core CPUs and 32 gb of memory on this VM.
Spring boot version is 1.3.6.RELEASE.
Is it something to do with Spring boot? Because even when we startup single spring boot app it spikes CPU to 70-80% usage. Your help is very much appreciated!
This is more of how many beans and Auto Configurations that get executed while the application being started.
For even a simple web application along with JPA, there is a webcontainer and its thread pools, DataSources initializations and many more supporting beans and auto configurations that need to get initialized. These are some serious resource taking actions and they all are rushed at the start of the application to get application booted as soon as possible.
Given that you are starting 40+ apps like these simultaneously, the server will have to pay its toll.
There are ways you can improve the application boot time.
Remove unnecessary modules and bean definitions from your application. Most common mistake a developer makes is to include a spring-boot-starter-web when the application doesn't even need a web environment. Same goes for other starter modules.
Make use of Conditional Bean definitions with the use of #ConditionalOnMissingBean #ConditionalOnProperty #ConditionalOnClass #ConditionalOnBean #ConditionalOnMissingClass #ConditionalOnExpression. This might backfire if you make spring to check for beans with lots of conditions.
Make use of spring profiles. If you don't want a specific set of beans not to be part of that running instance you can group them into a profile and enable them or disable them
Configure initial number of threads a web container can have. Same goes for Datasources. Initiate your pool with only required number of active threads.
Using lazy-initialization for beans by annotating your classes or beans with #Lazy. This annotation can be per bean or against an entire #Configuration.
If that doesn't satisfy your needs, you can always throttle the CPU usage per process with commands like nice or cputools.
Here is an article around cputools.

spring + struts2, inject DAO into external thread

I have a web application that uses Struts2 + Spring for the resource injection, basically my DAO. Now I would like to create a thread that periodically polls the database and, if needed, send email notifications to users.
I would like to know how I can implement this in a way that this thread can use my DAO. I haven't been able to manage Spring to inject it the way I've done it. So I would like to hear suggestions and see if someone can point me to the right way.
Right now I have a thread started by a ServletContextListener, that just creates a timer and schedules an action every 5 minutes. But I can't get this action to use my DAO. I don't have any need to use this structure, I'm open to using whichever solution works.
Thanks for your help!
Edit: As axtavt suggested, I used Spring task Execution Scheduling and it works perfectly, the thing is that my task gets injected with the DAO but then I get LazyInitializationException every time I try to access a property of my fetched objects, any suggestion on how to solve that??
Perhaps the best option is to use Spring's own scheduling support, see 25. Task Execution and Scheduling (if necessary - with Quartz, see 25.6 Using the OpenSymphony Quartz Scheduler). This apporach allows you to configure your scheduled action as Spring beans, so you can wire them with other beans such as DAO.
Alternatively, you can use the following to obtain any Spring bean in web application (for example, to obtain DAO from your thread):
WebApplicationContextUtils.getWebApplicationContext(servletContext).getBean(...)

Resources