How to prevent Spring Boot Devtools from caching few files - java

I am using spring cache to cache my database results, when spring cache is enabled along with spring boot devtools we receive weird exception ClassCastException due to known limitation is spring dev tools.
Now I want to exclude the class which contains cache from auto restart or reload, How we can achieve this?

You can workaround this issue pretty easily.
First of, you can disable caching completely, simply add the following to your configuration:
spring.cache.type=none
You could add that as a system property, or in the run configuration of your IDE so that it only applies when you're using devtools on your box.
Then you can switch to a cache manager implementation that does not serialize the content of object. One way to achieve that is to create a cache manager in memory with a certain profile:
#Configuration
#Profile("dev")
public DevConfig {
public CacheManager cacheManager() {
return new SimpleCacheManager();
}
}
And then enable the dev profile (again via a property or in the run config of your IDE). This might now work if you have complex eviction rules.
Finally, you can fix the underlying problem by adding (including) the cache library (the component that is responsible of the serialization) in the application classloader. See this link for more details.

The restart technology provided by Spring Boot works by using two classloaders. Classes that do not change (for example, those from third-party jars) are loaded into a base classloader. Classes that you are actively developing are loaded into a restart classloader. When the application is restarted, the restart classloader is thrown away and a new one is created. This approach means that application restarts are typically much faster than “cold starts”, since the base classloader is already available and populated.
By default, any open project in your IDE is loaded with the “restart” classloader, and any regular .jar file is loaded with the “base” classloader. If you work on a multi-module project, and not every module is imported into your IDE, you may need to customize things. To do so, you can create a META-INF/spring-devtools.properties file.
The spring-devtools.properties file can contain properties prefixed with restart.exclude and restart.include. The include elements are items that should be pulled up into the “restart” classloader, and the exclude elements are items that should be pushed down into the “base” classloader. The value of the property is a regex pattern that is applied to the classpath, as shown in the following example:
restart.exclude.companycommonlibs=/mycorp-common-[\\w\\d-\.]+\.jar
restart.include.projectcommon=/mycorp-myproj-[\\w\\d-\.]+\.jar
see Spring boot devtools docs

Related

Spring: Dynamic registrations of beans, rest-controllers, and more

I am new to Spring and would like to convert my existing applications to Spring Boot.
However, I am using a self-written module framework that allows me to add or remove components or additional functions of the application dynamically at runtime. The whole thing can be compared to plugin frameworks like PF4J or the plugin mechanism in Minecraft servers.
The advantage of this is obvious. The application is much more dynamic and certain parts of the program can be updated at runtime without having to restart the whole application.
Under the hood, a new ClassLoader is created for each module when it is loaded. The ClassPath of this ClassLoader contains the JAR file of the module. Afterwards, I load the respective classes with this ClassLoader and execute there an init method, which contains each module.
Now, I would like of course in connection with Spring that both the dependency injection in the modules functions, and that beans or, for example, rest controllers, which are in the modules, register with the module loading and unregister with the module unloading.
Example: I have a staff module. When I register it, the employee endpoint is registered and is functional. When I unload the module, the employee endpoint is removed again.
Now to my problem:
Unfortunately, I don't know how to implement this with Spring, or if something like this is even possible in Spring. Or are there even already other solutions for this?
I also read something about application contexts. Do I have to create a new application context for each module, which I then somehow "closed" when unloading the module?
I hope you can help me, also with code examples.
This post helped me a bit: https://hdpe.me/post/modular-architecture-with-spring-boot/
In short for each module a new ApplicationContext (e.g. AnnotationConfigApplicationContext) is created. If you want to share beans between the modules, you have to publish them to the main application context.
Beans can be registered at runtime by ((GenericApplicationContext) applicationContext).registerBeanDefinition(name, beanDefinition); at the main Application Context.
Another problem is that additional configurations are required, for example for #RestController or similar, in order for them to work. See other questions on StackOverFlow from me.

Spring boot - Loading configuration property file in to java.util.properties

I need to load a configuration property fully into java.util.Properties file in my spring boot project and then need to pass this wherever needed. With Spring boot I can load the full file and can get the access of the values though keys. But how I can load the whole configuration file into Properties object or pass the spring loaded property (not a single value rather all the values) wherever required?
My current code:
Properties myProps= new Properties();
myProps.load(resourceAsStream);
If you're looking for specific ways of loading them using Spring-boot I'd suggest looking into:
Binding properties to an object by using the #Configuration, #ConfigurationProperties and #PropertySource annotations if you want to enforce and implicitly manage type-safety at all times
The Environment interface you can #AutoWire to your classes, if you don't need to enforce type-safety at all times (you can still do it, but you're not forced to). #PropertySource can be used in this case as well to load properties outside the default default-loaded application.properties, although they'll be loaded only when the application context refreshes (e.g. they won't be available while the application is booting up)
The PropertiesLoaderUtils class, as suggested in the comments, if you want to selectively load a configuration file at runtime for example
I usually recommend the first. The result is the same as using an #AutoWired Environment, with the advantages of implicit type-safety and improved readability. You can then get the properties and write them inside your java.util.properties if you need them to be there.
However, there is more than one way to do that, both using Spring-Boot or not. Loading properties like that is also perfectly fine, although arguably not the best practice since you're using Spring-boot.

How to dynamically load jar files with application context by Spring (with no OSGi)?

I am going to create Java Application that can load external jar files at runtime by FileChooser. I am using Spring Framework, and I want to load jar file and its applicationContext.xml file and inject its dependencies dynamically. I tried to achieve this by OSGi, but it seems very complicated so that I am searching another appropriate variants.
I want to make something like Intellij IDEA plugin installation from the disk.
How can I do this? (After the jar file chosen restarting an application also accepted)
I realy like your approach, unfortunately spring has lifecycles that are strict. As you might know, spring autowires "beans" only. Exactly one lifecycle registers the different bean candidates. After that lifecycle spring (by default) does not accept new classes.
You must use the spring-osgi.
If you only need the CDI part out of spring, you might like to use a different CDI like red hat's jboss server.

Run multiple spring boot jars in one jvm

My project contains several services, each one is annotated with #SpringBootApplication and can be run on a random port via "gradle bootRun".
Is it possible to build the services into jars and run them together in one JVM? Not matter by programmatic method or just put them in a container.
Please show me some instructions if possible. Thanks!
It's a little hacky, but can be done. I wrote a blog post about it some time ago: Running Multiple Spring Boot Apps in the Same JVM. The basic idea is to run every Spring Boot application in a different classloader (because otherwise there would be resource conflicts).
I, personally, only used it for testing. I would prefer to run the different applications in different docker containers in production. But for testing it's pretty cool: You can quickly boot up your application and debug everything...
If you want to launch multiple spring boot microservices in single JVM then you can achieve this by launching multiple threads. Please refer sample code here https://github.com/rameez4ever/springboot-demo.git
Yes you can please check this SO.
However, if separating the running-user processes and simplicity is core , I would recommend the use of Docker containers, each running instance of the container(your apps) will runs in its own JVM on the same or distributed host
This is applicable, as David Tanzer said, by using two classloaders to start each Spring application in one JVM process. And no special code changes are required for these Spring apps.
In this way, almost every resource under those classloaders are separated: spring beans, class instances and even static fields of a same class.
But there are still concerns if you decide to hack like this:
Some resources like ports, cannot be reused in one JVM;
JVM system properties are shared within JVM process so pay attention if those two apps are reading a system property with same name. If you are using Spring, could try setting properties via command line argument to override those from system properties.
Classes loaded by the system class loader or its parents will share static fields and class definitions. For example, Spring Boot's thin jar launcher will use the system class loader to load bean class definition by default so there will be only one class definition even you have launched Spring apps in separate class loaders.

Lazy Loading Spring Beans as part of Integration Test

The Test class of my application is extending "AbstractSingleSpringContextTests".
We are loading all the Spring config files by overriding the "getConfigLocations" method.
All Spring files that I am loading are bundled inside JAR files (which are provided by other teams).
Hence the startup time for the integration tests is quite high. I am unable to set the default lazy load parameter to false since the spring config files are in JAR files.
Is there way to programmatically set lazy load to true while running
the tests?
Is there a way to programmatically disallow certain beans defined in application-context.xml from loading?
Thanks a lot for your suggestions.
I have able to lazily load by following the steps specified in this link - http://batmat.net/blog/post/2008/01/13/How-to-load-a-XML-Spring-context-lazily-by-default

Categories

Resources