Plugins/Modules in Spring - spring

Is there a possibility of a plugin/module system in Spring/Spring-Boot, so that I can load plugins/modules as JARs at runtime, like with PF4J or Spigot/Bukkit?

Related

Spring Boot: Load profile from dependent jar

I have a Spring Boot application and a dependent common jar. This jar is for third party connections e.g. database, LDAP etc. And this common jar is going to be used in other Spring Boot services. There for I want to keep all the connection details in one place in the common jar so that when I use this common jar with other applications, I don't have to replicate the same settings repeatedly. My application structure is,
ServiceA
application-dev.properties
env=dev
application-prod.properties
env=prod
--------------------------
Common.jar
common-dev.properties
jdbc.url=
jdbc.un=un
jdbc.pass=pass
common-prod.properties
jdbc.url=
jdbc.un=un
jdbc.pass=pass
---------------------
When I start the application with an environment profile then I want the respective properties file from common jar is also loaded. Let's say I start the application as following,
-Dspring.profiles.active=dev
I want common-dev.properties also gets loaded from the common jar.
Thanks in advance.

How to control module loading order in Liberty profile

I have an ear file with a web module and a ejb module(just used for message driven beans). The ejb module has dependency on web module and it's classes. I would need to load the web module first and then ejb module. But the liberty always loading the ejb module first causing com.ibm.ws.container.service.state.StateChangeException: java.lang.NoClassDefFoundError:
How to control the order of modules loading within the same ear file? On traditional webshpere there is an option called 'Starting weight'. Whichever module has lowest value takes precedence and loads it first. so the application works good on tradition Websphere. However, this property seems missing on Liberty. I already looked at this. It only talks about deploying the multiple war files and their order.
If your EJB module depends on Web, that is bad design. It should be the other way around.
If you have such situation , proper way would be to extract shared classes in to a common jar file, let say mycommon.jar and then put that into ear\lib folder. In this way they will be visible by both modules ejb and web.
If your EJB module depends on the javax web api (e.g. servletRequest) that is even worse, and you should redesign such classes to POJO DTOs.
As a last resort you could try what is described here and add <initialize-in-order>true</initialize-in-order> in your application.xml.
FRowe's solution will not work, as classes are not shared between the applications, so changing load order of apps will not help. Each Java™ EE application has its own class loader in a running Liberty server.
Consider using the ability to control app start order as described here: https://www.openliberty.io/blog/2020/06/05/graphql-open-liberty-20006.html?_ga=2.4728563.17466047.1620833568-1423690488.1614284842&cm_mc_uid=99965752544816136653536&cm_mc_sid_50200000=61078141620909829332#ORDER
You'll have to deploy the war module as an app instead of packaging it within the ear, but you should be able to achieve the proper ordering.

Log4j2 not loading from external classpath in an EAR

The project artifact structure is:
test.ear
--lib - has all log4j2 jars core, web, bridge and JCL
--META-INF -- has app.xml, JBoss specific deployment XML, and manifest file
--a.war -- each war has web.xml with log4jConfiguration and Log4jServletContextListener specified.
--b.war
--c.war
The war creates context with log4jConfiguration, which is "classpath:test.xml". I can see each war creating the context with log4jContextName I have provided in web.xml.I have a few crons, too, which run based on configured time intervals. When crons run, and many of the JMS process run, I observed the log files are not populated with logs(From project-specific classes). While going through the log4j2 code, I understood that log4j2 creates a context for each classloader. And in my case, it creates a context for "test.ear", which is defaulted to error(DefaultContext) as it is not able to find a default log4j2.xml since I have a custom named(test.xml) on in the classpath. The Log4jServletContextListener does not catch the "test.ear" event.
How to inject my "classpath:test.xml" while log4j2 creates a context for the ear file? Since my project can be both deployed to WebSphere and JBoss, I am looking forward to suggestions that are not server-specific. Or is there a way to create a single context for all the war and ear somehow? I have different apps outside this ear in same server so I cannot give an environmental config of -Dlog4j.configurationFile as other apps have there own log4j2 xml's.
One approach that I can think of is to place your log4j config file test.xml in a shared library and configure your application to use the shared library.
The following link describes how to configure a shared library for a server or an enterprise application on WebSphere.
https://www.ibm.com/support/pages/how-create-shared-library-and-associate-it-application-server-or-enterprise-application-websphere-application-server
The shared library should be a generic function for modern Java app servers, so JBoss should also be able to configure this.

Using SpringBoot as an application loader

I have a spring-boot app that acts as a small framework for other apps. It provides a couple of JMS queues and a DAO layer to retrieve and store data from a common set of data stores. The problem is that the original developer of this framework app is scanning all the package "com.mycompany" (rather than com.mycompany.framework) so that it can load the beans of the specific app that may be declared under com.mycompany.myapp1 or com.mycompany.myapp2 an which JARs are bundled together with the JARs of the framework.
We only load a single app in the JVM (app1 or app2), but these apps may share other libraries and sometimes we end up with beans in the context that we don't need. (these may be needed in app1 but not in app2)
So, what would be your advice ?
My problem is similar to what was described here:
https://github.com/spring-projects/spring-boot/issues/3300
I am debating if each app should be aware of the framework and load it. Or if the framework should instantiate a class loader and create a new Spring context loading the app specific code as suggested in the link above.
Perhaps you should consider leveraging some of Spring Boot's Auto Configuration capabilities such as #ConditionalOnProperty or #ConditionalOnClass in your framework. That way, you can only actually enable certain beans if and when the application using your framework takes some specific action (e.g. has a given jar on the classpath, or sets a configuration value). For reference check out: http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-developing-auto-configuration

Seam Equivalent of Spring PersistenceUnitPostProcessor

We have a very comfortable setup using JPA through Spring/Hibernate, where we attach a PersistenceUnitPostProcessor to our entity manager factory, and this post processor takes a list of project names, scans the classpath for jars that contain that name, and adds those jar files for scanning for entities to the persistence unit, this is much more convenient than specifying in persistence.xml since it can take partial names and we added facilities for detecting the different classpath configurations when we are running in a war, a unit test, an ear, etc.
Now, we are trying to replace Spring with Seam, and I cant find a facility to accomplish the same hooking mechanism. One Solution is to try and hook Seam through Spring, but this solution has other short-comings on our environment. So my question is: Can someone point me to such a facility in Seam if exists, or at least where in the code I should be looking if I am planning to patch Seam?
Thanks.
If you're running in a Java EE container like JBoss 6 (and I really recommend so), all you need is to package your beans into a jar, place a META-INF/persistence.xml inside it and place the jar into your WAR or EAR package. All #Entity annotated beans inside the jar will be processed.
For unit-testing, you could point the <jar-file> element to the generated .class output directory and Hibernate will also pick the Entities. Or even configure during runtime using Ejb3Configuration.addAnnotatedClass;
#see http://docs.jboss.org/hibernate/entitymanager/3.6/reference/en/html/configuration.html

Resources