java修改static final String常量值
背景
在项目中使用的JPA,@Table
设置实体类表名,使用mysql数据库的话,设置@Table
中catalog
和schema
可以在生成查询sql时,加上schema。例如表为sys_node
,库名叫stu_manage
,设置schema=stu_manage
和catalog=stu_manage
,sql就会变为select * from stu_manage.sys_node
项目现在要访问另一个库的表,但是这个库schema不是固定的要从配置文件中读取。
实现想法
- 设置一个静态常量表示schema,静态常量通过
@Value
读取配置文件。 - 只要动态改变
@Table
中schema
和catalog
,将上述常量赋值给schema
和catalog
。 - 想法很美好实现很残酷。
实现
- 对于第一个想法代码如下,利用Spring组件注入的方式。
@Component
public class DataSchema{
public static String schema = "";
@Value("${data.schema}")
public void setSchema(String schema){
DataSchema.schema = schema;
}
}
到这一步想着赋值给@Table
属性schema
和catalog
不就好了。
结果发现,属性要求是 final
变量。于是新问题又来了,怎么给static final String
变量改变值呢。
在研究之下有了如下的代码
@Component
public class DataSchema{
public static final String schema = (1=1?"":"");
@Value("${data.schema}")
public void setSchema(String schema){
DataSchema.schema = schema;
class<?> clas = DataSchema.class;
try{
Field field = cla.getDeclaredField("schema")//属性名称
field.setAccessible(true);
//用于去掉final
Field modifiers = Field.class.getDeclaredField("modifiers");
modifiers.setAccessible(true);
modifiers.setInt(field,field.getModifiers() & ~Modifier.Final);
field.set(null,schema)
}catch(NoSuchFieldException e){
throw new RuntimeException(e);
}catch(IllegalAccessException e){
throw new RuntimeException(e)
}
}
}
上述代码(1=1?"":"")
不是无用代码,在jvm编译时,常量会直接替换使用方式。我的这种读取配置文件修改,那肯定是在类加载结束后才开始的。所以使用的地方值已经固定,就算我修改掉依然用不了。使用三元表达式Jvm加载时不会直接替换。
上述代码是实现了,从配置文件读取配置,然后修改静态final String变量。
但是@Table
属性必须是已经确定的常量。。。也就是"xxxx"这种,这一下人都麻了,废了那么多功夫白做了。
于是有了下面的思想。
1、修改class文件。
这是理论,在类没有加载到jvm修改了class文件也可以实现动态改变值。但是。。。项目使用Apollo,配置文件也不是立马就有的。人又麻了。
2、修改已经加载到jvm中类常量。
没实现出来,资料太少。
最后
对不起各位,看了这么久,没有出现解决方案,最后我还是用sql拼接实现了。