Как заставить AutoClosable Предупреждение распространяться на вызывающего класса в Java?
Я новичок в интерфейсе AutoClosable Java (но не новичок в Java). Я пытаюсь заставить клиентский код, который запрашивает экземпляр WebDriver
закрыть driver
после того, как он заканчивает использовать его (вызывая driver.quit()
)
Я хочу, чтобы способ заставить любой метод, который создает экземпляр WebDriver
закрыть это.
Поэтому я создал новый класс, который реализует AutoClosable
:
public class WebDriverLauncher implements AutoCloseable {
WebDriver driver;
public WebDriverLauncher()
{
driver = new FirefoxDriver();
}
public WebDriver getDriver()
{
return driver;
}
@Override
public void close() throws Exception {
driver.quit();
}
}
Теперь вместо непосредственного создания экземпляра WebDriver (WebDriver driver = new FirefoxDriver()
) Я создаю экземпляр этого класса и возвращаю экземпляр WebDriver
такой как в следующем примере:
public WebDriver launchDriver()
{
WebDriverLauncher webDriverLauncher = new WebDriverLauncher();
WebDriver driver = webDriverLauncher.getDriver();
return driver;
}
Когда я делаю это, я получаю предупреждение / ошибку: Resource leak: 'webDriverLauncher' is never closed
Поскольку я не могу закрыть ресурс в этом методе, потому что ресурс (т.е. WebDriver
) используется в методе вызывающего launchDriver()
закрыть driver
,
Поэтому вместо этого я решил, что метод должен возвращать экземпляр WebDriverLauncher
- например, в следующем примере:
public WebDriverLauncher launchDriver()
{
WebDriverLauncher webDriverLauncher = new WebDriverLauncher();
return webDriverLauncher;
}
Таким образом, вызывающий абонент будет иметь доступ к driver
(позвонив по webDriverLauncher .getDriver()
) и будьте предупреждены, чтобы закрыть ресурс (так я думал).
Однако, когда я попробовал это, предупреждающее сообщение полностью исчезло. Другими словами, я больше не вижу предупреждение о закрытии ресурса - ни в launchDriver()
класс / метод, ни в классе вызывающего / клиентского (как я уже упоминал, я хочу, чтобы предупреждение появлялось, поэтому всякий, кто вызывает этот метод, получает предупреждение о закрытии ресурса)
Я пытаюсь понять следующее:
1) Почему предупреждение не распространяется до класса вызывающего (если ресурс никогда не был закрыт)?
2) Почему предупреждение исчезает, когда я возвращаюсь webDriverLauncher
но не когда я вернусь driver
?
3) Есть ли способ изменить код, чтобы предупреждение распространялось на вызывающего абонента? (чтобы предупредить вызывающего этого метода о закрытии ресурса)
4) Если это невозможно, что можно сделать, чтобы заставить клиента закрыться WebDriver
?
Спасибо!
1 ответ
Использование оператора Try-with-resources:
try (WebDriverLauncher webDriverLauncher = new WebDriverLauncher(){
//Your Code Here
}//webDriverLauncher.close() will be called after here weather throw any exception in try...catch block or not.
В других мирах AutoClosable
Интерфейс является ограничением для определения, какой тип может быть использован в Try-with-resources statement
Я опаздываю на этот вопрос. Но вот мое мнение, если мы хотим заставить клиента осторожно использовать ресурсы. Мы можем ограничить создание ресурса (частный конструктор + отключить доступ к отражению, включив свойство -Djava.security.manager для jar) и разрешить клиенту только предоставлять метод, который будет вызываться на этом ресурсе для фабрики ресурсов.
public class MyResource implements AutoCloseable{
public static class ResourceFactory{
public static void useResourceSafely(Consumer<MyResource> work) {
try(MyResource res = new MyResource()){
work.accept(res);
}
catch(Exception e)
{
e.printStackTrace();
//you may even check for Suppressed exceptions
}
}
}
private MyResource() {
System.out.println("Resource created");
}
public void doWork() {
System.out.println("resource in use");
}
@Override
public void close() throws Exception {
System.out.println("Closing myResource");
}
}
Клиентский код может выглядеть так:
public static void main(String[] args) throws Exception{
ResourceFactory.useResourceSafely(s->{
s.doWork();
System.out.println("Check 1");
s.doWork();
System.out.println("Check 2");
});
}
PS: Возможно, это не рекомендуемый способ, это всего лишь попытка сделать это.