HHH-7994 Improve OsgiClassLoader performance
This commit is contained in:
parent
1e5fdfc689
commit
7611a5055c
|
@ -917,10 +917,7 @@ public class Ejb3Configuration implements Serializable, Referenceable {
|
|||
thread = Thread.currentThread();
|
||||
contextClassLoader = thread.getContextClassLoader();
|
||||
thread.setContextClassLoader( overridenClassLoader );
|
||||
builder.withApplicationClassLoader( overridenClassLoader );
|
||||
builder.withEnvironmentClassLoader( overridenClassLoader );
|
||||
builder.withHibernateClassLoader( overridenClassLoader );
|
||||
builder.withResourceClassLoader( overridenClassLoader );
|
||||
builder.with( overridenClassLoader );
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* JBoss, Home of Professional Open Source
|
||||
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
|
||||
* as indicated by the @authors tag. All rights reserved.
|
||||
* See the copyright.txt in the distribution for a
|
||||
* full listing of individual contributors.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License, v. 2.1.
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT A
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
* You should have received a copy of the GNU Lesser General Public License,
|
||||
* v.2.1 along with this distribution; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
package org.hibernate.osgi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
|
||||
import org.osgi.framework.Bundle;
|
||||
|
||||
/**
|
||||
* Integrates a Bundle, its key, and classes/resources that have been found
|
||||
* through its ClassLoader. Primarily used to clear the OsgiClassLoader
|
||||
* caches once the Bundle is deactivated.
|
||||
*
|
||||
* @author Brett Meyer
|
||||
*/
|
||||
public class CachedBundle {
|
||||
|
||||
private Bundle bundle;
|
||||
|
||||
private String key;
|
||||
|
||||
private List<String> classNames = new ArrayList<String>();
|
||||
|
||||
private List<String> resourceNames = new ArrayList<String>();
|
||||
|
||||
private List<String> resourceListNames = new ArrayList<String>();
|
||||
|
||||
public CachedBundle( Bundle bundle, String key ) {
|
||||
this.bundle = bundle;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public Class loadClass(String name) throws ClassNotFoundException {
|
||||
Class clazz = bundle.loadClass( name );
|
||||
if ( clazz != null ) {
|
||||
classNames.add( name );
|
||||
}
|
||||
return clazz;
|
||||
}
|
||||
|
||||
public URL getResource(String name) {
|
||||
URL resource = bundle.getResource( name );
|
||||
if ( resource != null ) {
|
||||
resourceNames.add( name );
|
||||
}
|
||||
return resource;
|
||||
}
|
||||
|
||||
public Enumeration getResources(String name) throws IOException {
|
||||
Enumeration resourceList = bundle.getResources( name );
|
||||
if ( resourceList != null ) {
|
||||
resourceListNames.add( name );
|
||||
}
|
||||
return resourceList;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public List<String> getClassNames() {
|
||||
return classNames;
|
||||
}
|
||||
|
||||
public List<String> getResourceNames() {
|
||||
return resourceNames;
|
||||
}
|
||||
|
||||
public List<String> getResourceListNames() {
|
||||
return resourceListNames;
|
||||
}
|
||||
}
|
|
@ -26,6 +26,8 @@ package org.hibernate.osgi;
|
|||
import java.net.URL;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.osgi.framework.Bundle;
|
||||
|
||||
|
@ -37,11 +39,13 @@ import org.osgi.framework.Bundle;
|
|||
*/
|
||||
public class OsgiClassLoader extends ClassLoader {
|
||||
|
||||
private HashMap<String, Bundle> bundles;
|
||||
private Map<String, CachedBundle> bundles = new HashMap<String, CachedBundle>();
|
||||
|
||||
public OsgiClassLoader() {
|
||||
bundles = new HashMap<String, Bundle>();
|
||||
}
|
||||
private Map<String, Class<?>> classCache = new HashMap<String, Class<?>>();
|
||||
|
||||
private Map<String, URL> resourceCache = new HashMap<String, URL>();
|
||||
|
||||
private Map<String, Enumeration<URL>> resourceListCache = new HashMap<String, Enumeration<URL>>();
|
||||
|
||||
/**
|
||||
* Load the class and break on first found match.
|
||||
|
@ -51,16 +55,15 @@ public class OsgiClassLoader extends ClassLoader {
|
|||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||
// TODO: This is horrible -- we shouldn't iterate over all the
|
||||
// classloaders every time we need to construct an entity, etc. Instead,
|
||||
// keep references to all classes/resources found in active bundles
|
||||
// in memory? Find a way to identify what we "care about" and keep
|
||||
// only those? Discover them the first time and then cache the
|
||||
// reference?
|
||||
for ( Bundle bundle : bundles.values() ) {
|
||||
if ( classCache.containsKey( name ) ) {
|
||||
return classCache.get( name );
|
||||
}
|
||||
|
||||
for ( CachedBundle bundle : bundles.values() ) {
|
||||
try {
|
||||
Class clazz = bundle.loadClass( name );
|
||||
if ( clazz != null ) {
|
||||
classCache.put( name, clazz );
|
||||
return clazz;
|
||||
}
|
||||
}
|
||||
|
@ -78,16 +81,15 @@ public class OsgiClassLoader extends ClassLoader {
|
|||
*/
|
||||
@Override
|
||||
protected URL findResource(String name) {
|
||||
// TODO: This is horrible -- we shouldn't iterate over all the
|
||||
// classloaders every time we need to construct an entity, etc. Instead,
|
||||
// keep references to all classes/resources found in active bundles
|
||||
// in memory? Find a way to identify what we "care about" and keep
|
||||
// only those? Discover them the first time and then cache the
|
||||
// reference?
|
||||
for ( Bundle bundle : bundles.values() ) {
|
||||
if ( resourceCache.containsKey( name ) ) {
|
||||
return resourceCache.get( name );
|
||||
}
|
||||
|
||||
for ( CachedBundle bundle : bundles.values() ) {
|
||||
try {
|
||||
URL resource = bundle.getResource( name );
|
||||
if ( resource != null ) {
|
||||
resourceCache.put( name, resource );
|
||||
return resource;
|
||||
}
|
||||
}
|
||||
|
@ -106,16 +108,15 @@ public class OsgiClassLoader extends ClassLoader {
|
|||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected Enumeration<URL> findResources(String name) {
|
||||
// TODO: This is horrible -- we shouldn't iterate over all the
|
||||
// classloaders every time we need to construct an entity, etc. Instead,
|
||||
// keep references to all classes/resources found in active bundles
|
||||
// in memory? Find a way to identify what we "care about" and keep
|
||||
// only those? Discover them the first time and then cache the
|
||||
// reference?
|
||||
for ( Bundle bundle : bundles.values() ) {
|
||||
if ( resourceListCache.containsKey( name ) ) {
|
||||
return resourceListCache.get( name );
|
||||
}
|
||||
|
||||
for ( CachedBundle bundle : bundles.values() ) {
|
||||
try {
|
||||
Enumeration<URL> resources = bundle.getResources( name );
|
||||
if ( resources != null ) {
|
||||
resourceListCache.put( name, resources );
|
||||
return resources;
|
||||
}
|
||||
}
|
||||
|
@ -132,11 +133,9 @@ public class OsgiClassLoader extends ClassLoader {
|
|||
public void registerBundle(Bundle bundle) {
|
||||
if ( bundle != null ) {
|
||||
synchronized ( bundles ) {
|
||||
// create a bundle classloader and add it to the list of
|
||||
// classloaders
|
||||
String key = getBundleKey( bundle );
|
||||
if ( !bundles.containsKey( key ) ) {
|
||||
bundles.put( key, bundle );
|
||||
bundles.put( key, new CachedBundle( bundle, key ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -148,17 +147,28 @@ public class OsgiClassLoader extends ClassLoader {
|
|||
public void unregisterBundle(Bundle bundle) {
|
||||
if ( bundle != null ) {
|
||||
synchronized ( bundles ) {
|
||||
// remove a bundle classloader for a given bundle
|
||||
String key = getBundleKey( bundle );
|
||||
if ( bundles.containsKey( key ) ) {
|
||||
bundles.remove( key );
|
||||
CachedBundle cachedBundle = bundles.remove( key );
|
||||
clearCache( classCache, cachedBundle.getClassNames() );
|
||||
clearCache( resourceCache, cachedBundle.getResourceNames() );
|
||||
clearCache( resourceListCache, cachedBundle.getResourceListNames() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void clearCache( Map cache, List<String> names ) {
|
||||
for ( String name : names ) {
|
||||
cache.remove( name );
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
bundles.clear();
|
||||
classCache.clear();
|
||||
resourceCache.clear();
|
||||
resourceListCache.clear();
|
||||
}
|
||||
|
||||
protected static String getBundleKey(Bundle bundle) {
|
||||
|
|
Loading…
Reference in New Issue