目前业务有个需求,须要使用多线程同时去获取不一样类型的数据。在获取数据时,须要作签名检验,签名校验的包由第三方提供 (咱们没法修改),如今的问题是,线程启动后,第一个类型的数据能够被成功获取,可是后面类型的数据就会提示签名失败。可是单独拉后面类型的数据时,又能够成功,进过排查,发现是第三方包中的一个核心类其中有不少变量被设置为了static, 每一个线程都会去设置这些static变量值,致使签名检验失败。如下是几种解决策略:java
1. 将多线程换成单线程; 加锁,使得每次只有一个线程在真正执行。 因为第三方包一个static变量会在初始化时追加上次的记录,致使这种方法也不能解决问题。多线程
2. 将多线程换成多进程。每一个进程处理一个类型,类型之间互相独立。(能够解决,可是一样代码却得部署多个应用,不爽!)this
3. 想办法让不一样类型对应的静态变量互相隔离--使用不一样的classloader加载类,使得对应的类互相不同的 。可是这种状况,不能将新定义的对象为‘原’对象。如如下代码是会抛出异常的:url
URLClassLoader classLoader1 = new URLClassLoader(urls); URLClassLoader classLoader2 =new URLClassLoader(urls); Class<?> clazz1= classLoader1.loadClass(Hello.class.getName()); Class<?> clazz2= classLoader2.loadClass(Hello.class.getName()); Hello hello1=(Hello) clazz1.newInstance(); Hello hello2=(Hello) clazz2.newInstance();
这个hello1是不能强制转换为Hello对象的,由于Hello.class和clazz1是不同的类,因此这里只能使用spa
URLClassLoader classLoader1 = new URLClassLoader(urls); URLClassLoader classLoader2 =new URLClassLoader(urls); Class<?> clazz1= classLoader1.loadClass(Hello.class.getName()); Class<?> clazz2= classLoader2.loadClass(Hello.class.getName()); Object hello1=clazz1.newInstance(); Object hello2= clazz2.newInstance();
这样带入的问题是,上层使用hello1和hello2对象的地方,都得是object对象。.net
4.想办法解决这个问题---代理类线程
下面是解决的方法:代理
import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.util.HashMap; /** * Created by litao on 16/10/16. */ public class HelloProxy implements MethodInterceptor { private String name; public static HashMap<String, Object> delegates = new HashMap<String, Object>(); public Hello getInstance(String name) throws ClassNotFoundException, IllegalAccessException, InstantiationException { this.name = name; if (delegates.get(name) == null) { URL url = Hello.class.getProtectionDomain().getCodeSource().getLocation(); URL[] urls = new URL[]{url}; URLClassLoader classLoader = new URLClassLoader(urls, null); Class clazz = classLoader.loadClass(Hello.class.getName()); Object obj = clazz.newInstance(); delegates.put(name, obj); } Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Hello.class); // 回调方法 enhancer.setCallback(this); // 建立代理对象 return (Hello) enhancer.create(); } public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object realObj= delegates.get(name); Method method2 = realObj.getClass().getMethod(method.getName(), method.getParameterTypes()); return method2.invoke(realObj, args); } }
定义HelloProxy对象,用它来“代替”Hello类,对Hello类的操做,转为对HelloProxy操做,可是底层却仍是使用Hello类来完成,而且Hello能够是“加载”成的不一样类对象code
下面是使用例子对象
/** * Created by litao on 16/10/16. */ public class Hello { private static String name; public void setName(String _name) { name=_name; } public void sayHello() { System.out.println("name:"+name); } }
/** * Created by litao on 16/10/16. */ public class LoadMain { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException { Hello helloProxy1=new HelloProxy().getInstance("hello1"); Hello helloProxy2 =new HelloProxy().getInstance("hello2"); helloProxy1.setName("zhangsan"); helloProxy2.setName("lisi"); helloProxy1.sayHello(); helloProxy2.sayHello(); } }
输出结果是:zhangsan
lisi
这里,“同”类的static值却不同了,实现了逻辑