I'm trying to make a Spring Boot app where plugins are loaded dynamically from JARs at runtime. I also want the plugins to have access to all the Spring Boot features, most prominently Spring Data JPA. I've already figured out how to load classes from JARs, and now my problem is how to "hook up" the loaded classes (that might be Beans, JpaRepositories etc.) to "work with" my main Spring Boot application.
I also might in the future want to have my own annotation system for doing different things with the main app from the plugins, (that I know how to do using reflection) and I would want to still be able to do it after I manage to sort the Spring stuff out.
I imagine I have to tell Spring somehow to additionally look for #Components and other meaningful classes from those JARs, when it's scanning for annotations. I tried with #ComponentScan's basePackageClasses attribute but that needs to be constant, and hard-coding this is not an option for what I wanna do.
So is what I want to achieve even possible? And if it is, then can I do it through Java code, or is it maybe achievable by writing some XML configs?
When you start an spring app, beans are loaded and hooked in its contexts, so if you want to add more to it manually you might need to reload the whole context which may not be a good idea for an spring boot app.
Instead, I would suggest to use spring profiles, so you can define different configurations and based on what you want you can simple enable the one you need.
Find out more at:
https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-profiles
Hope this helps!
Related
I'd like to write a framework on top of spring boot that does a bunch of things, like exposing specific endpoints and doing specific logic.
But I'd like to build it as a framework in the sense that someone else can take it, implement a number of specific interfaces and it will then run as a spring boot web application.
I haven't found how to do this specifically.
I've looked into this article about writing a custom starter, but it looks like the dependency is the wrong way round. I want the custom code "plugged into" the framework rather than calling the classes of the starter directly, if that makes sense.
It seems you're looking for the EnableAutoConfiguration plugin. This is the core of any spring boot libraries that wants to deal with spring boot custom beans without user help. EnableAutoConfiguration classes need to be placed in spring.factories file.
spring.factories file can have multiple classes each class needs to be provided using org.springframework.boot.autoconfigure.EnableAutoConfiguration=A,B,C
Using these boot classes you can create many beans that could be the backbone of your framework. Also if you want to provide custom properties as boot does, you need to add those properties file spring-configuration-metadata.json file.
For your reference, you can see this repo Rqueue
I have a Spring Boot REST application with JPA entities and Repository classes (and related services) that works very well. Now I would like to reuse these classes for other purposes, like weekly CRON jobs and similar one-time processes which will be run from the command line.
What would be the best way to do this? The challenge is that the persistence context properties are set in application.properties, and the persistence context isn't initialized unless the Application class is initialized.
I can break out all of these classes into a separate project, and use a different way to define the persistence context there, but this becomes more of a maintenance headache if anything changes with the entities or DAO methods.
What I would really like is to have a way, from the command line, to tell Spring Boot to run another class instead of the main Application (and have the persistence context properly initialized). Any way to do this?
(Note I asked a similar question which got no response: Possible to use Spring Boot repositories from another main class?)
[Edit] is it possible to do this by creating a #component that implements the CommandLineRunner? I just want it to run a simple one-time process and not the full REST application.
There are a number of ways you could do this.
You can have multiple Main classes, and then select which application yuo want to start select main class, however if you don't know how ComponetScan works you will end up loading both applications if you are not careful.
Another way is to use Profiles, you can set the profile when you start your spring app, and then have your web profile that will start Tomcat, and a command line profile that will not .
In the project I'm working on we have choosen to have the data-layer as a completly separate module (same gradle project), which has it's own Spring Context. The data-layer spring context is then used as the parent context for other applications, as a reusable component. It is a somewhat cleaner separations of concerns, were the shared code is clearly marked, instead of having multiple applications inside the same code mudule.
My Spring Boot Application features a content management system. I would like to be able to dynamically load new components without requiring an application restart. An example component may be loading a new video player component or ad component. Each component would likely contain its own controllers and views.
What would the recommended pattern be for this, and what is a good framework to help handle this? Is OSGi an option?
I'm afraid there isn't a 100% solution. There's maybe some options; let me highlight the following three:
There are Spring factories, a way to (auto-)configure your beans.
Another interesting approach to go is the way of how Spring Boot handles extensions by itself - by having its own spring-boot-starters, like in this article: https://blog.codecentric.de/en/2014/11/extending-spring-boot-five-steps-writing-spring-boot-starter/, combined with Spring Factories you could
The most plugin-like solution is the spring-plugin-project. However it looks like only loading is supported, some other features like versioning are missing, too. So you probably have to build it by yourself.
So the main problem might be in unloading and updating these things at runtime, which leads me to the final observation:
In general I have the impression that the concept of having a plugin is working a bit against the idea of Spring Boot, as it is designed for microservice architectures. So the added (plugin) functionality probably would rather be a separate microservice (with its own storage) which gets orchestrated by a gateway, here let me highlight the spring-boot-based JHipster project to show the idea of such an architecture.
I asked a question yesterday ( Using Spring in standalone apps ) on how you would use Spring in a standalone application. From that I learned that you only create the application context object once. So now the question is (even though it was partially answered in a comment) what happens when you create the application context?
Does Spring create the beans and wire them together when you say
new ClassPathXmlApplicationContext("some.xml") ?
I am not sure if I understand the boot strapping, and why it is like that.
The idea behind the ApplicationContext in Spring is that in order to properly inject objects where they are needed, some thing needs to be aware of the configuration the user specifies and inject dependencies based on this configuration.
The ApplicationContext is the thing that understands the user's wishes in terms of where and what should be injected (as well as other things such as AOP pointcuts and such) based on the configuration a user provides, either through an xml file or annotations.
Yes it will parse the bean definition file , it will create the beans , give them the dependencies,
The easiest way to debug is to go with the output print statements,
Put the statements in constructor & setter methods and try different possibilities to track the flow
I'm working on a 10-year-old Java webapp, and I would like to introduce some new technology into the project. One of the things I would like to start doing is dependency injection. I know the Spring Framework has the capability to do dependency injection, but I am having a hard time integrating the framework into the old project.
Could someone provide an example of what I would have to change in my web.xml, other files I would have to add, and other changes I would need to make? I want the smallest Spring footprint while still being bale to do dependency injection.
There are a lot of examples online about starting a new project using Spring, but I can't find any about integrating Spring into an old project.
Thanks.
You'll have to start by adding a context loader listener into your web.xml, along with the locations of the Spring configuration XML files.
You should configure the Spring DispatcherServlet to accept all URLs that you wish for it to handle.
You should write Controllers to bind and validate HTTP requests, call services, add data to ModelAndView for rendering, and map JSPs to success/failure views as needed.
You should put interfaces in front of your service and persistence tiers. Move implementations into implementation classes that Spring can inject.
Leverage Spring AOP for security and transactions and logging as needed.
Throwing new technology at a project wont make it faster\better, unless you introduce the new technology to all parts of the project. The idea behind DI is to lose dependencies between objects. The project probably is tightly coupled, so you'd have to rewrite at least parts of the thing. Depending on the size, this can be a monster to beat - ask yourself if this is worth it, if it has any positive effect on the project other than introducing new technology.
The reason why there are little to none tutorials about integrating DI container into an old project is quite simple: it usually doesn't make any sense. Either you use the pattern in all places, or none at all. The bastard child that would be creating by mixing both would be a horror to maintain. I'd really advise you think about why you want to introduce a DI container into that 10 year project. Unless there is a real good reason for doing it (and you are happy with rewriting a lot of code) don't do it.