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();
|
thread = Thread.currentThread();
|
||||||
contextClassLoader = thread.getContextClassLoader();
|
contextClassLoader = thread.getContextClassLoader();
|
||||||
thread.setContextClassLoader( overridenClassLoader );
|
thread.setContextClassLoader( overridenClassLoader );
|
||||||
builder.withApplicationClassLoader( overridenClassLoader );
|
builder.with( overridenClassLoader );
|
||||||
builder.withEnvironmentClassLoader( overridenClassLoader );
|
|
||||||
builder.withHibernateClassLoader( overridenClassLoader );
|
|
||||||
builder.withResourceClassLoader( overridenClassLoader );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
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.net.URL;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.osgi.framework.Bundle;
|
import org.osgi.framework.Bundle;
|
||||||
|
|
||||||
|
@ -37,11 +39,13 @@ import org.osgi.framework.Bundle;
|
||||||
*/
|
*/
|
||||||
public class OsgiClassLoader extends ClassLoader {
|
public class OsgiClassLoader extends ClassLoader {
|
||||||
|
|
||||||
private HashMap<String, Bundle> bundles;
|
private Map<String, CachedBundle> bundles = new HashMap<String, CachedBundle>();
|
||||||
|
|
||||||
public OsgiClassLoader() {
|
private Map<String, Class<?>> classCache = new HashMap<String, Class<?>>();
|
||||||
bundles = new HashMap<String, Bundle>();
|
|
||||||
}
|
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.
|
* Load the class and break on first found match.
|
||||||
|
@ -51,16 +55,15 @@ public class OsgiClassLoader extends ClassLoader {
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
@Override
|
@Override
|
||||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||||
// TODO: This is horrible -- we shouldn't iterate over all the
|
if ( classCache.containsKey( name ) ) {
|
||||||
// classloaders every time we need to construct an entity, etc. Instead,
|
return classCache.get( name );
|
||||||
// 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
|
for ( CachedBundle bundle : bundles.values() ) {
|
||||||
// reference?
|
|
||||||
for ( Bundle bundle : bundles.values() ) {
|
|
||||||
try {
|
try {
|
||||||
Class clazz = bundle.loadClass( name );
|
Class clazz = bundle.loadClass( name );
|
||||||
if ( clazz != null ) {
|
if ( clazz != null ) {
|
||||||
|
classCache.put( name, clazz );
|
||||||
return clazz;
|
return clazz;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,16 +81,15 @@ public class OsgiClassLoader extends ClassLoader {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected URL findResource(String name) {
|
protected URL findResource(String name) {
|
||||||
// TODO: This is horrible -- we shouldn't iterate over all the
|
if ( resourceCache.containsKey( name ) ) {
|
||||||
// classloaders every time we need to construct an entity, etc. Instead,
|
return resourceCache.get( name );
|
||||||
// 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
|
for ( CachedBundle bundle : bundles.values() ) {
|
||||||
// reference?
|
|
||||||
for ( Bundle bundle : bundles.values() ) {
|
|
||||||
try {
|
try {
|
||||||
URL resource = bundle.getResource( name );
|
URL resource = bundle.getResource( name );
|
||||||
if ( resource != null ) {
|
if ( resource != null ) {
|
||||||
|
resourceCache.put( name, resource );
|
||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,16 +108,15 @@ public class OsgiClassLoader extends ClassLoader {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
protected Enumeration<URL> findResources(String name) {
|
protected Enumeration<URL> findResources(String name) {
|
||||||
// TODO: This is horrible -- we shouldn't iterate over all the
|
if ( resourceListCache.containsKey( name ) ) {
|
||||||
// classloaders every time we need to construct an entity, etc. Instead,
|
return resourceListCache.get( name );
|
||||||
// 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
|
for ( CachedBundle bundle : bundles.values() ) {
|
||||||
// reference?
|
|
||||||
for ( Bundle bundle : bundles.values() ) {
|
|
||||||
try {
|
try {
|
||||||
Enumeration<URL> resources = bundle.getResources( name );
|
Enumeration<URL> resources = bundle.getResources( name );
|
||||||
if ( resources != null ) {
|
if ( resources != null ) {
|
||||||
|
resourceListCache.put( name, resources );
|
||||||
return resources;
|
return resources;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,11 +133,9 @@ public class OsgiClassLoader extends ClassLoader {
|
||||||
public void registerBundle(Bundle bundle) {
|
public void registerBundle(Bundle bundle) {
|
||||||
if ( bundle != null ) {
|
if ( bundle != null ) {
|
||||||
synchronized ( bundles ) {
|
synchronized ( bundles ) {
|
||||||
// create a bundle classloader and add it to the list of
|
|
||||||
// classloaders
|
|
||||||
String key = getBundleKey( bundle );
|
String key = getBundleKey( bundle );
|
||||||
if ( !bundles.containsKey( key ) ) {
|
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) {
|
public void unregisterBundle(Bundle bundle) {
|
||||||
if ( bundle != null ) {
|
if ( bundle != null ) {
|
||||||
synchronized ( bundles ) {
|
synchronized ( bundles ) {
|
||||||
// remove a bundle classloader for a given bundle
|
|
||||||
String key = getBundleKey( bundle );
|
String key = getBundleKey( bundle );
|
||||||
if ( bundles.containsKey( key ) ) {
|
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() {
|
public void clear() {
|
||||||
bundles.clear();
|
bundles.clear();
|
||||||
|
classCache.clear();
|
||||||
|
resourceCache.clear();
|
||||||
|
resourceListCache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static String getBundleKey(Bundle bundle) {
|
protected static String getBundleKey(Bundle bundle) {
|
||||||
|
|
Loading…
Reference in New Issue