我有一个启用Java安全管理器的简单Java应用程序ClientApp。
该应用程序正在尝试调用获取“ os.arch”系统属性的Test jar方法。由于这很耗时,因此我们正在使用Completable任务调用新线程。
这给了例外
java.util.concurrent.ExecutionException: java.security.AccessControlException: access denied ("java.util.PropertyPermission" "os.arch" "read")
at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
at SecurityApplication.ClientApp.main(ClientApp.java:23)
Caused by: java.security.AccessControlException: access denied ("java.util.PropertyPermission" "os.arch" "read")
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472)
at java.security.AccessController.checkPermission(AccessController.java:884)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
at java.lang.SecurityManager.checkPropertyAccess(SecurityManager.java:1294)
at java.lang.System.getProperty(System.java:717)
at com.ravindra.CustomSupplier.get(CustomSupplier.java:10)
at com.ravindra.CustomSupplier.get(CustomSupplier.java:5)
at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1582)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
ClientApp:
import com.test.App;
public class ClientApp
{
public static void main(String[] args)
{
//Enable security
SecurityManager securityManager = new SecurityManager();
System.setSecurityManager(securityManager);
TestApp app = new TestApp();
Future<String> future = app.getOsArchitecture();
try
{
// blocking Aysnc get Future call for result
System.out.println(future.get());
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
Test.jar有下面2个类文件
Test.java
final public class TestApp
{
public Future<String> getOsArchitecture()
{
CompletableFuture<String> completableFuture
= CompletableFuture.supplyAsync(new CustomSupplier());
return completableFuture;
}
}
CustomSupplier.java
public class CustomSupplier implements Supplier<String> {
public CustomSupplier() {
}
public String get() {
//Time consuming complex Task and finally return "os.arch"
//...
//...
//...
return System.getProperty("os.arch");
}
}
但是,当我们禁用Java安全管理器时,程序将正确运行。
任何帮助,感激不尽。
最佳答案
默认的ForkJoinPool
使用配置为没有特权的线程。
一种解决方案是使用自定义线程工厂或使用普通线程的任何其他ForkJoinPool
实现创建新的Executor
实例。问题在于创建自己的线程池需要安全管理器授予相关权限。
一种替代方法是将查询作为特权操作执行,而忽略调用线程的限制:
public class CustomSupplier implements Supplier<String> {
public CustomSupplier() {
}
public String get() {
//Time consuming complex Task and finally return "os.arch"
//...
//...
//...
return AccessController.doPrivileged(
(PrivilegedAction<String>)() -> System.getProperty("os.arch"));
}
}
这会忽略调用方的特权,并在调用
doPrivileged
的代码(即您的CustomSupplier
)的许可下执行查询。默认情况下,授予应用程序代码读取"os.arch"
系统属性的权限。但是,由于预计该系统属性在应用程序的生存期内不会发生变化,并且查询也不是一项昂贵的操作,因此无需在后台执行查询。
public class CustomSupplier implements Supplier<String> {
public CustomSupplier() {
}
public String get() {
//Time consuming complex Task and finally return "os.arch"
//...
//...
//...
return ARCH;
}
static final String ARCH = System.getProperty("os.arch");
}