使用代理類解決靜態變量的一個問題

目前業務有個需求,須要使用多線程同時去獲取不一樣類型的數據。在獲取數據時,須要作簽名檢驗,簽名校驗的包由第三方提供 (咱們沒法修改),如今的問題是,線程啓動後,第一個類型的數據能夠被成功獲取,可是後面類型的數據就會提示簽名失敗。可是單獨拉後面類型的數據時,又能夠成功,進過排查,發現是第三方包中的一個核心類其中有不少變量被設置爲了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值卻不同了,實現了邏輯 

相關文章
相關標籤/搜索