简介
在开发项目的时候,有些资源是需要放在redis里面,一般是以key-value的形式存放。为了区分,key通常会带有一个前缀。后来,项目多了,而redis用的还是同一个,这时有可能会产生冲突。为了解决这样的冲突,需要在固定的前缀前加上项目名做隔离。由于key的前缀定义在一个公用web配置包里,和具体的web项目名称不在同一个地方,所以直接修改前缀是不可行的。最后用了Java的反射机制在项目运行的时候获取项目名并且改变原有前缀。
代码实现
@Component
public class RedisConstants {
private static String moduleName;
//此处需要把字符串改为new String的形式,否则不成功
public static final String REDIS_USER_CACHE = new String("redis_user_cache");
// 获取项目名
@Value("${spring.application.name}")
private void setModuleName(String m) {
moduleName = m;
try {
setStaticFinal(RedisConstants.class.getField("REDIS_USER_CACHE"),
moduleName + RedisConstants.REDIS_USER_CACHE);
}catch (Exception e){}
}
private static void setStaticFinal(Field field, Object newValue) throws Exception {
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
//去掉final修饰符
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, newValue);
}
}
setStaticFinal方法
上面的代码中,最为关键的就是setStaticFinal方法。这个方法改变了变量的访问控制全,也就是说把final的修饰符给去掉了,从而可以改变变量的值。
modifiers字段
modifiers字段是Field类中一个比较关键的字段。它主要记录字段上都采用类那些修饰符。可以下面的代码与运行结果看出,采用private final static修饰的变量的modifiers值为26。
public class ReflectTest {
private final static String name="xxxx";
public static void main(String[] args) throws Exception {
Field nameField = ReflectTest.class.getDeclaredField("name");
int modifiers = nameField.getModifiers();
System.out.println(modifiers);
System.out.println(Modifier.toString(modifiers));
System.out.println(Modifier.toString(7));
}
}
Modifier类
modifiers字段有一个对应的Modifier类,该类的toString方法可以把modifiers字段的值解析为具体的修饰符。从该类的源码可以看出,设计者把modifiers字段(整形变量,32位)的不同位赋予了不同的含义。例如,public对应1,也就是把modifiers字段的二进制中的第一位有无对应起是否用public修饰。上述代码中,把7解释为了public protected private,因为7的二进制为0000 0000 0000 0000 0000 0000 0000 0111。
源码中采用16进制表示的方式,把它转为二进制更为直观。
例如:
public:0000 0000 0000 0000 0000 0000 0000 0001
private:0000 0000 0000 0000 0000 0000 0000 0010
protected:0000 0000 0000 0000 0000 0000 0000 0100
/**
* The {@code int} value representing the {@code public}
* modifier.
*/
public static final int PUBLIC = 0x00000001;
/**
* The {@code int} value representing the {@code private}
* modifier.
*/
public static final int PRIVATE = 0x00000002;
/**
* The {@code int} value representing the {@code protected}
* modifier.
*/
public static final int PROTECTED = 0x00000004;
/**
* The {@code int} value representing the {@code static}
* modifier.
*/
public static final int STATIC = 0x00000008;
/**
* The {@code int} value representing the {@code final}
* modifier.
*/
public static final int FINAL = 0x00000010;
/**
* The {@code int} value representing the {@code synchronized}
* modifier.
*/
public static final int SYNCHRONIZED = 0x00000020;
/**
* The {@code int} value representing the {@code volatile}
* modifier.
*/
public static final int VOLATILE = 0x00000040;
/**
* The {@code int} value representing the {@code transient}
* modifier.
*/
public static final int TRANSIENT = 0x00000080;
/**
* The {@code int} value representing the {@code native}
* modifier.
*/
public static final int NATIVE = 0x00000100;
/**
* The {@code int} value representing the {@code interface}
* modifier.
*/
public static final int INTERFACE = 0x00000200;
/**
* The {@code int} value representing the {@code abstract}
* modifier.
*/
public static final int ABSTRACT = 0x00000400;
/**
* The {@code int} value representing the {@code strictfp}
* modifier.
*/
public static final int STRICT = 0x00000800;
final修饰符
这行代码的作用是把field字段的final修饰符给去掉。Modifier.FINAL的值为 0000 0000 0000 0000 0000 0000 0001 0000,取反后1111 1111 1111 1111 1111 1111 1110 1111。把原有的modifiers值和取反后的Modifier.FINAL做与运算,即可不改变其他位,单独修改对应的位。
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
小结
在最开始的代码中还存在了一些值得注意的问题。
1、设置静态常量的类一般的使用方法为类名.字段名,也就是说不需要创建该类。在这个应用场景中,需要在Spring注入项目的名称,并且需要运行setStaticFinal方法来改变原有的值,所以需要加入@Component注解。把这个类交给Spring管理,并且属性注入的时候需要采用set方法注入,以便在其中运行setStaticFinal方法。
2、如注释所提及的,需要把常量改为用new String包裹起来的形式,这里涉及JDK的知识就不在此深究了。