Spring ApplicationContext - Rò rỉ tài nguyên: 'context' không bao giờ bị đóng


94

Trong một ứng dụng MVC mùa xuân, tôi khởi tạo một biến trong một trong các lớp dịch vụ bằng cách sử dụng phương pháp sau:

ApplicationContext context = 
         new ClassPathXmlApplicationContext("META-INF/userLibrary.xml");
service = context.getBean(UserLibrary.class);

UserLibrary là một tiện ích của bên thứ 3 mà tôi đang sử dụng trong ứng dụng của mình. Đoạn mã trên tạo cảnh báo cho biến 'ngữ cảnh'. Cảnh báo được hiển thị bên dưới:

Resource leak: 'context' is never closed

Tôi không hiểu cảnh báo. Vì ứng dụng là ứng dụng Spring MVC, tôi không thể thực sự đóng / hủy ngữ cảnh khi tôi đề cập đến dịch vụ trong khi ứng dụng đang chạy. Chính xác thì cảnh báo đang muốn nói với tôi điều gì?


2
Tôi tò mò là tại sao bạn đang tạo một bối cảnh ứng dụng như trái ngược với việc tạo ra các hạt trong bối cảnh ứng dụng bootstrapped bởi Spring MVC
Kevin Bowersox

Xem chuỗi này stackoverflow.com/questions/14184177/… để biết giải thích tại sao tôi phải tạo một vùng chứa mới.
ziggy

Khi nào thì sự suy yếu này được hiển thị: trong khi bạn tạo bối cảnh?
Ralph

Tôi chỉ nhìn thấy nó trong Eclipse (gạch chân màu Vàng). Tôi vừa kiểm tra nhật ký khi chạy ứng dụng nhưng không thấy cảnh báo.
ziggy

Câu trả lời:


92

Vì bối cảnh ứng dụng là một ResourceLoader(tức là hoạt động I / O) nên nó tiêu thụ tài nguyên cần được giải phóng tại một thời điểm nào đó. Nó cũng là một phần mở rộng của AbstractApplicationContextClosable. Do đó, nó có một close()phương thức và có thể được sử dụng trong câu lệnh try-with-resources .

try (ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("META-INF/userLibrary.xml")) {
  service = context.getBean(UserLibrary.class);
}

Liệu bạn có thực sự cần tạo bối cảnh này hay không là một câu hỏi khác (bạn đã liên kết với nó), tôi sẽ không bình luận về điều đó.

Đúng là ngữ cảnh được đóng ngầm khi ứng dụng bị dừng nhưng điều đó vẫn chưa đủ tốt. Eclipse nói đúng, bạn cần thực hiện các biện pháp để đóng nó theo cách thủ công cho các trường hợp khác để tránh rò rỉ bộ nạp lớp.


Tôi nghĩ nguồn gốc của vấn đề thực sự là do tôi được tạo ra một bối cảnh khác. Loại bỏ ngữ cảnh bổ sung đó có lẽ là một lựa chọn tốt hơn là cố gắng giải quyết cảnh báo. Cảm ơn.
ziggy

25
Đáng lưu ý: Mặc dù giao diện cơ sở ApplicationContextkhông cung cấp close()phương thức, nhưng ConfigurableApplicationContext( phương thức ClassPathXmlApplicationContexttriển khai) thực hiện và mở rộng Closeableđể khởi động, vì vậy bạn có thể sử dụng mô hình thử với tài nguyên Java 7.
kbolino

@kbolino. Câu lệnh try-with-resources đảm bảo rằng mỗi tài nguyên được đóng ở cuối câu lệnh.
ruruskyi 27/09/13


3
+1 đến @ kbolino của bình luận ở đây, bởi vì tôi đã tuyên bố biến tôi như là một ApplicationContextvà gãi đầu của tôi trên lý do tại sao tôi đã nhận được cảnh báo khi có không xuất hiện như một phương pháp gần sẵn ...
Periata Breatta

40

close()không được xác định trong ApplicationContextgiao diện.

Cách duy nhất để thoát khỏi cảnh báo một cách an toàn là như sau

ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(...);
try {
    [...]
} finally {
    ctx.close();
}

Hoặc, trong Java 7

try(ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(...)) {
    [...]
}

Sự khác biệt cơ bản là vì bạn khởi tạo ngữ cảnh một cách rõ ràng (tức là bằng cách sử dụng new) bạn biết lớp bạn đang khởi tạo, vì vậy bạn có thể xác định biến của mình cho phù hợp.

Nếu bạn không khởi tạo AppContext (tức là sử dụng AppContext do Spring cung cấp) thì bạn không thể đóng nó.


6
Một lần nữa và một lần thử sai ... cuối cùng cũng được truyền cho người khác ... Việc new ClassPathXmlApplicationContext(...);phải nằm ngoài khối thử. Sau đó, không cần kiểm tra null. Nếu phương thức khởi tạo ném một ngoại lệ thì ctxlà null và finallykhối không được gọi (vì ngoại lệ được ném ra bên ngoài khối try). Nếu phương thức khởi tạo không ném ra một ngoại lệ thì trykhối được nhập và ctxkhông thể là null, vì vậy không cần kiểm tra null.
kayahr

Câu trả lời này là không tốt, có một vấn đề thực sự với khối thử cuối cùng của bạn. vừa thử nghiệm nhưng không hoạt động gì cả.
HDJEMAI

12

Một diễn viên đơn giản giải quyết vấn đề:

((ClassPathXmlApplicationContext) fac).close();

6

Vì ngữ cảnh Ứng dụng có một thể hiện của ClassPathXmlApplicationContext và cùng một phương thức close (). Tôi chỉ cần CAST đối tượng appContext và gọi phương thức close () như bên dưới.

ApplicationContext appContext = new ClassPathXmlApplicationContext("spring.xml");
//do some logic
((ClassPathXmlApplicationContext) appContext).close();

Điều này sẽ khắc phục cảnh báo rò rỉ tài nguyên.


4

thử cái này. bạn cần áp dụng ép kiểu để đóng ứng dụng.

   ClassPathXmlApplicationContext ctx = null;
      try {
         ctx = new ClassPathXmlApplicationContext(...);
            [...]
             } finally {
              if (ctx != null)
                  ((AbstractApplicationContext) ctx).close();       
      }

3

Ngay cả khi tôi đã có cùng một cảnh báo, tất cả những gì tôi đã làm là khai báo ApplicationContextbên ngoài hàm chính như private staticvà ta-da, vấn đề đã được khắc phục.

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();
    }
}

8
Điều này giải quyết vấn đề cảnh báo nhưng không giải quyết được vấn đề thực sự đang để bối cảnh mở và gây ra rò rỉ. Bạn có thể làm tương tự với @SupressWarningschú thích, nhưng vẫn tốt hơn để giải quyết vấn đề gốc rễ, bạn có nghĩ vậy không?
Xtreme Biker

Vâng, bạn nói đúng .. đó chỉ là một giải pháp cho tôi tại thời điểm đó.
Elysium

Đây không phải là một câu trả lời hay. vì vấn đề thực sự vẫn như cũ, tức là có rò rỉ tài nguyên, ngữ cảnh không bao giờ bị đóng.
HDJEMAI

2

Truyền là giải pháp chính xác cho vấn đề này. Tôi gặp phải vấn đề tương tự bằng cách sử dụng dòng dưới đây. ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);

Để giải quyết cảnh báo chỉ cần downcast ctxđối tượng như dưới đây và sau đó đóng nó lại. ((AnnotationConfigApplicationContext) ctx).close();


1

Hạ cấp ngữ cảnh xuống ConfigurableApplicationContext.

((ConfigurableApplicationContext)context).close();

((ConfigurableApplicationContext)(context)).close();có thể đây là câu trả lời đúng
Bhargav Modi

Câu trả lời từ amit28 là đúng. Tại sao câu trả lời không hữu ích?
Rudy Vissers

1
Object obj = context.getBean("bean");
if(bean instanceof Bean) {
    Bean bean = (Bean) obj;
}

Trong trường hợp của tôi, rò rỉ biến mất


1

Điều này làm việc tốt nhất cho tôi.

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());
    }
}

0

Nếu bạn đang sử dụng ClassPathXmlApplicationContext thì bạn có thể sử dụng

((ClassPathXmlApplicationContext) context).close();

để đóng vấn đề rò rỉ tài nguyên.

Nếu bạn đang sử dụng AbstractApplicationContext thì bạn có thể ép kiểu này bằng phương thức close.

((AbstractApplicationContext) context).close();

Nó phụ thuộc vào loại ngữ cảnh sử dụng trong ứng dụng.


0
import org.springframework.context.ConfigurableApplicationContext;

((ConfigurableApplicationContext)ctx).close();

2
Bạn có thể giải thích tại sao bạn nghĩ câu trả lời này trả lời câu hỏi?
Jeen Broekstra

Siêu lớp ClassPathXMLApplicationContext thực hiện ConfigurableApplicationContext chứa phương thức close (). Chúng ta có thể nhập ngữ cảnh vào ConfigurableApplicationContext để gọi phương thức close (), nó giải phóng tài nguyên. Đơn giản chúng ta cũng có thể làm như ((ClassPathXmlApplicationContext) ctx) .close ();
Suseendran P

0

Bạn đặt ngữ cảnh thành một biến tĩnh, có nghĩa là ngữ cảnh có sẵn cho tất cả các phương thức tĩnh trong lớp và không bị giới hạn trong phạm vi của phương thức chính nữa. Vì vậy, công cụ không thể giả định rằng nó phải được đóng ở cuối phương thức nữa, vì vậy nó không đưa ra cảnh báo nữa.

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();

       }
}

0

Có, giao diện ApplicationContextkhông có close()phương thức, vì vậy tôi muốn sử dụng lớp AbstractApplicationContextđể sử dụng closephương thức đó một cách rõ ràng và cũng ở đây bạn có thể sử dụng lớp cấu hình Ứng dụng mùa xuân của mình bằng cách sử dụng chú thích thay vì XMLloại.

AbstractApplicationContext context = new AnnotationConfigApplicationContext(SpringAppConfig.class);
Foo foo = context.getBean(Foo.class);

//do some work with foo

context.close();

Resource leak: 'context' is never closedcảnh báo của bạn đã biến mất ngay bây giờ.


0

nó có một giải pháp đơn giản chỉ cần nhập Core jar vào các thư viện, được cung cấp tại liên kết này [tải xuống các tệp jar lõi cho mùa xuân] [1] [1]: https://static.javatpoint.com/src/sp/spcorejars. zip


1
Vui lòng kiểm tra tài liệu Markdown và sử dụng bản xem trước, URL của bạn dường như đã bị cắt bớt.
Leo

-1

Phương thức đóng đã được thêm vào giao diện ConfigurableApplicationContext, vì vậy cách tốt nhất bạn có thể làm để truy cập vào nó là:

ConfigurableApplicationContext context = new ClassPathXmlApplicationContext(
                "/app-context.xml");

// Use the context...

context.close();
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.