2023年7月4日发(作者:)
Java单元测试动态修改环境变量Java单元测试动态修改环境变量今天再写单元测试的时候,遇到⼀个⽐较有趣的事情,程序需要读取⼀个环境变量,⽽这个变量⼜是动态⽣成的,所以在执⾏单元测试之前要进⾏环境变量的配置。⽬前总结了两种⽅案可以实现动态修改环境变量,修改后的环境变量仅对当前进程⽣效,即仅在当前Java进程中调⽤(name)⽣效,分别是通过反射修改Runtime中保存环境变量的Map、和通过JNI的⽅式调⽤系统的setenv⽅法。下⾯将分别对两种⽅案进⾏实现。1 通过反射修改Runtime中保存环境变量的Map在Java中获取环境变量,可以使⽤如下两种⽅法:public static String getenv(String name);public static getenv();getenv()返回的是⼀个Map,但是这个map是不可修改的,如果我们对其修改会报如下错误:Exception in thread "main" ortedOperationException at tions$(:1459) at (:8)这种⽅案修改环境变量的原理很简单,我们可以通过反射的⽅式拿到这个Map,并对其修改即可。直接上代码:package ;import ;import ;import ;/** * @author shirukai */public class EnvUtils { public static void setEnv(String name, String value) throws Exception { getModifiableEnvironment().put(name, value); } /** *
通过反射的⽅式从Runtime中获取存储环境变量的Map,返回的Map是可变的 * Copy from /questions/580085/is-it-possible-to-set-an-environment-variable-at-runtime-from-java * * @return Map * @throws Exception e */ @SuppressWarnings("unchecked") private static Map getModifiableEnvironment() throws Exception { Class> pe = e("sEnvironment"); Method getenv = laredMethod("getenv"); essible(true); Object unmodifiableEnvironment = (null); Class> map = e("tions$UnmodifiableMap"); Field m = laredField("m"); essible(true); return (Map) (unmodifiableEnvironment); } public static void main(String[] args) throws Exception { ("TEST_SET_ENV","test-set-env"); n(("TEST_SET_ENV")); }}2 通过JNI的⽅式调⽤系统的setenv⽅法2.1 基本概念2.2 setenv⽅法有了JNI,我们就可以很⽅便的调⽤标准库中的setenv⽅法,⾸先我们可以在Linux的环境中,输⼊man setenv从说明⽂档可以看出,要使⽤setenv⽅法⾸先要引⼊标准库,然后调⽤该⽅法,当前⽅法参数也⾮常简单name为变量名称,value为变量值,overwrite为是否覆盖的标志位,如果为0不覆盖,⾮零将进⾏覆盖。2.3 使⽤JNI调⽤setenv⽅法JNI开发的基本流程如下():1、编写声明了native⽅法的Java类2、将Java源代码编译成class字节码⽂件3、⽤javah -jni命令⽣成.h头⽂件(javah是jdk⾃带的⼀个命令,-jni参数表⽰将class中⽤native声明的函数⽣成jni规则的函数)4、⽤本地代码实现.h头⽂件中的函数5、将本地代码编译成动态库(windows:.dll,linux/unix:.so,mac os x:*.jnilib)6、拷贝动态库⾄ 本地库搜索⽬录下,并运⾏Java程序下⾯就将⼀步⼀步实现,笔者电脑为Mac,仅记录在Mac下的实现,其它平台实现参考具体资料。2.3.1 编写声明了native⽅法的Java类⾸先我们创建⼀个名为EnvNativeUtils的类:public class EnvNativeUtils { public static native void setEnv(String name, String value);}2.3.2 编译编译很简单,我们可以直接使⽤Maven的compile直接编译,这时会在target/classes下⽣成对应的class⽂件,这⾥不做演⽰。2.3.3 ⽤javah -jni命令⽣成.h头⽂件使⽤如下命令⽣成.h头⽂件:javah -classpath /Users/shirukai/hollysys/repository/learn-demo-java/examples/target/classes/ iveUtils-classpath 指定编译后的类路径,这⾥笔者指定的是绝对路径,后⾯的参数是包路径。执⾏命令后,会在当前⽂件夹下⽣成⼀个名为learn_examples_jni_EnvNativeUtils.h的头⽂件,内容如下:/* DO NOT EDIT THIS FILE - it is machine generated */#include /* Header for class learn_examples_jni_EnvNativeUtils */#ifndef _Included_learn_examples_jni_EnvNativeUtils#define _Included_learn_examples_jni_EnvNativeUtils#ifdef __cplusplusextern "C" {#endif/* * Class: learn_examples_jni_EnvNativeUtils * Method: setEnv * Signature: (Ljava/lang/String;Ljava/lang/String;)V */JNIEXPORT void JNICALL Java_learn_examples_jni_EnvNativeUtils_setEnv (JNIEnv *, jclass, jstring, jstring);#ifdef __cplusplus}#endif#endif2.3.4 实现.h头⽂件中的函数在当前⽂件夹下新建⼀个名为EnvNativeUtils.c的⽂件,内容如下:#include "learn_examples_jni_EnvNativeUtils.h"#include #ifdef __cplusplusextern "C"{#endif/* * Class: com_study_jnilearn_HelloWorld * Method: sayHello * Signature: (Ljava/lang/String;)Ljava/lang/String; */JNIEXPORT void JNICALL Java_learn_examples_jni_EnvNativeUtils_setEnv (JNIEnv *env, jclass cls, jstring j_name, jstring j_value){ const char *name = NULL; const char *value = NULL; char buff[128] = { 0 }; name = (*env)->GetStringUTFChars(env, j_name, NULL); value = (*env)->GetStringUTFChars(env, j_value, NULL); setenv(name,value,0);}#ifdef __cplusplus}#endif2.3.5 将本地代码编译成动态库使⽤如下命令编译成动态库gcc -dynamiclib -o /Users/shirukai/hollysys/repository/learn-demo-java/examples/src/main/java/learn/examples/jni/ /Users/shirukai/hollysys/repository/learn-demo-java/examples/src/main/java/learn/examples/jni/EnvNativeUtils.c -I/$JAVA_HOME/include -I/$JAVA_HOME/include/darwin2.3.6 代码中使⽤绝对路径加载动态库执⾏上⾯命令之后,会在对应的⽬录⽣成⼀个的动态库,我们在代码⾥可以直接指定动态库的路径对其进⾏加载public class EnvNativeUtils { public static native void setEnv(String name, String value); static { ("/Users/shirukai/hollysys/repository/learn-demo-java/examples/src/main/java/learn/examples/jni/"); }}2.3.7 验证上述操作完成之后,我们就可以进⾏验证了,编写测试类EnvNativeUtilsTest:public class EnvNativeUtilsTest { public static void main(String[] args) { ("TEST_ENV_BY_JNI","Hello JNI"); n(("TEST_ENV_BY_JNI")); }}执⾏main⽅法,环境变量⽣效。
发布者:admin,转转请注明出处:http://www.yc00.com/news/1688463068a141141.html
评论列表(0条)