我维护一个 JDBC 驱动程序,该驱动程序还具有通过 native 库(通过 JNA 访问)提供的嵌入式数据库服务器模式。由于其依赖项的卸载顺序,作为 native 库本身卸载的一部分完成的关闭在 Windows 上会遇到问题。为避免访问冲突或其他问题,我需要在卸载此库之前明确关闭嵌入式引擎。
鉴于其使用的性质,很难确定调用关闭的合适时机,我现在看到的普通 Java 应用程序的唯一正确方法是使用 Runtime.getRuntime( ).addShutdownHook 与实现关闭逻辑的 Thread 的子类。
这对于普通的 Java 应用程序来说工作正常,但对于将我的库作为应用程序的一部分(在 WAR 的 WEB-INF/lib 中)的 Web 应用程序,这将导致内存在取消部署时泄漏,因为关闭 Hook 将保持对我的关闭实现和 Web 应用程序的类加载器的强引用。
什么是解决这个问题的适当方法?我现在正在研究的选项是:
使用 java.sql.DriverAction.deregister() 进行清理。
不适合,因为驱动程序不会在正常的应用程序退出时注销。
使用 java.sql.DriverAction.deregister() 删除关闭 Hook 并自行执行关闭逻辑。
DriverAction 的使用存在一些问题,因为驱动程序仍然支持 Java 7,并且此类是在 JDBC 4.2 (Java 8) 中引入的。这在技术上并不总是正确使用操作(JDBC 驱动程序也可以在现有连接保持有效和使用时注销),并且有可能使用该驱动程序(通过 javax.sql.DataSource) 而 JDBC java.sql.Driver 实现未注册。
包括一个用 @WebListener 注释的 javax.servlet.ServletContextListener 实现,该驱动程序将删除关闭 Hook 并自行执行关闭逻辑。
如果将驱动程序作为一个整体部署到服务器而不是特定的 Web 应用程序(尽管可以解决这些复杂问题),则此选项会很复杂。
Java 中是否有我忽略的适合我需要的关闭机制?
最佳答案
我试图弄清楚这一点,因为这似乎是一个有趣的案例。我在这里发布我的发现,尽管我觉得我可能仍然误解了某些东西,或者做了一些过于牵强的简化。其实,也有可能我完全误解了你的情况,这个回答毫无用处(如果是这样,我道歉)。
我在这里汇集的内容基于两个概念:
System.props,但它可能不是最佳选择 - 也许一些临时文件会更好)ClassLoader 加载的所有类)我提出了一个 EmbeddedEngineHandler.loadEmbeddedEngineIfNeeded 方法,该方法将被调用:
javax.sql.DataSource 实现静态初始化器中(如果整个 DataSource 相关的东西都是那样工作的——我对此知之甚少)如果我做对了,您根本不需要调用 Runtime.removeShutdownHook。
我在这里不确定的主要事情是 - 如果驱动程序是全局部署的,它会在任何 servlet 初始化之前注册吗?如果没有,那我就错了,这行不通。但是也许检查 EmbeddedEngineHandler 的 ClassLoader 会有帮助吗?
这是EmbeddedEngineHandler:
final class EmbeddedEngineHandler {
private static final String PREFIX = ""; // some ID for your library here
private static final String IS_SERVLET_CONTEXT = PREFIX + "-is-servlet-context";
private static final String GLOBAL_ENGINE_LOADED = PREFIX + "-global-engine-loaded";
private static final String TRUE = "true";
private static volatile boolean localEngineLoaded = false;
// LOADING
static void loadEmbeddedEngineIfNeeded() {
if (isServletContext()) {
// handles only engine per container case
loadEmbeddedEngineInLocalContextIfNeeded();
} else {
// handles both normal Java application & global driver cases
loadEmbeddedEngineInGlobalContextIfNeeded();
}
}
private static void loadEmbeddedEngineInLocalContextIfNeeded() {
if (!isGlobalEngineLoaded() && !isLocalEngineLoaded()) { // will not load if we have a global driver
loadEmbeddedEngine();
markLocalEngineAsLoaded();
}
}
private static void loadEmbeddedEngineInGlobalContextIfNeeded() {
if (!isGlobalEngineLoaded()) {
loadEmbeddedEngine();
markGlobalEngineAsLoaded();
Runtime.getRuntime().addShutdownHook(new Thread(EmbeddedEngineHandler::unloadEmbeddedEngine));
}
}
private static void loadEmbeddedEngine() {
}
static void unloadEmbeddedEngine() {
}
// SERVLET CONTEXT (state shared between containers)
private static boolean isServletContext() {
return TRUE.equals(System.getProperty(IS_SERVLET_CONTEXT));
}
static void markAsServletContext() {
System.setProperty(IS_SERVLET_CONTEXT, TRUE);
}
// GLOBAL ENGINE (state shared between containers)
private static boolean isGlobalEngineLoaded() {
return TRUE.equals(System.getProperty(GLOBAL_ENGINE_LOADED));
}
private static void markGlobalEngineAsLoaded() {
System.setProperty(GLOBAL_ENGINE_LOADED, TRUE);
}
// LOCAL ENGINE (container-specific state)
static boolean isLocalEngineLoaded() {
return localEngineLoaded;
}
private static void markLocalEngineAsLoaded() {
localEngineLoaded = true;
}
}
这是ServletContextListener:
@WebListener
final class YourServletContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
EmbeddedEngineHandler.markAsServletContext();
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
if (EmbeddedEngineHandler.isLocalEngineLoaded()) {
EmbeddedEngineHandler.unloadEmbeddedEngine();
}
}
}
关于java - 在 'normal' Java 应用程序和 Web 应用程序中运行良好的库关闭例程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51685146/
我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0
我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
我想用ruby编写一个小的命令行实用程序并将其作为gem分发。我知道安装后,Guard、Sass和Thor等某些gem可以从命令行自行运行。为了让gem像二进制文件一样可用,我需要在我的gemspec中指定什么。 最佳答案 Gem::Specification.newdo|s|...s.executable='name_of_executable'...endhttp://docs.rubygems.org/read/chapter/20 关于ruby-在Ruby中编写命令行实用程序
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer
我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此
我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r
在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',