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);//用于去掉finalField 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拼接实现了。