Let say I have an external jar named data-access-0.0.1.jar that contains Spring annotation like #Component, #Bean. But this jar does NOT contain the main method to run as a Spring application (means no #SpringBootApplication, no #ComponentScan, ...).
Now I have another jar named employee.0.0.1.jar (does have the main method to run as Spring boot application - #SpringBootApplication), that use data-access-0.0.1.jar as a dependency. But somehow it does not scan #Bean, #Component in an external jar (error when starting the app, no bean with type "myComponent" found).
I think #ComponentScan in employee-0.0.1.jar should configure base packages include a package from the external jar and it should work, but I do not want to apply this mechanism. I want to somehow configure in the external jar so that any another jar that depend on it should scan the whole jar for autowiring
Related
I have two spring boot apps. The first is an API library that's pulled into the second (a web application) as a dependent jar.
The first, is an API library that houses functions to create "cases" in an IBM solution. It's a standalone type jar that has a service class that exposes methods like getCaseXMLForDocId(String docId) or createCaseForAgreementNumber(String agreementNumber)
The first library called CaseInvocationAPI has an application.properties file which has several properties. For example:
caseinvocation.query.fetchNonProcessedCaseXml=SELECT Id, CaptureSource, AgreementNumber, CaptureSourceID FROM CaseInvocation WHERE ProcessIndicator IN (0, 2)
The service class has a method which makes a query, grabbing that query string from a member variable that's populated with a property from the application.properties file:
#Value("${caseinvocation.query.fetchNonProcessedCaseXml}")
private String selectNonProcessedQueryString;
The second SpringBoot app is a webapplication that has REST controllers. These controllers expose endpoints that call the CaseInvocationAPI library, specifically the CaseInvocationService class.
The problem I am having is that when the SpringBoot WEBAPPLICATION starts up, the context configuration blows up with the following error:
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'caseinvocation.query.fetchNonProcessedCaseXml' in string value "${caseinvocation.query.fetchNonProcessedCaseXml}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:174)
at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126)
at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:219)
at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:193)
at org.springframework.context.support.PropertySourcesPlaceholderConfigurer$2.resolveStringValue(PropertySourcesPlaceholderConfigurer.java:172)
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:813)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1039)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1019)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:566)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:349)
... 45 common frames omitted
It appears that when the WebApp starts up, when it's trying to build the classes from the dependent jar, those properties are not being found.
I didn't think I had to copy each and every property out of the dependent jar application.properties file into an application.properties file in the Webapp project.
Why isn't the WebApp project (CaseInvocationWebApp) picking up the application.properties file from the dependent jar file (CaseInvocationAPI)?
I checked the compiled jar file (CaseInvocationAPI) and the application.properties file is there in the jar.
Looks like the problem was related to the fact that both the child jar and the webapp have application.properties files. I wasn't aware that the parent WebApp application.properties sort of overwrites the others (ignoring all others really).
Special thanks to Paschoal for his response.
You can see details on the answer here:
Adding multiple application.properties files
There are 3 ways (that I can think of) you can approach this:
The dependency, API library, should not have an application.properties since it's a library and not an executable Spring boot application in itself. You only define the properties in your web application's application.properties, even for the API library.
But, here the assumption is that you have access to the API library jar.
You can redefine all the properties in web application's application.properties essentially overriding them.
Explicitly configure the Spring boot application to use both the application.properties files, each for different set of properties.
Caveat: The file names must be different, as config location is classpath for both.
#SpringBootApplication
public class WebApplication {
public static void main(String[] args) {
SpringApplication app = new SpringApplicationBuilder(WebApplication.class)
.properties("spring.config.location=classpath:api-application.properties,classpath:application.properties")
app.run(args);
}
}
I have to make a plugin manager that handle Spring Bean inside jar contains in a specific external folder, in my case it's externalPlugin.
The folder externalPlugin is in my classpath.
My problem is that spring don't load beans when there are inside the jar.
If the jar file is extracted in /externalPlugin folder, Spring boot loads correctly the beans.
Is there a specific way to create jar , that spring loads correctly bean inside JAR? or even is it possible to load bean in external Jar?
Thank you for your time.
In my spring boot application, in order to load external Bean, I use the annotation
#ComponentScan({"com.app","com.plugin"})
To know if my bean are loaded I use and print the result of
String[] beanNames = ctx.getBeanNamesForType(AbstractPlugin.class);
external plugin jars are created as follow with jar cvf command
/externalPlugin/pluginA.jar
|-META-INF/
| |-MANIFEST.mf
|
|-com/
|-plugin/
|- beanA1.class
|- beanA2.class
package com.plugin
#Component
public class BeanA1 extends AbstractPlugin{
}
package com.plugin
#Component
public class BeanA2 extends AbstractPlugin{
}
found what i needed
http://www.codevomit.xyz/bootlog/blog/how-to-provide-spring-boot-fat-jar
and specialy generate jar with eclispe
I have a Spring Boot application. I have several customers who each have a version of this application, with a few custom #Component, #Service, etc, classes. I am trying to abstract those custom Spring beans out into library jars which I can place on the classpath and load dynamically.
For example, suppose I have an interface in my core library:
public interface MyInterface {
String doSomething();
}
I have a different implementations of MyInterface in my customer-specific libraries, all annotated with #Component.
I want to be able to put
#Autowired
List<MyInterface> components;
in my main application.
Then, I want to just place my main application in a folder with the appropriate customer's library (or multiple) and run it with
java -cp . -jar my-application.jar
and have that #Autowired pick up the customer's specific components.
Is this possible? I don't want to use #Import in the main application, because that requires knowing which customer's library is being loaded.
I did figure this out. Here is a demo project for loading #Component objects from plugins at runtime.
https://github.com/imnotpete/plugin-demo
It uses the loader.properties file to specify a folder to add to the classpath, and then #ComponentScan can include any jars from that folder when autowiring.
loader.properties:
loader.path=plugins
I am working on a project where we developed various jars as small modules. Then these jars were added as dependencies in a base project.
In the base projects applicationContext we have imported the applicationContext of all dependendant jars using the following line
<import resource="classpath*:applicationContext.xml" />
The above line makes sure that all the applicationContexts.xml s get loaded. On code analysis I found that each of the module in its applicationContext has the dataSource injected. Although all the jars are going to use the same datasource still each of the jar is instantiating its own datasource. Is there a way by which I can specify a global datasource which can be injected through base class itself.
In each of the jars we have a datasource injected which the jar uses to perform database operations. I would want the jars to use a datasource of base jar instead of its own datsources.
Goal:
List item
I have a spring webapp project, which is using component scan for configuration and autowiring interface implementation through maven submodules
the main project is dependant on the other modules thus the jar's of the submodules are placed in the /WEB-INF/lib folder
the submodules (aka plugins) have common package parent name x.y.z.extension eg. x.y.z.extension.pluginA
the classes in this package are annotated with #Component or #Configuration
in the servlet xml configuration i have placed such component-scan information:
Code:
<context:spring-configured />
<context:component-scan base-package="x.y.z.extension" />
With the mentioned configuration everything is working correctly.
What I would like to achieve:
List item
remove dependency of the main webapp maven module and other modules - the core webapp will be shipped without plugins
create subfolder e.g. "WEB-INF/classes/plugins" in the classpath classes dir
put there the mentioned jar's from submodules (or extract the jar content to eg. WEB-INF/classes/plugins/pluginA) - this could be done during "plugin installation" with webapp restart after new plugin installation
spring automagically should detect annotated classes and load it into the application context (and use not annotated classes in the plugin jar (annotated classes are mainly interface implementation but they are using some not annotated classes in the jar))
and ... of course this does not work The classes are not found.
If it possible to achieve this only using spring ecosystem, or should I take a look into other examples e.g. jspf ?
How can I modify classpath scanning with spring and also keep automatic component scanning ?
thanks !