com.alipay.sofa.ark.springboot.loader.CachedLaunchedURLClassLoader Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alipay.sofa.ark.springboot.loader;
import org.springframework.boot.loader.launch.Archive;
import org.springframework.boot.loader.launch.LaunchedClassLoader;
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
/**
* A cached LaunchedURLClassLoader to accelerate load classes and resources.
* NOTE:
* 1. Not found classes will be cached.
* 2. If findResources(name) return null Enumeration, then it will be cached.
* 3. findResource(name) will always be cached no matter it was found or not found.
* 4. Otherwise, classes or resources-enumeration will not be cached explicitly.
*
* @author bingjie.lbj
*/
public class CachedLaunchedURLClassLoader extends LaunchedClassLoader {
private final Map classCache = new ConcurrentHashMap<>(
3000);
private final Map> resourceUrlCache = new ConcurrentHashMap<>(
3000);
private final Map>> resourcesUrlCache = new ConcurrentHashMap<>(
300);
static {
ClassLoader.registerAsParallelCapable();
}
public CachedLaunchedURLClassLoader(boolean exploded, Archive rootArchive, URL[] urls,
ClassLoader parent) {
super(exploded, rootArchive, urls, parent);
}
@Override
protected Class> loadClass(String name, boolean resolve) throws ClassNotFoundException {
return loadClassWithCache(name, resolve);
}
@Override
public URL findResource(String name) {
Optional urlOptional = resourceUrlCache.get(name);
if (urlOptional != null) {
return urlOptional.orElse(null);
}
URL url = super.findResource(name);
resourceUrlCache.put(name, url != null ? Optional.of(url) : Optional.empty());
return url;
}
@Override
public Enumeration findResources(String name) throws IOException {
Optional> urlOptional = resourcesUrlCache.get(name);
if (urlOptional != null) {
return urlOptional.orElse(null);
}
Enumeration enumeration = super.findResources(name);
if (enumeration == null || !enumeration.hasMoreElements()) {
resourcesUrlCache.put(name, Optional.empty());
}
return enumeration;
}
/**
* NOTE: Only cache ClassNotFoundException when class not found.
* If class found, do not cache, and just use parent class loader cache.
*
* @param name
* @param resolve
* @return
* @throws ClassNotFoundException
*/
protected Class> loadClassWithCache(String name, boolean resolve)
throws ClassNotFoundException {
LoadClassResult resultInCache = classCache.get(name);
if (resultInCache != null) {
if (resultInCache.getEx() != null) {
throw resultInCache.getEx();
}
return resultInCache.getClazz();
}
try {
Class> clazz = super.findLoadedClass(name);
if (clazz == null) {
clazz = super.loadClass(name, resolve);
}
if (clazz == null) {
classCache.put(name, LoadClassResult.NOT_FOUND);
}
return clazz;
} catch (ClassNotFoundException exception) {
classCache.put(name, LoadClassResult.NOT_FOUND);
throw exception;
}
}
protected static class LoadClassResult {
private Class> clazz;
private ClassNotFoundException ex;
protected static LoadClassResult NOT_FOUND = new LoadClassResult(
new ClassNotFoundException());
public LoadClassResult() {
}
public LoadClassResult(ClassNotFoundException ex) {
this.ex = ex;
}
public Class> getClazz() {
return clazz;
}
public void setClazz(Class> clazz) {
this.clazz = clazz;
}
public ClassNotFoundException getEx() {
return ex;
}
public void setEx(ClassNotFoundException ex) {
this.ex = ex;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy