首先继承ClassLoader类,如果不希望双亲委派,重写loadClass方法,否则重写findClass方法,以下是一次业务中的使用
import org.springframework.util.Base64Utils;
// 此classloader用于网络传输,从服务器下载licenseFilter
public class NetworkClassLoader extends ClassLoader {
// 根路径
private String rootUrl;
public NetworkClassLoader(String rootUrl) {
super(NetworkClassLoader.class.getClassLoader());
this.rootUrl = rootUrl;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] classData = getClassData(name);
if (classData == null) {
throw new ClassNotFoundException();
}
return defineClass(name, classData, 0, classData.length);
}
// 获取class二进制数据
private byte[] getClassData(String name) {
try {
// 下载源class文件
/*String path = classNameToPath(name);
URL url = new URL(path);
InputStream is = url.openStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
IOUtils.copy(is, baos);
IOUtils.closeQuietly(is);
return baos.toByteArray();*/
// 源licenseFilter字节码文件使用了aes加密,从服务器获取加密后的数据
String s = HttpTookit.doGet(AdminManageConfig.ADMIN_MANAGE_LOAD_CLASS, null);
// aes解密
String ss = EncrypAES.decrypt(s);
return Base64Utils.decodeFromString(ss);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/*private String classNameToPath(String name) {
return rootUrl + name.replace(".", "/") + ".class";
}*/
}
filterconfig中使用
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;
@Configuration
public class FilterConfig {
// 注入配置文件中的license和私钥
@Value("${license.license}")
private String license;
@Value("${license.private_key}")
private String private_key;
@Bean
public FilterRegistrationBean licenseFilterRegistration() throws Exception {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.addInitParameter("license", license);
registration.addInitParameter("private_key", private_key);
registration.setDispatcherTypes(DispatcherType.REQUEST);
// 使用自定义classloader加载licenseFilter
NetworkClassLoader loader = new NetworkClassLoader(AdminManageConfig.ADMIN_MANAGE_URL);
registration.setFilter((Filter) loader.loadClass("LicenseFilter").newInstance());
registration.addUrlPatterns("/*");
registration.setName("licenseFilter");
registration.setOrder(Integer.MAX_VALUE - 2);
return registration;
}
}
注:
自定义NetworkClassLoader构造方法中,使用了super(NetworkClassLoader.class.getClassLoader());,如果使用super(),在tomcat中会报NoClassDefFoundError异常,而springboot中没报异常,原因加载继承的filter时,双亲委派由父级加载,由于tomcat中filter由URLClassLoader加载,不指定父级加载器,默认是AppClassLoader,都加载不成功报错,而springboot中使用RestartClassLoader,父级也是AppClassLoader,导致在AppClassLoader可以获取到filter而不报错