At the startup time of a spring app, I want to scan a path on the computer, find the jar files and build a spring application context from an xml config files inside them. Every thing is OK to add jar file to the classpath and making an ApplicationContext. But I can't find any beans from new context. All of needed dependencies are available in the jar files in the specific path on computer (via a maven copier plugin) expect those dependencies which are in the base spring project (for example spring dependency itself).
The code is (In Kotlin language):
var loader = URLClassLoader(arrayOf(entry.toFile().toURL()), Thread.currentThread().contextClassLoader)
...
val context = ClassPathXmlApplicationContext("classpath*:/$name")//name is xml file. I'm sure the address in classpath is right. context is not creating when the address in wrong. for example: classpath://$name
val services = context.getBeanNamesForType(IService::class.java)//services is empty
I have tried many other ways to load the xml but none of them was successful. for example:
val beans = DefaultListableBeanFactory(applicationContext)
val reader = XmlBeanDefinitionReader(beans)
reader.beanClassLoader = loader
reader.resourceLoader = resourceLoader
reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_XSD)
jarFile.getInputStream(jarEntry).use {
reader.loadBeanDefinitions(EncodedResource(InputStreamResource(it)))
}
beans.preInstantiateSingletons()
the xml inside jar file looks like this:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<import resource="classpath*:/xxx-logic-context.xml"/>
<context:annotation-config/>
<context:component-scan base-package="aa.bbb.ccc.server"/>
</beans>
It's really interesting: When I define regular Beans instead using package scaning feature, I can get the bean in a sort of code
Great answer from #talex guided me. I fixed it by setting the current class loader:
val loader = URLClassLoader(arrayOf(entry.toFile().toURL()), Thread.currentThread().contextClassLoader)
Thread.currentThread().contextClassLoader = loader
Related
I have gone through multiple stackoverflow threads but couldn't find a solution so posting this question. This is regarding how the xsd's are being mapped in spring container.
Below is the configuration in the context.xml
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
This works perfectly when the application is connected to internet, but the problem is when it works offline. It throws below error on start-up.
Caused by: org.xml.sax.SAXParseException; lineNumber: 7; columnNumber:
68; cvc-elt.1.a: Cannot find the declaration of element 'beans'.
If I explicitly point to the classpath like this,it works.
xsi:schemaLocation="http://www.springframework.org/schema/beans
classpath:/org/springframework/beans/factory/xml/spring-beans.xsd"
As per my understanding, Every spring jar shipped with the xsd and it is being mapped in META-INF/spring.schemas. The refered xds in the xml file should be able to load the local xsd available in the jar.
My concern is
Why it is unable to load the local xsd when there is no internet?
Of-course I can refactor all the xsi:schemaLocation to load from classpath but I have more than 25 xml files so instead of changing in all of them is there a better way to deal with it?
Spring version - spring-beans-5.1.5.RELEASE.jar
spring.schemas -
http\://www.springframework.org/schema/beans/spring-beans-2.0.xsd=org/springframework/beans/factory/xml/spring-beans.xsd
http\://www.springframework.org/schema/beans/spring-beans-2.5.xsd=org/springframework/beans/factory/xml/spring-beans.xsd
http\://www.springframework.org/schema/beans/spring-beans-3.0.xsd=org/springframework/beans/factory/xml/spring-beans.xsd
http\://www.springframework.org/schema/beans/spring-beans-3.1.xsd=org/springframework/beans/factory/xml/spring-beans.xsd
http\://www.springframework.org/schema/beans/spring-beans-3.2.xsd=org/springframework/beans/factory/xml/spring-beans.xsd
http\://www.springframework.org/schema/beans/spring-beans-4.0.xsd=org/springframework/beans/factory/xml/spring-beans.xsd
http\://www.springframework.org/schema/beans/spring-beans-4.1.xsd=org/springframework/beans/factory/xml/spring-beans.xsd
http\://www.springframework.org/schema/beans/spring-beans-4.2.xsd=org/springframework/beans/factory/xml/spring-beans.xsd
http\://www.springframework.org/schema/beans/spring-beans-4.3.xsd=org/springframework/beans/factory/xml/spring-beans.xsd
http\://www.springframework.org/schema/beans/spring-beans.xsd=org/springframework/beans/factory/xml/spring-beans.xsd
http\://www.springframework.org/schema/tool/spring-tool-2.0.xsd=org/springframework/beans/factory/xml/spring-tool.xsd
http\://www.springframework.org/schema/tool/spring-tool-2.5.xsd=org/springframework/beans/factory/xml/spring-tool.xsd
http\://www.springframework.org/schema/tool/spring-tool-3.0.xsd=org/springframework/beans/factory/xml/spring-tool.xsd
http\://www.springframework.org/schema/tool/spring-tool-3.1.xsd=org/springframework/beans/factory/xml/spring-tool.xsd
http\://www.springframework.org/schema/tool/spring-tool-3.2.xsd=org/springframework/beans/factory/xml/spring-tool.xsd
http\://www.springframework.org/schema/tool/spring-tool-4.0.xsd=org/springframework/beans/factory/xml/spring-tool.xsd
http\://www.springframework.org/schema/tool/spring-tool-4.1.xsd=org/springframework/beans/factory/xml/spring-tool.xsd
http\://www.springframework.org/schema/tool/spring-tool-4.2.xsd=org/springframework/beans/factory/xml/spring-tool.xsd
http\://www.springframework.org/schema/tool/spring-tool-4.3.xsd=org/springframework/beans/factory/xml/spring-tool.xsd
http\://www.springframework.org/schema/tool/spring-tool.xsd=org/springframework/beans/factory/xml/spring-tool.xsd
http\://www.springframework.org/schema/util/spring-util-2.0.xsd=org/springframework/beans/factory/xml/spring-util.xsd
http\://www.springframework.org/schema/util/spring-util-2.5.xsd=org/springframework/beans/factory/xml/spring-util.xsd
http\://www.springframework.org/schema/util/spring-util-3.0.xsd=org/springframework/beans/factory/xml/spring-util.xsd
http\://www.springframework.org/schema/util/spring-util-3.1.xsd=org/springframework/beans/factory/xml/spring-util.xsd
http\://www.springframework.org/schema/util/spring-util-3.2.xsd=org/springframework/beans/factory/xml/spring-util.xsd
http\://www.springframework.org/schema/util/spring-util-4.0.xsd=org/springframework/beans/factory/xml/spring-util.xsd
http\://www.springframework.org/schema/util/spring-util-4.1.xsd=org/springframework/beans/factory/xml/spring-util.xsd
http\://www.springframework.org/schema/util/spring-util-4.2.xsd=org/springframework/beans/factory/xml/spring-util.xsd
http\://www.springframework.org/schema/util/spring-util-4.3.xsd=org/springframework/beans/factory/xml/spring-util.xsd
http\://www.springframework.org/schema/util/spring-util.xsd=org/springframework/beans/factory/xml/spring-util.xsd
I'm writing a WebApp back-end with spring in java. in the code there are a lot of magic numbers. is there a way to put this in a config in such a way that any changes in this config will be put in effect without restarting the entire app?
When java process start it loads spring context, once spring context is loaded it only reads properties file once so if you are changing any property you have to restart your app thats good to have way.
OR you can replace java.util.Properties with a PropertiesConfiguration from the Apache Commons Configuration project. It supports automatic reloading, either by detecting when the file changes, or by triggering through JMX.
one more alternate way is to keep all your prop variables in database and refresh your reference cache periodically that way you don't have to restart your app and can change properties on-fly from database.
You can call the configuration file through the below steps:
Use the #Configuration annotation for the class which calls the
config file.
Another annotation to be declared above the class for defining the path to the config file #PropertySource({"URL/PATH_OF_THE_CONFIG_FILE"})
#Value("${PROPERTY_KEY}") annotation above a variable where the value corresponding to the property_key needs to be assigned.
The the following bean in the same configuration invoking class.
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
return new PropertySourcesPlaceholderConfigurer();
}
Make sure the #ComponentScan covers the folder where the config file is placed
Here is the way you can configure it
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemalocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<!--To load properties file -->
<bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:META-INF/*-config.properties">
</property></bean>
<bean id="createCustomer" class="com.example.Customer">
<property name="propertyToInject" value="${example.propertyNameUnderPropertyFile}">
</beans>
You can also refer it in java file straight away
public class Customer {
#Value("${example.propertyNameUnderPropertyFile}")
private String attr;
}
It seems like the Spring Batch 3.0.6 release points to the 2.2 schema by default.
In the spring.schemas file there is this definition
http\://www.springframework.org/schema/batch/spring-batch.xsd=/org/springframework/batch/core/configuration/xml/spring-batch-2.2.xsd
And when I add this namespace to my spring file, I then get the scope="step" option (in my IDE, although IntelliJ has been pretty reliable matching runtime issues)
...
xmlns:batch="http://www.springframework.org/schema/batch"
...
But everything seems to claim that scope="job" is invalid.
Is it the spring.schemas file doing this? Why would the 3.xx iteration point back to the 2.2 schemas?
I can't seem to get a declaration like xmlns:batch="http://www.springframework.org/schema/batch/spring-batch-3.0.xsd" to work. Surprisingly that totally invalidates the batch namespace. Even though the spring.schemas file points to 3.xx like so
http\://www.springframework.org/schema/batch/spring-batch-3.0.xsd=/org/springframework/batch/core/configuration/xml/spring-batch-3.0.xsd
If I do this:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:batch="http://www.springframework.org/schema/batch"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/batch
http://www.springframework.org/schema/batch/spring-batch-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
...
</beans>
I can then get the scope="step" to be valid, and everything seems to point to batch-3.0, but scope="job" is still invalid.
Does anyone have a clean example of importing batch & using a job scope declaration on a bean?
Thanks!
I am learner of spring have build my test project with spring IOC container and have configure beans.xml in my project root path and load into my application and get bean from it.
spring.xml in project root directory
BeanFactory bean = new XmlBeanFactory(new FileSystemResource("spring.xml"));
spring.xml in source file
BeanFactory bean = new XmlBeanFactory(new FileSystemResource("src/spring.xml"));
this is another code to load beans.xml file
ApplicationContext context = new GenericXmlApplicationContext("beans.xml");
my question is that is there any standards or conventions for creation of xml file name and location of file in real project.because in some reading articles i also found that there might be multiple xml files for large project like service.xml and dao.xml.
It can be useful to have bean definitions span multiple XML files. Often each individual XML configuration file represents a logical layer such as defining DAO beans etc. in your architecture but you should always place your XML configuration files under src/resources and access them as
new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});
From the Spring's Manual:
You can use the application context constructor to load bean definitions from all these XML fragments. This constructor takes multiple Resource locations, as was shown in the previous section. Alternatively, use one or more occurrences of the element to load bean definitions from another file or files. For example:
<beans>
<import resource="services.xml"/>
<import resource="resources/messageSource.xml"/>
<import resource="/resources/themeSource.xml"/>
</beans>
I recently startet working with JBoss' Wildfly 8.1 and the activiti framework.
I created two projects, one with my bpmn.xml file and the classes for the Service Tasks:
Process:
-src/main/
-impl.java
-src/resources/
-diagrams
-myprocess.bpmn.xml
-config
-activiti-context.xml
The other one holds the servlet
WebTest:
-src/main
-testServlet.java
-lib
-process.jar
in my servlet i implemented the init method to get the Activiti processEngine:
#Override
public void init() throws ServletException{
super.init();
engine = ProcessEngines.getDefaultProcessEngine();
}
I build the Webtest.war file and deploy it to
D:/path/to/workingdir/wildfly-8.1.0.Final/**standalone/deployments**/Webtest.war
Then i start up Widlfly using the provided standalone.bat, it starts up correctly and deploys to the context /Webtest, so far so good.
if i now access localhos:8080/Webtest/servlet i get the Exception:
org.activiti.engine.ActivitiException: couldn't initialize process engine from spring configuration resource vfs:/D:/path/to/workingdir/wildfly-8.1.0.Final/bin/content/TEST-1.war/WEB-INF/lib/process.jar/activiti-context.xml: null
the error with :null at the end implies that the file could not be accessed. of course it cannot, there is no bin/content!
my question now is: where does Widlfly get the idea to look at bin/content? it obviously was able to find the config file on itself, i never told spring or activiti to look in the process.jar, so the app finds the configuration in the classpath alright... then it proceeds to reading the file from an entirely different location that does not exist?
I dont know if this is of interesst, but here is my activiti-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration"/>
</beans>
thanks for any help or hints!