W aplikacji Spring MVC inicjalizuję zmienną w jednej z klas usług w następujący sposób:
ApplicationContext context =
new ClassPathXmlApplicationContext("META-INF/userLibrary.xml");
service = context.getBean(UserLibrary.class);
UserLibrary to narzędzie innej firmy, którego używam w mojej aplikacji. Powyższy kod generuje ostrzeżenie dla zmiennej „kontekst”. Ostrzeżenie jest pokazane poniżej:
Resource leak: 'context' is never closed
Nie rozumiem ostrzeżenia. Ponieważ aplikacja jest aplikacją Spring MVC, nie mogę naprawdę zamknąć / zniszczyć kontekstu, ponieważ odnoszę się do usługi, gdy aplikacja jest uruchomiona. Co dokładnie ma mi powiedzieć ostrzeżenie?
java
eclipse
spring
spring-mvc
ziggy
źródło
źródło
Odpowiedzi:
Ponieważ kontekst aplikacji jest
ResourceLoader
(tj. Operacjami we / wy), zużywa zasoby, które muszą zostać zwolnione w pewnym momencie. Jest to również rozszerzenieAbstractApplicationContext
którego realizujeClosable
. W ten sposób maclose()
metodę i można jej użyć w instrukcji try-with-resources .try (ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("META-INF/userLibrary.xml")) { service = context.getBean(UserLibrary.class); }
To, czy naprawdę potrzebujesz stworzyć ten kontekst, to inne pytanie (podałeś do niego link), nie będę tego komentować.
Prawdą jest, że kontekst jest niejawnie zamykany, gdy aplikacja jest zatrzymywana, ale to nie wystarczy. Eclipse ma rację, musisz podjąć kroki w celu ręcznego zamknięcia go w innych przypadkach, aby uniknąć wycieków z modułu ładującego klasy.
źródło
ApplicationContext
interfejs nie zapewniaclose()
metody,ConfigurableApplicationContext
(któraClassPathXmlApplicationContext
implementuje) tak i rozszerza się wCloseable
celu rozruchu, więc możesz użyć paradygmatu prób z zasobami Java 7.ApplicationContext
i drapałem się po głowie, dlaczego otrzymałem ostrzeżenie, gdy nie było dostępnej bliskiej metody ...close()
nie jest zdefiniowany wApplicationContext
interfejsie.Jedyny sposób na bezpieczne pozbycie się ostrzeżenia jest następujący
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(...); try { [...] } finally { ctx.close(); }
Lub w Javie 7
try(ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(...)) { [...] }
Podstawowa różnica polega na tym, że ponieważ tworzysz instancję kontekstu jawnie (tj. Używając
new
), znasz klasę, którą tworzysz, więc możesz odpowiednio zdefiniować swoją zmienną.Jeśli nie tworzyłeś wystąpienia AppContext (tj. Używając tego dostarczonego przez Spring), nie możesz go zamknąć.
źródło
new ClassPathXmlApplicationContext(...);
Musi być poza blokiem prób. Wtedy nie ma potrzeby sprawdzania zerowej wartości. Jeśli konstruktor zgłasza wyjątek,ctx
jest null ifinally
blok nie jest wywoływany (ponieważ wyjątek został zgłoszony poza blokiem try). Jeśli konstruktor nie zgłosił wyjątku,try
wprowadzany jest blok ictx
nie może mieć wartości null, więc nie ma potrzeby sprawdzania wartości null.Prosta obsada rozwiązuje problem:
źródło
Ponieważ kontekst aplikacji ma instancję ClassPathXmlApplicationContext, a to samo ma metodę close (). Po prostu rzuciłbym obiekt appContext i wywołał metodę close () jak poniżej.
ApplicationContext appContext = new ClassPathXmlApplicationContext("spring.xml"); //do some logic ((ClassPathXmlApplicationContext) appContext).close();
To naprawi ostrzeżenie o wycieku zasobów.
źródło
Spróbuj tego. musisz zastosować rzutowanie, aby zamknąć kontekst aplikacji.
ClassPathXmlApplicationContext ctx = null; try { ctx = new ClassPathXmlApplicationContext(...); [...] } finally { if (ctx != null) ((AbstractApplicationContext) ctx).close(); }
źródło
Nawet ja miałem dokładnie to samo ostrzeżenie, wszystko, co zrobiłem, to zadeklarowanie
ApplicationContext
poza główną funkcją asprivate static
i ta-da, problem naprawiony.public class MainApp { private static ApplicationContext context; public static void main(String[] args) { context = new ClassPathXmlApplicationContext("Beans.xml"); HelloWorld objA = (HelloWorld) context.getBean("helloWorld"); objA.setMessage("I'm object A"); objA.getMessage(); HelloWorld objB = (HelloWorld) context.getBean("helloWorld"); objB.getMessage(); } }
źródło
@SupressWarnings
adnotacją, ale nadal lepiej rozwiązać problem główny, nie sądzisz?Przesyłanie jest poprawnym rozwiązaniem tego problemu. Napotkałem ten sam problem, korzystając z poniższej linii.
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
Aby rozwiązać problem, po prostu opuść
ctx
obiekt jak poniżej, a następnie zamknij go.((AnnotationConfigApplicationContext) ctx).close();
źródło
Przekaż kontekst do ConfigurableApplicationContext.
źródło
((ConfigurableApplicationContext)(context)).close();
może to jest właściwa odpowiedźObject obj = context.getBean("bean"); if(bean instanceof Bean) { Bean bean = (Bean) obj; }
W moim przypadku wyciek znika
źródło
To wyszło najlepiej dla mnie.
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test { private static ApplicationContext con; public static void main(String[] args) { con = new ClassPathXmlApplicationContext("config.xml"); Employee ob = (Employee) con.getBean("obj"); System.out.println("Emp Id " + ob.getEmpno()); System.out.println("Emp name " + ob.getEmpname()); } }
źródło
Jeśli używasz ClassPathXmlApplicationContext , możesz użyć
aby zamknąć problem wycieku zasobów.
Jeśli używasz AbstractApplicationContext , możesz rzutować to za pomocą metody close.
Zależy to od rodzaju kontekstu używanego w aplikacji.
źródło
import org.springframework.context.ConfigurableApplicationContext; ((ConfigurableApplicationContext)ctx).close();
źródło
Ustawiasz kontekst jako zmienną statyczną, co oznacza, że kontekst jest dostępny dla wszystkich metod statycznych w klasie i nie jest już ograniczony do zakresu metody głównej. Dlatego narzędzie nie może już zakładać, że powinno zostać zamknięte na końcu metody, więc nie wyświetla już ostrzeżenia.
public class MainApp { private static ApplicationContext context; public static void main(String[] args) { context = new ClassPathXmlApplicationContext("Beans.xml"); HelloWorld obj = (HelloWorld) context.getBean("helloWorld"); obj.getMessage(); } }
źródło
Tak, interfejs
ApplicationContext
nie maclose()
metody, więc lubię używać class,AbstractApplicationContext
aby używać tejclose
metody jawnie, a także tutaj możesz użyć klasy konfiguracji Spring Application używając adnotacji zamiastXML
typu.AbstractApplicationContext context = new AnnotationConfigApplicationContext(SpringAppConfig.class); Foo foo = context.getBean(Foo.class); //do some work with foo context.close();
twoje
Resource leak: 'context' is never closed
ostrzeżenie już minęło.źródło
ma proste rozwiązanie, wystarczy wprowadzić plik Core jar do bibliotek, podany pod tym linkiem [pobierz pliki core jar na wiosnę] [1] [1]: https://static.javatpoint.com/src/sp/spcorejars. zamek błyskawiczny
źródło
Metoda close została dodana do interfejsu ConfigurableApplicationContext, więc najlepsze, co możesz zrobić, aby uzyskać do niej dostęp, to:
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext( "/app-context.xml"); // Use the context... context.close();
źródło