How to minimize and speed up Spring Boot project for development enviroment? - spring

I'm working on a Spring Boot Rest project with 500~ entity in it. But it is slow on start up duration (about 3 minutes) because of the EntityManagerFactory initialization. And it has 5GB~ memory allocation.
Using profiles I want to open a lightweighted version of my project. I'm trying to avoid some of the entities to be mapped via EntityManagerFactory. And related beans via ComponentScan.
Do you have any solution related this issue?
For example I wanna hide some of the packages from hibernate & spring boot auto configuration.

If the class path scanning takes to long you can narrow it down to specific packages
#ComponentScan(basePackages = "com.your.project")
#EntityScan(basePackages = "com.your.project.model")
#EnableJpaRepositories(basePackages = "com.your.project.repository")
You also have an option to create a custom EntityManagerFactory as explained in this answer with a custom ConnectionProvider.

Related

Spring boot Jpa is not working with Spring batch and spring integration

I am working with spring batch. I needed to add some jpa repositories. So previously i was using JDBCTemplate which was working fine.
But when I started working with JPA, the spring boot application could not find the repos. Which were there.
#Autowired
ClassLevelConfigRepo clcr;
I checked these things as the best practices.
Added #EnableJpaRepositories in springBoot application class.
Added #Repostiories to the repository interfaces.
extended the interfaces with JpaRepository<Account, String>
Added #Entity to the entity classes and defined the #Table and # Column annotations properly.
But I am still getting below error.
Field clcr in com.cloudtask.batchconfig.util.LhmUtility required a bean of type 'com.cloudtask.batchconfig.repo.ClassLevelConfigRepo' that could not be found.
I tried checking all the dependencies in pom.xml it was as per recommended. And I have all the tables defined properly in data base.
I was expecting the application to return the Autowired clcr object propely.
Edit 1 : spring boot application annotations
#SpringBootApplication
#ComponentScan({"com.cloudtask"})
#EnableAsync
#IntegrationComponentScan({"com.cloudtask"})
#EnableIntegrationManagement(defaultLoggingEnabled = "true")
#EnableJpaRepositories
#EntityScan
public class imclassApplication ```
When you work with Spring Data Jpa with those basic points you should also keep track of below points.
you have added spring-boot-starter-data-jpa in your pom.xml
you have added the entity and repo package below one level of the application package.
If you the package is at same level you should specify the exact package details in the annotation. in your case it should be like :
#EnableJpaRepositories("com.cloudtask.batchconfig.repo")
#EntityScan(basePackages = {"com.cloudtask.batchconfig.entity"})
Happy programming!

Prevent AutoConfiguration of all included Spring Cloud dependencies

Excluding several AutoConfiguration classes in Spring Boot is easy. Just exclude it from the application:
#SpringBootApplication(exclude = {
org.springframework.cloud.autoconfigure.RefreshAutoConfiguration.class,
org.springframework.cloud.openfeign.FeignAutoConfiguration.class,
})
But how can all AutoConfiguration from the package org.springframework.cloud can be excluded without adding all Spring Clouds AutoConfiguration classes to the exclude? That would be dozens if not hundred entries. And it would not be future proof as with every new Spring Cloud version new AutoConfiguration classes come along.
Using #ComponentScan would only work if #SpringBootApplication respective #EnableAutoConfiguration is not used. But that would remove all the convenient auto configuration capabilities, too.
Is there a way to achieve that programmatically? And how?
Removing Spring Clouds dependencies from the application is unfortunately not a feasible solution.
Why you want to exclude all classes from auto configuration ?
Most of the beans in Autoconfigurations are #conditional , they will not be created if you are providing your own.
Anyway you can look into AutoConfigurationImportSelector . As of now Spring boot allow only class and name for #EnableAutoConfigurtion exclude . if you want to write customize "AutoConfigurationImportSelector" , you can subclass and filter exclude by package after writing your own extended interface for EnableAutoConfiguration to write package method.
As I mentioned this will be the last thing I would like to do . just check #conditional dependency for auto configuration and provide your own beans is better solution.

Upgrading from Java Config to Spring Boot

Upgrading an existing system to Spring Boot with Auto config. Currently the system is all Java config. I'm confused over whether to continue the use of #Profile. Is this annotation no longer needed? I searched extensively about upgrading and found only references to non-Spring Java migration and creating new projects.
Typical #Profile usage in our configuration classes looks something like:
#Bean
#Profile("is-standalone")
public Service unsecuredService(SomeApi someApi) {
return new ...
}
I inferred from the Spring Boot examples that using one of the #Conditional annotations is recommended like this:
#Bean
#ConditionalOnProperty("unsecured.enabled")
public Service unsecuredService(SomeApi someApi) {
return new ...
}
Then in a YAML file the is-standalone Profile enables or disables all the various properties for that Profile. Is this the proper way to upgrade? To repeat a question from above differently, can the #Profile usage be left as is? This is for a fairly large project, the upgrade is non-trivial, so I would like to do this only once!
Depends where your previous #Profile annotation is coming from. If you're using Spring's #Profile, the functionality is as follows:
Annotating a class with #Profile("dev") will load the class and register it in the Spring context only when the dev profile is active
Annotating a class with #Profile("!dev") will load the class and register it in the Spring context only when the dev profile is inactive
If this sounds like what you have already, no change is needed.

Why AutoConfigurationPackages not consider #ComponentScan?

Spring Boot's support for Spring data configuration is generally by org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport, and this class use the follow code to determine what packages to scan for repositories:
AutoConfigurationPackages.get(this.beanFactory)
So, basically Spring Data with Spring Boot only scan the package which contains the #EnableAutoConfiguration or #ImportAutoConfiguration, but not consider the #ComponentScan, Is this correct ?
The #ComponentScan annotation is a core Spring Framework feature to search for classes annotated with #Component. Since Spring Data repositories are interfaces (and not annotated), the #ComponentScan annotation won't pick them up.
If you are using Spring Data outside of Spring Boot, you can scan for Spring Data repositories using #EnableJpaRepositories with the basePackages attribute set.
When it comes to Spring Boot, there's usually no need to use either #ComponentScan or #EnableJpaRepositories. If you structure your code as suggested, both components and repositories will be picked up.
To get back to your original question about AbstractRepositoryConfigurationSourceSupport. If you look at the source of #SpringBootApplication you'll see it's annotated with #ComponentScan (to find #Components) and #AutoConfigurationPackage (via #EnableAutoConfiguration). The #AutoConfigurationPackage sets up AutoConfigurationPackages with the value that's later retrieved.
If you want to override the packages the Spring Data searches for repositories (for example in tests) you'll need to use #EnableJpaRepositories to completely override auto-configuration. I usually don't do this, but instead use #DataJpaTest and pick up my main configuration.

How to enable classpath scanning for #Entity classes in Spring boot

All my attempts at classpath scanning of #Entity classes failed in a Spring boot application. The most common solution I found on the web was this and it didn't work -
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.acme.domain");
#EntityScan on a #Configuration class did not work either.
All the entities and their mappings were listed in orm.xml and I had to move back to using #Entity annotations.
One solution that got me half way there was -
<persistence-unit>
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<mapping-file>META-INF/orm.xml</mapping-file>
<class>com.acme.domain.Entity</class>
<shared-cache-mode>NONE</shared-cache-mode>
</persistence-unit>
This way I could use the #Entity annotations if I listed entity classes in persistence.xml.
The solution I didn't find while searching, which is listed on Spring Data JPA web page is this -
ClasspathScanningPersistenceUnitPostProcessor postProcessor = new ClasspathScanningPersistenceUnitPostProcessor("com.acme.domain");
entityManagerFactory.setPersistenceUnitPostProcessors(postProcessor);
Now the classpath scanning of #Entity classes is enabled. No mappings in orm.xml and no listing of entities in persistence.xml.
Sharing your code will help troubleshoot. Is there a github project you can share?
One thing to keep in mind is that SpringBoot takes an "opiniated" approach to everything. This means that for JPA, there is a "boot" way of doing things. Spring Tool Suite is your friend here.
Recommend checking this tutorial that shows you how to do JPA in Boot. Also, when using boot, I strongly recommend to start with a maven project setup from the Spring Initializer project.

Resources