alzamabar
Jun 21st, 2008, 10:47 AM
Hi, I'm trying to create my only simple container. The idea is to have a jar with a Main class in it which has in its classpath Spring jars and my application. I could then start the container with something like:
java -jar myapp.jar
For this purpose, I created a sort of /lib folder with all Spring jars, including some other service jars such as log4j, commons, etc.
I also created a custom classloader, which I use to load all the above jars from the main class in the JAR file.
This is the main class:
package uk.co.jemos.tests;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* Hello world!
*
*/
public class Main
{
private static final String LIB_PATH = "C:" + File.separatorChar + "temp" +
File.separatorChar + "spring-lib";
public static void main( String[] args )
{
new Main().boot();
}
private void boot() {
Set<URL> urlSet = new HashSet<URL>();
try {
String path = ClassLoaderHelper.getPath(LIB_PATH + File.separatorChar);
urlSet.add(new URL("file", null, path));
path = ClassLoaderHelper.getPath(LIB_PATH + File.separatorChar + "ext" + File.separatorChar);
urlSet.add(new URL("file", null, path));
urlSet.add(new URL(this.getClass().getProtectionDomain().getCodeS ource().getLocation() +
this.getClass().getName().replace('.', '/') + ".class"));
URL[] jars = ClassLoaderHelper.getJarNames(urlSet);
System.out.println(Arrays.toString(jars));
URLClassLoader loader = URLClassLoader.newInstance(jars);
Class cl1 = loader.loadClass("org.springframework.context.support.ClassPathXmlAp plicationContext");
Constructor<?> c1 = cl1.getConstructor(String.class);
c1.newInstance("spring-config.xml");
Class cl2 = loader.loadClass("org.springframework.remoting.rmi.RmiRegistryFactor yBean");
System.out.println(cl2.getName());
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
The Classloader helper class and the spring configuration files are attached:
If I run the example, it works and it gives me the following:
[CODE]
C:\Projects\jemos-framework\target>java -jar jemos-framework-1.0-SNAPSHOT.jar
Class in classpath: C:\temp\spring-lib\ext\commons-digester.jar
Class in classpath: C:\temp\spring-lib\ext\commons-pool.jar
Class in classpath: C:\temp\spring-lib\spring-beans.jar
Class in classpath: C:\temp\spring-lib\spring-test.jar
Class in classpath: C:\temp\spring-lib\ext\commons-collections.jar
Class in classpath: C:\temp\spring-lib\ext\commons-lang.jar
Class in classpath: C:\temp\spring-lib\ext\commons-validator.jar
Class in classpath: C:\temp\spring-lib\spring-context-support.jar
Class in classpath: C:\temp\spring-lib\spring-core.jar
Class in classpath: C:\temp\spring-lib\ext\commons-io.jar
Class in classpath: C:\temp\spring-lib\ext\commons-discovery.jar
Class in classpath: C:\temp\spring-lib\spring-webmvc-portlet.jar
Class in classpath: C:\temp\spring-lib\ext\commons-codec.jar
Class in classpath: C:\temp\spring-lib\ext\log4j-1.2.15.jar
Class in classpath: C:\temp\spring-lib\spring-tx.jar
Class in classpath: C:\temp\spring-lib\spring-aop.jar
Class in classpath: C:\temp\spring-lib\ext\commons-httpclient.jar
Class in classpath: C:\temp\spring-lib\spring-sources.jar
Class in classpath: C:\temp\spring-lib\ext\commons-attributes-api.jar
Class in classpath: C:\temp\spring-lib\spring.jar
Class in classpath: C:\temp\spring-lib\spring-context.jar
Class in classpath: C:\temp\spring-lib\spring-jdbc.jar
Class in classpath: C:\temp\spring-lib\spring-orm.jar
Class in classpath: C:\temp\spring-lib\ext\commons-fileupload.jar
Class in classpath: C:\temp\spring-lib\ext\commons-beanutils.jar
Class in classpath: C:\temp\spring-lib\spring-webmvc-struts.jar
Class in classpath: C:\temp\spring-lib\spring-web.jar
Class in classpath: C:\temp\spring-lib\spring-webmvc.jar
Class in classpath: C:\temp\spring-lib\ext\commons-dbcp.jar
Class in classpath: C:\temp\spring-lib\spring-jms.jar
Class in classpath: C:\temp\spring-lib\ext\commons-logging.jar
Class in classpath: C:\temp\spring-lib\ext\commons-attributes-compiler.jar
[main] INFO org.springframework.context.support.ClassPathXmlAp plicationContext - Refreshing org.springf
[main] INFO org.springframework.beans.factory.xml.XmlBeanDefin itionReader - Loading XML bean definition
[main] INFO org.springframework.context.support.ClassPathXmlAp plicationContext - Bean factory for appli
[main] INFO org.springframework.beans.factory.support.DefaultL istableBeanFactory - Pre-instantiating si
RMI registry loaded from custom classloader: org.springframework.remoting.rmi.RmiRegistryFactor yBean
Please note the latest line, which tells us that the RmiRegistryFactoryBean has been loaded by the customised classloader.
However if I add the following bean declaration in the configuration file:
<bean class="org.springframework.remoting.rmi.RmiRegistryFactor yBean">
<property name="port" value="8889"></property>
</bean>
It gives this exception:
Caused by: java.lang.ClassNotFoundException: org.springframework.remoting.rmi.RmiRegistryFactor yBean
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at org.springframework.util.ClassUtils.forName(ClassU tils.java:249)
at org.springframework.beans.factory.support.Abstract BeanDefinition.resolveBeanClass(AbstractBeanDefini tion.java:381)
at org.springframework.beans.factory.support.Abstract BeanFactory.resolveBeanClass(AbstractBeanFactory.j ava:1135)
Notice that between before and now I didn't change the code. I just added a bean configuration. It's like Spring uses its own classloader to load the beans. Is there a way of telling Spring to use my classloader?
Thanks.
M.
java -jar myapp.jar
For this purpose, I created a sort of /lib folder with all Spring jars, including some other service jars such as log4j, commons, etc.
I also created a custom classloader, which I use to load all the above jars from the main class in the JAR file.
This is the main class:
package uk.co.jemos.tests;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* Hello world!
*
*/
public class Main
{
private static final String LIB_PATH = "C:" + File.separatorChar + "temp" +
File.separatorChar + "spring-lib";
public static void main( String[] args )
{
new Main().boot();
}
private void boot() {
Set<URL> urlSet = new HashSet<URL>();
try {
String path = ClassLoaderHelper.getPath(LIB_PATH + File.separatorChar);
urlSet.add(new URL("file", null, path));
path = ClassLoaderHelper.getPath(LIB_PATH + File.separatorChar + "ext" + File.separatorChar);
urlSet.add(new URL("file", null, path));
urlSet.add(new URL(this.getClass().getProtectionDomain().getCodeS ource().getLocation() +
this.getClass().getName().replace('.', '/') + ".class"));
URL[] jars = ClassLoaderHelper.getJarNames(urlSet);
System.out.println(Arrays.toString(jars));
URLClassLoader loader = URLClassLoader.newInstance(jars);
Class cl1 = loader.loadClass("org.springframework.context.support.ClassPathXmlAp plicationContext");
Constructor<?> c1 = cl1.getConstructor(String.class);
c1.newInstance("spring-config.xml");
Class cl2 = loader.loadClass("org.springframework.remoting.rmi.RmiRegistryFactor yBean");
System.out.println(cl2.getName());
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
The Classloader helper class and the spring configuration files are attached:
If I run the example, it works and it gives me the following:
[CODE]
C:\Projects\jemos-framework\target>java -jar jemos-framework-1.0-SNAPSHOT.jar
Class in classpath: C:\temp\spring-lib\ext\commons-digester.jar
Class in classpath: C:\temp\spring-lib\ext\commons-pool.jar
Class in classpath: C:\temp\spring-lib\spring-beans.jar
Class in classpath: C:\temp\spring-lib\spring-test.jar
Class in classpath: C:\temp\spring-lib\ext\commons-collections.jar
Class in classpath: C:\temp\spring-lib\ext\commons-lang.jar
Class in classpath: C:\temp\spring-lib\ext\commons-validator.jar
Class in classpath: C:\temp\spring-lib\spring-context-support.jar
Class in classpath: C:\temp\spring-lib\spring-core.jar
Class in classpath: C:\temp\spring-lib\ext\commons-io.jar
Class in classpath: C:\temp\spring-lib\ext\commons-discovery.jar
Class in classpath: C:\temp\spring-lib\spring-webmvc-portlet.jar
Class in classpath: C:\temp\spring-lib\ext\commons-codec.jar
Class in classpath: C:\temp\spring-lib\ext\log4j-1.2.15.jar
Class in classpath: C:\temp\spring-lib\spring-tx.jar
Class in classpath: C:\temp\spring-lib\spring-aop.jar
Class in classpath: C:\temp\spring-lib\ext\commons-httpclient.jar
Class in classpath: C:\temp\spring-lib\spring-sources.jar
Class in classpath: C:\temp\spring-lib\ext\commons-attributes-api.jar
Class in classpath: C:\temp\spring-lib\spring.jar
Class in classpath: C:\temp\spring-lib\spring-context.jar
Class in classpath: C:\temp\spring-lib\spring-jdbc.jar
Class in classpath: C:\temp\spring-lib\spring-orm.jar
Class in classpath: C:\temp\spring-lib\ext\commons-fileupload.jar
Class in classpath: C:\temp\spring-lib\ext\commons-beanutils.jar
Class in classpath: C:\temp\spring-lib\spring-webmvc-struts.jar
Class in classpath: C:\temp\spring-lib\spring-web.jar
Class in classpath: C:\temp\spring-lib\spring-webmvc.jar
Class in classpath: C:\temp\spring-lib\ext\commons-dbcp.jar
Class in classpath: C:\temp\spring-lib\spring-jms.jar
Class in classpath: C:\temp\spring-lib\ext\commons-logging.jar
Class in classpath: C:\temp\spring-lib\ext\commons-attributes-compiler.jar
[main] INFO org.springframework.context.support.ClassPathXmlAp plicationContext - Refreshing org.springf
[main] INFO org.springframework.beans.factory.xml.XmlBeanDefin itionReader - Loading XML bean definition
[main] INFO org.springframework.context.support.ClassPathXmlAp plicationContext - Bean factory for appli
[main] INFO org.springframework.beans.factory.support.DefaultL istableBeanFactory - Pre-instantiating si
RMI registry loaded from custom classloader: org.springframework.remoting.rmi.RmiRegistryFactor yBean
Please note the latest line, which tells us that the RmiRegistryFactoryBean has been loaded by the customised classloader.
However if I add the following bean declaration in the configuration file:
<bean class="org.springframework.remoting.rmi.RmiRegistryFactor yBean">
<property name="port" value="8889"></property>
</bean>
It gives this exception:
Caused by: java.lang.ClassNotFoundException: org.springframework.remoting.rmi.RmiRegistryFactor yBean
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at org.springframework.util.ClassUtils.forName(ClassU tils.java:249)
at org.springframework.beans.factory.support.Abstract BeanDefinition.resolveBeanClass(AbstractBeanDefini tion.java:381)
at org.springframework.beans.factory.support.Abstract BeanFactory.resolveBeanClass(AbstractBeanFactory.j ava:1135)
Notice that between before and now I didn't change the code. I just added a bean configuration. It's like Spring uses its own classloader to load the beans. Is there a way of telling Spring to use my classloader?
Thanks.
M.