zoukankan      html  css  js  c++  java
  • 使用代理类解决静态变量的一个问题

    目前业务有个需求,需要使用多线程同时去获取不同类型的数据。在获取数据时,需要做签名检验,签名校验的包由第三方提供 (我们无法修改),现在的问题是,线程启动后,第一个类型的数据可以被成功获取,但是后面类型的数据就会提示签名失败。但是单独拉后面类型的数据时,又可以成功,进过排查,发现是第三方包中的一个核心类其中有很多变量被设置为了static, 每个线程都会去设置这些static变量值,导致签名检验失败。以下是几种解决策略:

    1. 将多线程换成单线程; 加锁,使得每次只有一个线程在真正执行。 由于第三方包一个static变量会在初始化时追加上次的记录,导致这种方法也不能解决问题。

    2. 将多线程换成多进程。每个进程处理一个类型,类型之间互相独立。(可以解决,但是同样代码却得部署多个应用,不爽!)

    3. 想办法让不同类型对应的静态变量互相隔离--使用不同的classloader加载类,使得对应的类互相不一样的 。但是这种情况,不能将新定义的对象为‘原’对象。如以下代码是会抛出异常的:

    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是不一样的类,所以这里只能使用

    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对象。

    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可以是“加载”成的不同类对象

    下面是使用例子

    /**
     * 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值却不一样了,实现了逻辑 

  • 相关阅读:
    poj3537--Crosses and Crosses
    poj3480--John
    poj2975--Nim
    poj2960 S-Nim
    poj2505-A multplication game
    Team Queue(POJ 2259)
    将caffemodel文件转换为Matlab可用的数据形式
    Invalid MEX-file: caffe.mexa64 的解决方案
    mongoDB-3.x启用认证
    mongoDB跨平台图形管理工具
  • 原文地址:https://www.cnblogs.com/limingluzhu/p/5968253.html
Copyright © 2011-2022 走看看