使用代理类解决静态变量的一个问题

目前业务有个需求,需要使用多线程同时去获取不同类型的数据。在获取数据时,需要做签名检验,签名校验的包由第三方提供 (我们无法修改),现在的问题是,线程启动后,第一个类型的数据可以被成功获取,但是后面类型的数据就会提示签名失败。但是单独拉后面类型的数据时,又可以成功,进过排查,发现是第三方包中的一个核心类其中有很多变量被设置为了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值却不一样了,实现了逻辑 

时间: 2024-10-07 09:31:40

使用代理类解决静态变量的一个问题的相关文章

c++ 类的静态变量

类的静态变量作为类的一部分,但不由类的创建产生,类的销毁而消失.静态变量和全局变量一样,会在main函数结束后销毁. 类可以对静态变量的值进行改变 #pragma once class ctest { public: ctest(void); ~ctest(void); static bool btest; }; 运用场景1: 类中有一个线程,但是类已经销毁了,而线程(while循环等)没有退出,这是可以通过静态变量来控制线程.

C++类中静态变量和普通变量的区别

静态变量: 1.静态变量会被编到程序的exe里面,从程序启动到结束,它一直存在: 2.静态变量的初始化值为0: 3.全局变量默认是静态变量: 4.在类中的函数变量前面加了static的也是静态变量,只不过被语言限定在只能在函数内部使用: 5.在有MFC对话框的程序了,如果一个变量和对话框绑定,那么该变量就不能声明为静态变量,函数也是一样的,因为声明为静态变量后不能随时接受对话框内的值,    主要是因为静态变量的值设置后是不能被修改的: 6.可以使用类名+静态成员名访问此静态成员,因为静态成员存

关于“在本类中访问本类私有静态变量”的一点疑惑解析

关于"在本类中访问本类私有静态变量"的一点疑惑解析 代码如下: public class StaticVar { private static int x = 100; public static void main(String[] args) { StaticVar var1 = new StaticVar(); var1.x++; StaticVar var2 = new StaticVar(); var2.x++; StaticVar.x++; System.out.print

类的静态变量访问

<?php /** * @author keke * @copyright 2016 * 这是一个类的标准格式,用于记忆,静态变量访问:student::$fee */ class student { public static $fee = 0; public $name; function __construct($name) { $this->name = $name; //非静态属性访问格式:$this->name } public static function runCode

java 类的静态变量

主要是记录一个奇葩的现象,java类中的静态变量,不仅可以通过类名称直接调用,而且还可以通过类的实力对象调用,java是不存在静态类的,如果非要用静态的类那就是内部类. 类中的静态变量是存储在JVM方法区中,线程共享的. public class HasStatic { public static int x = 100; public static void main(String args[]) { HasStatic hasStatic1 = new HasStatic(); hasSta

jav利用反射修改类的静态变量

有Student这个类: public class Student { private static String schoolName=""; private static String schoolArea= ""; private static boolean isSetValue= false; private String name; private int age; public String getName() { return name; } pub

PHP接口中的静态变量、常量与类中静态变量、常量的区别

接口: 1 不能够定义静态变量(常量除外) 2 定义的常量 const YOUCONST = VALUE,不能在子类中覆盖,在子类中以 interfaceName::YOUCONST的方式调用 3 不能使用parent::YOUCONST的方式调用接口的常量 类: 1 const 变量可以使用parent::YOUCONST的方式,className::YOUCONST的方式在子类中访问 2 const定义的变量,在子类中可以被覆盖 3 当然在类中可以定义静态成员变量了 示例: <?phpint

php类中静态变量与常亮的区别

在效率上:常量编译过程比静态变量快的多. 代码: <?php error_reporting(E_ALL); class A { const c = 9; public static $b = 5; public function setst ($ca) { self::$b = $ca; } } $obj = new A; echo $obj->c;//出错,是类的属性,不是对象的属性 echo $obj->$b;//出错,是类的属性,不是对象的属性 echo $obj::c;//ok

类和类的静态变量

类和类的静态属性 静态变量:是在类下被“static”修饰的成员变量. 程序的编译过程:java为例子:java是一门静态语言,在我们编写完java程序后,主要就是编写.java 文件,然后通过编译器去编译为.class文件,然后通过不同平台的JVM去解析和执行.class文件,所以说java是一门跨平台的语言,也可以说是java拥有不同平台的jvm来实现跨平台的. 类的创建过程:类被加载的时候是ClassLoader去加载类,如果该类继承了其他的类需要先去加载父类,然后在加载当前类.在加载类的