HHH-8015 Spring 3.2.1 cannot be deployed on JBoss AS7 with Hibernate 4.1.6 due to class loader issues.

This commit is contained in:
Strong Liu 2013-02-18 23:39:23 +08:00
parent 52f2edfa45
commit a6c46408df
3 changed files with 208 additions and 122 deletions

View File

@ -494,6 +494,14 @@ public interface AvailableSettings {
*/ */
public static final String NON_CONTEXTUAL_LOB_CREATION = "hibernate.jdbc.lob.non_contextual_creation"; public static final String NON_CONTEXTUAL_LOB_CREATION = "hibernate.jdbc.lob.non_contextual_creation";
/**
* Used to define a {@link java.util.Collection} of the {@link ClassLoader} instances Hibernate should use for
* class-loading and resource-lookups.
*
* @since 4.2
*/
public static final String CLASSLOADERS = "hibernate.classLoaders";
/** /**
* Names the {@link ClassLoader} used to load user application classes. * Names the {@link ClassLoader} used to load user application classes.
* @since 4.0 * @since 4.0

View File

@ -23,11 +23,14 @@
*/ */
package org.hibernate.service; package org.hibernate.service;
import java.util.ArrayList;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List;
import org.hibernate.integrator.internal.IntegratorServiceImpl; import org.hibernate.integrator.internal.IntegratorServiceImpl;
import org.hibernate.integrator.spi.Integrator; import org.hibernate.integrator.spi.Integrator;
import org.hibernate.service.classloading.internal.ClassLoaderServiceImpl; import org.hibernate.service.classloading.internal.ClassLoaderServiceImpl;
import org.hibernate.service.classloading.spi.ClassLoaderService;
import org.hibernate.service.internal.BootstrapServiceRegistryImpl; import org.hibernate.service.internal.BootstrapServiceRegistryImpl;
/** /**
@ -40,10 +43,8 @@ import org.hibernate.service.internal.BootstrapServiceRegistryImpl;
*/ */
public class BootstrapServiceRegistryBuilder { public class BootstrapServiceRegistryBuilder {
private final LinkedHashSet<Integrator> providedIntegrators = new LinkedHashSet<Integrator>(); private final LinkedHashSet<Integrator> providedIntegrators = new LinkedHashSet<Integrator>();
private ClassLoader applicationClassLoader; private List<ClassLoader> providedClassLoaders;
private ClassLoader resourcesClassLoader; private ClassLoaderService providedClassLoaderService;
private ClassLoader hibernateClassLoader;
private ClassLoader environmentClassLoader;
/** /**
* Add an {@link Integrator} to be applied to the bootstrap registry. * Add an {@link Integrator} to be applied to the bootstrap registry.
@ -61,23 +62,56 @@ public class BootstrapServiceRegistryBuilder {
* *
* @param classLoader The class loader to use * @param classLoader The class loader to use
* @return {@code this}, for method chaining * @return {@code this}, for method chaining
*
* @deprecated Use {@link #with(ClassLoader)} instead
*/ */
@SuppressWarnings( {"UnusedDeclaration"}) @SuppressWarnings( {"UnusedDeclaration"})
@Deprecated
public BootstrapServiceRegistryBuilder withApplicationClassLoader(ClassLoader classLoader) { public BootstrapServiceRegistryBuilder withApplicationClassLoader(ClassLoader classLoader) {
this.applicationClassLoader = classLoader; return with( classLoader );
}
/**
* Adds a provided {@link ClassLoader} for use in class-loading and resource-lookup
*
* @param classLoader The class loader to use
*
* @return {@code this}, for method chaining
*/
public BootstrapServiceRegistryBuilder with(ClassLoader classLoader) {
if ( providedClassLoaders == null ) {
providedClassLoaders = new ArrayList<ClassLoader>();
}
providedClassLoaders.add( classLoader );
return this; return this;
} }
/**
* Adds a provided {@link ClassLoaderService} for use in class-loading and resource-lookup
*
* @param classLoaderService The class loader to use
*
* @return {@code this}, for method chaining
*/
public BootstrapServiceRegistryBuilder with(ClassLoaderService classLoaderService) {
providedClassLoaderService = classLoaderService;
return this;
}
/** /**
* Applies the specified {@link ClassLoader} as the resource class loader for the bootstrap registry * Applies the specified {@link ClassLoader} as the resource class loader for the bootstrap registry
* *
* @param classLoader The class loader to use * @param classLoader The class loader to use
* @return {@code this}, for method chaining * @return {@code this}, for method chaining
*
* @deprecated Use {@link #with(ClassLoader)} instead
*/ */
@Deprecated
@SuppressWarnings( {"UnusedDeclaration"}) @SuppressWarnings( {"UnusedDeclaration"})
public BootstrapServiceRegistryBuilder withResourceClassLoader(ClassLoader classLoader) { public BootstrapServiceRegistryBuilder withResourceClassLoader(ClassLoader classLoader) {
this.resourcesClassLoader = classLoader; return with( classLoader );
return this;
} }
/** /**
@ -85,11 +119,13 @@ public class BootstrapServiceRegistryBuilder {
* *
* @param classLoader The class loader to use * @param classLoader The class loader to use
* @return {@code this}, for method chaining * @return {@code this}, for method chaining
*
* @deprecated Use {@link #with(ClassLoader)} instead
*/ */
@SuppressWarnings( {"UnusedDeclaration"}) @SuppressWarnings( {"UnusedDeclaration"})
@Deprecated
public BootstrapServiceRegistryBuilder withHibernateClassLoader(ClassLoader classLoader) { public BootstrapServiceRegistryBuilder withHibernateClassLoader(ClassLoader classLoader) {
this.hibernateClassLoader = classLoader; return with( classLoader );
return this;
} }
/** /**
@ -97,11 +133,13 @@ public class BootstrapServiceRegistryBuilder {
* *
* @param classLoader The class loader to use * @param classLoader The class loader to use
* @return {@code this}, for method chaining * @return {@code this}, for method chaining
*
* @deprecated Use {@link #with(ClassLoader)} instead
*/ */
@SuppressWarnings( {"UnusedDeclaration"}) @SuppressWarnings( {"UnusedDeclaration"})
@Deprecated
public BootstrapServiceRegistryBuilder withEnvironmentClassLoader(ClassLoader classLoader) { public BootstrapServiceRegistryBuilder withEnvironmentClassLoader(ClassLoader classLoader) {
this.environmentClassLoader = classLoader; return with( classLoader );
return this;
} }
/** /**
@ -110,12 +148,12 @@ public class BootstrapServiceRegistryBuilder {
* @return The built bootstrap registry * @return The built bootstrap registry
*/ */
public BootstrapServiceRegistry build() { public BootstrapServiceRegistry build() {
final ClassLoaderServiceImpl classLoaderService = new ClassLoaderServiceImpl( final ClassLoaderService classLoaderService;
applicationClassLoader, if ( providedClassLoaderService == null ) {
resourcesClassLoader, classLoaderService = new ClassLoaderServiceImpl( providedClassLoaders );
hibernateClassLoader, } else {
environmentClassLoader classLoaderService = providedClassLoaderService;
); }
final IntegratorServiceImpl integratorService = new IntegratorServiceImpl( final IntegratorServiceImpl integratorService = new IntegratorServiceImpl(
providedIntegrators, providedIntegrators,

View File

@ -27,6 +27,9 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL; import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
@ -35,6 +38,8 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.ServiceLoader; import java.util.ServiceLoader;
import org.jboss.logging.Logger;
import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.AvailableSettings;
import org.hibernate.service.classloading.spi.ClassLoaderService; import org.hibernate.service.classloading.spi.ClassLoaderService;
import org.hibernate.service.classloading.spi.ClassLoadingException; import org.hibernate.service.classloading.spi.ClassLoadingException;
@ -45,74 +50,74 @@ import org.hibernate.service.classloading.spi.ClassLoadingException;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class ClassLoaderServiceImpl implements ClassLoaderService { public class ClassLoaderServiceImpl implements ClassLoaderService {
private final ClassLoader classClassLoader; private static final Logger log = Logger.getLogger( ClassLoaderServiceImpl.class );
private final ClassLoader resourcesClassLoader;
private final ClassLoader aggregatedClassLoader;
public ClassLoaderServiceImpl() { public ClassLoaderServiceImpl() {
this( ClassLoaderServiceImpl.class.getClassLoader() ); this( ClassLoaderServiceImpl.class.getClassLoader() );
} }
public ClassLoaderServiceImpl(ClassLoader classLoader) { public ClassLoaderServiceImpl(ClassLoader classLoader) {
this( classLoader, classLoader, classLoader, classLoader ); this( Collections.singletonList( classLoader ) );
} }
public ClassLoaderServiceImpl( public ClassLoaderServiceImpl(List<ClassLoader> providedClassLoaders) {
ClassLoader applicationClassLoader, final LinkedHashSet<ClassLoader> orderedClassLoaderSet = new LinkedHashSet<ClassLoader>();
ClassLoader resourcesClassLoader,
ClassLoader hibernateClassLoader,
ClassLoader environmentClassLoader) {
// Normalize missing loaders
if ( hibernateClassLoader == null ) {
hibernateClassLoader = ClassLoaderServiceImpl.class.getClassLoader();
}
if ( environmentClassLoader == null || applicationClassLoader == null ) { // first add all provided class loaders, if any
ClassLoader sysClassLoader = locateSystemClassLoader(); if ( providedClassLoaders != null ) {
ClassLoader tccl = locateTCCL(); for ( ClassLoader classLoader : providedClassLoaders ) {
if ( environmentClassLoader == null ) { if ( classLoader != null ) {
environmentClassLoader = sysClassLoader != null ? sysClassLoader : hibernateClassLoader; orderedClassLoaderSet.add( classLoader );
} }
if ( applicationClassLoader == null ) {
applicationClassLoader = tccl != null ? tccl : hibernateClassLoader;
} }
} }
if ( resourcesClassLoader == null ) { // normalize adding known class-loaders...
resourcesClassLoader = applicationClassLoader; // first the Hibernate class loader
orderedClassLoaderSet.add( ClassLoaderServiceImpl.class.getClassLoader() );
// then the TCCL, if one...
final ClassLoader tccl = locateTCCL();
if ( tccl != null ) {
orderedClassLoaderSet.add( tccl );
}
// finally the system classloader
final ClassLoader sysClassLoader = locateSystemClassLoader();
if ( sysClassLoader != null ) {
orderedClassLoaderSet.add( sysClassLoader );
} }
final LinkedHashSet<ClassLoader> classLoadingClassLoaders = new LinkedHashSet<ClassLoader>(); // now build the aggregated class loader...
classLoadingClassLoaders.add( applicationClassLoader ); this.aggregatedClassLoader = new AggregatedClassLoader( orderedClassLoaderSet );
classLoadingClassLoaders.add( hibernateClassLoader );
classLoadingClassLoaders.add( environmentClassLoader );
this.classClassLoader = new ClassLoader(null) {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
for ( ClassLoader loader : classLoadingClassLoaders ) {
try {
return loader.loadClass( name );
}
catch (Exception ignore) {
}
}
throw new ClassNotFoundException( "Could not load requested class : " + name );
}
};
this.resourcesClassLoader = resourcesClassLoader;
} }
@SuppressWarnings( {"UnusedDeclaration"}) @SuppressWarnings({"UnusedDeclaration", "unchecked", "deprecation"})
@Deprecated
public static ClassLoaderServiceImpl fromConfigSettings(Map configVales) { public static ClassLoaderServiceImpl fromConfigSettings(Map configVales) {
return new ClassLoaderServiceImpl( final List<ClassLoader> providedClassLoaders = new ArrayList<ClassLoader>();
(ClassLoader) configVales.get( AvailableSettings.APP_CLASSLOADER ),
(ClassLoader) configVales.get( AvailableSettings.RESOURCES_CLASSLOADER ), final Collection<ClassLoader> classLoaders = (Collection<ClassLoader>) configVales.get( AvailableSettings.CLASSLOADERS );
(ClassLoader) configVales.get( AvailableSettings.HIBERNATE_CLASSLOADER ), if ( classLoaders != null ) {
(ClassLoader) configVales.get( AvailableSettings.ENVIRONMENT_CLASSLOADER ) for ( ClassLoader classLoader : classLoaders ) {
); providedClassLoaders.add( classLoader );
}
} }
addIfSet( providedClassLoaders, AvailableSettings.APP_CLASSLOADER, configVales );
addIfSet( providedClassLoaders, AvailableSettings.RESOURCES_CLASSLOADER, configVales );
addIfSet( providedClassLoaders, AvailableSettings.HIBERNATE_CLASSLOADER, configVales );
addIfSet( providedClassLoaders, AvailableSettings.ENVIRONMENT_CLASSLOADER, configVales );
return new ClassLoaderServiceImpl( providedClassLoaders );
}
private static void addIfSet(List<ClassLoader> providedClassLoaders, String name, Map configVales) {
final ClassLoader providedClassLoader = (ClassLoader) configVales.get( name );
if ( providedClassLoader != null ) {
providedClassLoaders.add( providedClassLoader );
}
}
private static ClassLoader locateSystemClassLoader() { private static ClassLoader locateSystemClassLoader() {
try { try {
return ClassLoader.getSystemClassLoader(); return ClassLoader.getSystemClassLoader();
@ -135,7 +140,7 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
@SuppressWarnings( {"unchecked"}) @SuppressWarnings( {"unchecked"})
public <T> Class<T> classForName(String className) { public <T> Class<T> classForName(String className) {
try { try {
return (Class<T>) Class.forName( className, true, classClassLoader ); return (Class<T>) Class.forName( className, true, aggregatedClassLoader );
} }
catch (Exception e) { catch (Exception e) {
throw new ClassLoadingException( "Unable to load class [" + className + "]", e ); throw new ClassLoadingException( "Unable to load class [" + className + "]", e );
@ -152,7 +157,7 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
} }
try { try {
return resourcesClassLoader.getResource( name ); return aggregatedClassLoader.getResource( name );
} }
catch ( Exception ignore ) { catch ( Exception ignore ) {
} }
@ -164,17 +169,43 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
public InputStream locateResourceStream(String name) { public InputStream locateResourceStream(String name) {
// first we try name as a URL // first we try name as a URL
try { try {
log.tracef( "trying via [new URL(\"%s\")]", name );
return new URL( name ).openStream(); return new URL( name ).openStream();
} }
catch ( Exception ignore ) { catch ( Exception ignore ) {
} }
try { try {
return resourcesClassLoader.getResourceAsStream( name ); log.tracef( "trying via [ClassLoader.getResourceAsStream(\"%s\")]", name );
InputStream stream = aggregatedClassLoader.getResourceAsStream( name );
if ( stream != null ) {
return stream;
}
} }
catch ( Exception ignore ) { catch ( Exception ignore ) {
} }
final String stripped = name.startsWith( "/" ) ? name.substring(1) : null;
if ( stripped != null ) {
try {
log.tracef( "trying via [new URL(\"%s\")]", stripped );
return new URL( stripped ).openStream();
}
catch ( Exception ignore ) {
}
try {
log.tracef( "trying via [ClassLoader.getResourceAsStream(\"%s\")]", stripped );
InputStream stream = aggregatedClassLoader.getResourceAsStream( stripped );
if ( stream != null ) {
return stream;
}
}
catch ( Exception ignore ) {
}
}
return null; return null;
} }
@ -182,7 +213,7 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
public List<URL> locateResources(String name) { public List<URL> locateResources(String name) {
ArrayList<URL> urls = new ArrayList<URL>(); ArrayList<URL> urls = new ArrayList<URL>();
try { try {
Enumeration<URL> urlEnumeration = resourcesClassLoader.getResources( name ); Enumeration<URL> urlEnumeration = aggregatedClassLoader.getResources( name );
if ( urlEnumeration != null && urlEnumeration.hasMoreElements() ) { if ( urlEnumeration != null && urlEnumeration.hasMoreElements() ) {
while ( urlEnumeration.hasMoreElements() ) { while ( urlEnumeration.hasMoreElements() ) {
urls.add( urlEnumeration.nextElement() ); urls.add( urlEnumeration.nextElement() );
@ -197,21 +228,27 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
@Override @Override
public <S> LinkedHashSet<S> loadJavaServices(Class<S> serviceContract) { public <S> LinkedHashSet<S> loadJavaServices(Class<S> serviceContract) {
final ClassLoader serviceLoaderClassLoader = new ClassLoader(null) { final ServiceLoader<S> loader = ServiceLoader.load( serviceContract, aggregatedClassLoader );
final ClassLoader[] classLoaderArray = new ClassLoader[] { final LinkedHashSet<S> services = new LinkedHashSet<S>();
// first look on the hibernate class loader for ( S service : loader ) {
getClass().getClassLoader(), services.add( service );
// next look on the resource class loader }
resourcesClassLoader,
// finally look on the combined class class loader return services;
classClassLoader }
}; private static class AggregatedClassLoader extends ClassLoader {
private final ClassLoader[] individualClassLoaders;
private AggregatedClassLoader(final LinkedHashSet<ClassLoader> orderedClassLoaderSet) {
super( null );
individualClassLoaders = orderedClassLoaderSet.toArray( new ClassLoader[ orderedClassLoaderSet.size() ] );
}
@Override @Override
public Enumeration<URL> getResources(String name) throws IOException { public Enumeration<URL> getResources(String name) throws IOException {
final HashSet<URL> resourceUrls = new HashSet<URL>(); final HashSet<URL> resourceUrls = new HashSet<URL>();
for ( ClassLoader classLoader : classLoaderArray ) { for ( ClassLoader classLoader : individualClassLoaders ) {
final Enumeration<URL> urls = classLoader.getResources( name ); final Enumeration<URL> urls = classLoader.getResources( name );
while ( urls.hasMoreElements() ) { while ( urls.hasMoreElements() ) {
resourceUrls.add( urls.nextElement() ); resourceUrls.add( urls.nextElement() );
@ -232,9 +269,20 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
}; };
} }
@Override
protected URL findResource(String name) {
for ( ClassLoader classLoader : individualClassLoaders ) {
final URL resource = classLoader.getResource( name );
if ( resource != null ) {
return resource;
}
}
return super.findResource( name );
}
@Override @Override
protected Class<?> findClass(String name) throws ClassNotFoundException { protected Class<?> findClass(String name) throws ClassNotFoundException {
for ( ClassLoader classLoader : classLoaderArray ) { for ( ClassLoader classLoader : individualClassLoaders ) {
try { try {
return classLoader.loadClass( name ); return classLoader.loadClass( name );
} }
@ -244,14 +292,6 @@ public class ClassLoaderServiceImpl implements ClassLoaderService {
throw new ClassNotFoundException( "Could not load requested class : " + name ); throw new ClassNotFoundException( "Could not load requested class : " + name );
} }
};
final ServiceLoader<S> loader = ServiceLoader.load( serviceContract, serviceLoaderClassLoader );
final LinkedHashSet<S> services = new LinkedHashSet<S>();
for ( S service : loader ) {
services.add( service );
} }
return services;
}
} }