Skip to content

Commit

Permalink
Register service ClassLoader when register processor. (sofastack#660)
Browse files Browse the repository at this point in the history
* register class cache
* add test cases
* register classloader
* remove unused commit
  • Loading branch information
zonghaishang committed Jul 1, 2019
1 parent c6c0bc7 commit f421322
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import com.alipay.sofa.rpc.common.utils.ClassLoaderUtils;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

Expand Down Expand Up @@ -80,6 +82,15 @@ public static void registerServiceClassLoader(String serviceUniqueName, ClassLoa
SERVICE_CLASSLOADER_MAP.put(serviceUniqueName, classloader);
}

/**
* 发注册服务的 ClassLoader
* @param serviceUniqueName
* @return
*/
public static ClassLoader unRegisterServiceClassLoader(String serviceUniqueName) {
return SERVICE_CLASSLOADER_MAP.remove(serviceUniqueName);
}

/**
* 得到服务的自定义ClassLoader
*
Expand All @@ -100,13 +111,13 @@ public static ClassLoader getServiceClassLoader(String serviceUniqueName) {
* String-->Class 缓存
*/
@VisibleForTesting
static final ConcurrentMap<String, Class> CLASS_CACHE = new ConcurrentHashMap<String, Class>();
static final ConcurrentMap<String, WeakHashMap<ClassLoader, Class>> CLASS_CACHE = new ConcurrentHashMap<String, WeakHashMap<ClassLoader, Class>>();

/**
* Class-->String 缓存
*/
@VisibleForTesting
static final ConcurrentMap<Class, String> TYPE_STR_CACHE = new ConcurrentHashMap<Class, String>();
static final ConcurrentMap<Class, String> TYPE_STR_CACHE = new ConcurrentHashMap<Class, String>();

/**
* 放入Class缓存
Expand All @@ -115,7 +126,8 @@ public static ClassLoader getServiceClassLoader(String serviceUniqueName) {
* @param clazz 类
*/
public static void putClassCache(String typeStr, Class clazz) {
CLASS_CACHE.put(typeStr, clazz);
CLASS_CACHE.putIfAbsent(typeStr, new WeakHashMap<ClassLoader, Class>());
CLASS_CACHE.get(typeStr).put(clazz.getClassLoader(), clazz);
}

/**
Expand All @@ -125,7 +137,13 @@ public static void putClassCache(String typeStr, Class clazz) {
* @return 类
*/
public static Class getClassCache(String typeStr) {
return CLASS_CACHE.get(typeStr);
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
return null;
} else {
Map<ClassLoader, Class> temp = CLASS_CACHE.get(typeStr);
return temp == null ? null : temp.get(classLoader);
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@
*/
package com.alipay.sofa.rpc.common.utils;

import com.alipay.sofa.rpc.common.cache.ReflectCache;
import org.junit.Assert;
import org.junit.Test;

import java.lang.reflect.Array;
import java.net.URL;
import java.net.URLClassLoader;

/**
*
Expand Down Expand Up @@ -107,6 +110,26 @@ class LocalType {
Assert.assertEquals(int[][].class, ClassTypeUtils.getClass(int[][].class.getName()));
}

@Test
public void testGetClassAccordingToTCL() {
// incompatible with JDK 9+
URLClassLoader current = (URLClassLoader) this.getClass().getClassLoader();
TempClassLoader t0 = new TempClassLoader(current.getURLs(), null);
TempClassLoader t1 = new TempClassLoader(current.getURLs(), null);

ClassLoader old = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(t0);
Class c0 = ClassTypeUtils.getClass(ClassTypeUtils.class.getCanonicalName());
Thread.currentThread().setContextClassLoader(t1);
Class c1 = ClassTypeUtils.getClass(ClassTypeUtils.class.getCanonicalName());

Thread.currentThread().setContextClassLoader(t0);
Assert.assertEquals(c0, ReflectCache.getClassCache(ClassTypeUtils.class.getCanonicalName()));
Thread.currentThread().setContextClassLoader(t1);
Assert.assertEquals(c1, ReflectCache.getClassCache(ClassTypeUtils.class.getCanonicalName()));
Thread.currentThread().setContextClassLoader(old);
}

@Test
public void testGetTypeStr() {

Expand Down Expand Up @@ -166,4 +189,11 @@ class LocalType {

class StaticClass {

}

class TempClassLoader extends URLClassLoader {

public TempClassLoader(URL[] urls, ClassLoader parent) {
super(urls, parent);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ public void registerProcessor(ProviderConfig providerConfig, Invoker instance) {
// 缓存Invoker对象
String key = ConfigUniqueNameGenerator.getUniqueName(providerConfig);
invokerMap.put(key, instance);
ReflectCache.registerServiceClassLoader(key, providerConfig.getProxyClass().getClassLoader());
// 缓存接口的方法
for (Method m : providerConfig.getProxyClass().getMethods()) {
ReflectCache.putOverloadMethodCache(key, m);
Expand All @@ -189,6 +190,7 @@ public void unRegisterProcessor(ProviderConfig providerConfig, boolean closeIfNo
// 取消缓存Invoker对象
String key = ConfigUniqueNameGenerator.getUniqueName(providerConfig);
invokerMap.remove(key);
ReflectCache.unRegisterServiceClassLoader(key);
// 如果最后一个需要关闭,则关闭
if (closeIfNoEntry && invokerMap.isEmpty()) {
stop();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@

import com.alipay.sofa.rpc.client.Cluster;
import com.alipay.sofa.rpc.common.RpcConstants;
import com.alipay.sofa.rpc.common.cache.ReflectCache;
import com.alipay.sofa.rpc.common.utils.ClassLoaderUtils;
import com.alipay.sofa.rpc.config.ConfigUniqueNameGenerator;
import com.alipay.sofa.rpc.config.ConsumerConfig;
import com.alipay.sofa.rpc.config.ProviderConfig;
import com.alipay.sofa.rpc.config.ServerConfig;
Expand All @@ -30,6 +33,8 @@
import org.junit.Assert;
import org.junit.Test;

import java.net.URL;
import java.net.URLClassLoader;
import java.util.Collections;

/**
Expand Down Expand Up @@ -165,4 +170,58 @@ public void testAttrUpdate() {
}
Assert.assertFalse(error);
}
}

@Test
public void testProviderClassLoader() throws Throwable {
// 发布一个服务
ServerConfig serverConfig = new ServerConfig()
.setStopTimeout(0)
.setPort(22223)
.setProtocol(RpcConstants.PROTOCOL_TYPE_BOLT)
.setQueues(100).setCoreThreads(5).setMaxThreads(5);
ProviderConfig<HelloService> providerConfig0 = new ProviderConfig<HelloService>()
.setId("p-0")
.setUniqueId("p-0")
.setInterfaceId(HelloService.class.getName())
.setRef(new HelloServiceImpl(2000))
.setServer(serverConfig)
.setRegister(false);
providerConfig0.export();

// incompatible with JDK 9+
URLClassLoader currentClassLoader = (URLClassLoader) this.getClass().getClassLoader();
TempClassLoader tempClassLoader = new TempClassLoader(currentClassLoader.getURLs(), null);
Class helloService = tempClassLoader.loadClass(HelloService.class.getCanonicalName());
Class helloServiceImpl = tempClassLoader.loadClass(HelloServiceImpl.class.getCanonicalName());

ProviderConfig<Object> providerConfig1 = new ProviderConfig<Object>()
.setId("p-1")
.setUniqueId("p-1")
.setInterfaceId(HelloService.class.getName())
.setProxyClass(helloService)
.setRef(helloServiceImpl.getConstructor(int.class).newInstance(2000))
.setServer(serverConfig)
.setRegister(false);
providerConfig1.export();

ClassLoader cl0 = ReflectCache.getServiceClassLoader(ConfigUniqueNameGenerator.getUniqueName(providerConfig0));
ClassLoader cl1 = ReflectCache.getServiceClassLoader(ConfigUniqueNameGenerator.getUniqueName(providerConfig1));

Assert.assertEquals(currentClassLoader, cl0);
Assert.assertEquals(tempClassLoader, cl1);

providerConfig0.unExport();
providerConfig1.unExport();
cl0 = ReflectCache.getServiceClassLoader(ConfigUniqueNameGenerator.getUniqueName(providerConfig0));
cl1 = ReflectCache.getServiceClassLoader(ConfigUniqueNameGenerator.getUniqueName(providerConfig1));
Assert.assertEquals(ClassLoaderUtils.getCurrentClassLoader(), cl0);
Assert.assertEquals(ClassLoaderUtils.getCurrentClassLoader(), cl1);
}
}

class TempClassLoader extends URLClassLoader {

public TempClassLoader(URL[] urls, ClassLoader parent) {
super(urls, parent);
}
}

0 comments on commit f421322

Please sign in to comment.