I am working on 2 projects, one web app (Spring MVC) and one standalone backend service application (Spring boot) that heavily interact together. I am using hibernate for both and they are both coded using the Netbeans IDE.
My "issue" is that i end up with duplicate code in both project, mainly in the Repository and Service layers. My entities are obviously also duplicated since both projects use the same database.
Is there a way to make some sort of class library (a third project maybe?) and put all the common code in there? If that is indeed possible, how do you then change each project so they can still access this code as if it were part of them? I was thinking of putting all my Repositories, Services and entities in there to avoid code duplication and greatly reduce the risk of error.
Thank you!
Separate those Repository and Service classes to a submodule.
The structure looks like:
-- your app
-- api (dependent on `common` module)
-- webapp (dependent on `common` module)
-- common
Then the problem is to initialize beans inside common module. AFAIK, you have two options:
In #Configuration class of api or webapp module, add base packages of common module to component scan packages
In api or webapp resources folder, add Spring configuration factory
/src/main/resources/META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=your.path.AutoConfiguration
Define service/repository #Bean inside AutoConfiguration class
I am assuming in this answer your projects are connected to each other
You can set multiple properties within one Spring project, where you store your database connection parameters etc. with the help of multiple property files.
For example:
application-web.properties
application-backend.properties
You can use these in your project, by activating the needed properties file per application. The profile names will be web and backend in these cases.
When using maven, this is the command line I am using:
mvn spring-boot:run -Drun.profiles=<<profile>>
Now, back to your java code.
If there are classes only one of your application is using, you can specify this by 'profile'. Example:
#Controller
#Profile({ "web" })
public class WebEndpoint {
}
This way you can make the shared code available for both applications, without duplicating most of the code.
Related
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.
Is it possible to have a multi module Maven project using JHipster?
At first sight seems not but I want to know if there's a way to share common classes like domain classes or repository classes among different web modules in my Project using Maven.
Suppose to have a Web module with an HTML GUI made with Thymeleaf (no React / Angular), a classic Backoffice.
Then I want to have another web module that expose some REST API that needs for the same domain classes and the existing repository layer.
At first It seems that I've have to duplicate these classes and code into another JHipster application but obviously It's not the best solution.
Without JHipster I create a multi module Maven project with 2 web modules (Backoffice + API) and a third module with these common classes packaged in a shared JAR included as dependency in the first two modules.
How (if It is possibile) can achive this with JHipster?
Thanks
JHipster won't be able to generate what you want, it's up to you manually refactor the generated project to suit your needs and it's not difficult because JHipster puts entity classes in domain package and repositories in repository package. You will then have to decide how you want to execute the Liquibase migrations.
You can generate only backend code using --skip-client option, see command line options in doc.
An alternative (if you are motivated) would be to write a JHipster blueprint to generate a project with the structure you want.
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.
I'm getting confused now with packages. It's broken down like this: Simple Maven multi module project. One parent POM, two sibling module children (one is a service module, one is a web module to be ran in Tomcat).
Below is my Spring Annotation Config for Dispatcher Servlet. Here is where I am confused. At first I didn't think basePackages was going to be able to scan for packages in a totally separate module (which is the service module). However, it somehow worked, exactly as written below. 'Entities' and 'Services' are the two packages from the Service module, while 'Controllers' comes from THIS web module. Let it be known that I have in fact added the Service module as a dependency into my web module. Nothing crazy going on there. Simple dependency so I can have access to my Service classes.
#EnableWebMvc
#Configuration
#ComponentScan(basePackages={"entities", "services", "controllers"})
public class DispatcherConfig {
}
What I don't understand is how the packaging is working. It's all spaghetti'd in my mind now. When Spring gets to the line #ComponentScan and sees "entities", and "services", what is the structure it is looking on to get these classes?
My package structure is very simple. In the Service module I simply have src/main/java/entities and src/main/java/services
Something is happening behind the scenes here that I don't understand. How come Spring is smart enough to know this? I didn't even have to list the full package, i.e. myproject/src/main/java/entities or something like that?
Thanks
suppose #ComponentScan uses string array, like this:
#ComponentScan({"com.package.first","com.my.package.second"})
When you provide multiple package names in only one string, Spring interprets this as one package name.
This post might be helpful.
I'd like to define some commonly used or generic service classes that should be used/shared by different projects. These common services should already make use of #Transactional, #Autowired and other Spring related stuff. So, I somehow have to define a spring context for these services to work.
Is it possible to put these services in a single external jar library that can then be used/imported by other (child)-projects? How could I create such a "personal framework"?
What you could do is create a maven (or gradle) module that contains the code you desire to be reusable and also have a spring configuration (either XML or Java Config) that will be imported by the project that uses the module (either with or having component scanning pick up the #Configuration class of the module).