101

In a spring MVC application, I initialize a variable in one of the service classes using the following approach:

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

The UserLibrary is a 3rd party utility which I am using in my application. The above code generates a warning for the 'context' variable. The warning is shown below:

Resource leak: 'context' is never closed

I don't understand the warning. As the application is a Spring MVC application, I can't really close/destroy the context as I refer to the service while the application is running. What exactly is the warning trying to tell me?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
ziggy
  • 15,677
  • 67
  • 194
  • 287
  • 2
    I'm curious as to why you are creating another application context as opposed to creating the bean within the application context bootstrapped by Spring MVC – Kevin Bowersox Jan 06 '13 at 16:24
  • See this thread http://stackoverflow.com/questions/14184177/converting-or-integrating-a-standalone-spring-application-to-a-spring-mvc-app for an explanation as to why i had to create a new container. – ziggy Jan 06 '13 at 16:33
  • When does this waning get shown: while you create the context? – Ralph Jan 06 '13 at 17:12
  • I only saw it in Eclipse (underlined in Yellow). I just checked the logs for when i run the application but i don't see the warning. – ziggy Jan 06 '13 at 17:21

17 Answers17

96

Since the app context is a ResourceLoader (i.e. I/O operations) it consumes resources that need to be freed at some point. It is also an extension of AbstractApplicationContext which implements Closable. Thus, it's got a close() method and can be used in a try-with-resources statement.

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

Whether you actually need to create this context is a different question (you linked to it), I'm not gonna comment on that.

It's true that the context is closed implicitly when the application is stopped but that's not good enough. Eclipse is right, you need to take measures to close it manually for other cases in order to avoid classloader leaks.

Marcel Stör
  • 22,695
  • 19
  • 92
  • 198
  • I think the source of the problem is actually the fact that i am created a different context. Removing that additional context is probably a better option than trying to resolve the warning. Thanks. – ziggy Jan 07 '13 at 13:07
  • 26
    Worthy of note: While the base `ApplicationContext` inteface does not provide the `close()` method, `ConfigurableApplicationContext` (which `ClassPathXmlApplicationContext` implements) does and extends `Closeable` to boot, so you can use the Java 7 try-with-resource paradigm. – kbolino Feb 03 '13 at 06:03
  • @kbolino. The try-with-resources statement ensures that each resource is closed at the end of the statement. – ruruskyi Sep 27 '13 at 20:56
  • 1
    @kbolino See also: http://stackoverflow.com/questions/14423980/how-to-close-a-spring-application-context – Raedwald Oct 18 '13 at 10:54
  • 3
    +1 to @kbolino's comment here, because I was declaring my variable as an `ApplicationContext` and scratching my head over why I was getting the warning when there didn't appear to be a close method available... – Periata Breatta Sep 23 '16 at 06:42
  • On wrapping it up, it closes my appcontext automatically and shutdowns the app on the server, which isn't what i would want as the app is now down, in such a case – Shubhi224 Sep 04 '18 at 07:13
40

close() is not defined in ApplicationContext interface.

The only way to get rid of the warning safely is the following

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

Or, in Java 7

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

The basic difference is that since you instantiate the context explicitly (i.e. by use of new) you know the class you are instantiating, so you can define your variable accordingly.

If you were not instantiating the AppContext (i.e. using the one provided by Spring) then you couldn't close it.

usr-local-ΕΨΗΕΛΩΝ
  • 26,101
  • 30
  • 154
  • 305
  • 6
    Again and again the wrong try...finally is teached to others... The `new ClassPathXmlApplicationContext(...);` must be outside of the try-block. Then there is no need for the null check. If the constructor throws an exception then `ctx` is null and the `finally` block is not called (because the exception was thrown outside the try-block). If the constructor didn't throw an exception then the `try` block is entered and `ctx` can't be null, so there is no need then for a null-check. – kayahr Sep 26 '13 at 06:43
  • This answer is bad, there is a real problem with your try finally block. just tested but not working at all. – HDJEMAI Feb 06 '17 at 03:50
15

A simple cast solves the issue:

((ClassPathXmlApplicationContext) fac).close();
Pang
  • 9,564
  • 146
  • 81
  • 122
RCInd
  • 344
  • 2
  • 13
8

As the Application context has an instance of ClassPathXmlApplicationContext and the same has a close() method. I would simply CAST the appContext object and invoke the close() method as below.

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

This will fix the Resource Leak warning.

4

try this. you need to apply cast to close applicationcontext.

   ClassPathXmlApplicationContext ctx = null;
      try {
         ctx = new ClassPathXmlApplicationContext(...);
            [...]
             } finally {
              if (ctx != null)
                  ((AbstractApplicationContext) ctx).close();       
      }
madhu_karnati
  • 785
  • 1
  • 6
  • 22
3

Even I had the exact same warning, all I did was declare ApplicationContext outside the main function as private static and ta-da, problem fixed.

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();
    }
}
ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
Elysium
  • 145
  • 1
  • 4
  • 15
  • 11
    This solves the warning problem but not the real issue which is leaving the context open and causing a leak. You could do the same with a `@SupressWarnings` annotation, but still better to solve the root problem, don't you think? – Aritz Jun 30 '14 at 10:25
  • 1
    Yeah you're right.. it was just a workaround for me at that moment. – Elysium Jul 02 '14 at 07:54
  • This is not a good answer. since the real issue remain the same, i.e there is a resource leak, context is never closed. – HDJEMAI Feb 06 '17 at 03:47
2

Downcast the context to ConfigurableApplicationContext.

((ConfigurableApplicationContext)context).close();
amit28
  • 176
  • 8
2

Casting is the correct resolution for this issue. I faced the same issue using the below line. ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);

To resolve the warning just downcast the ctx object like below and then close it. ((AnnotationConfigApplicationContext) ctx).close();

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

In my case leak disappears

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
1

This worked out best for me.

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());
    }
}
Bonifacio2
  • 3,405
  • 6
  • 34
  • 54
i4nk1t
  • 419
  • 1
  • 6
  • 16
0

If you are using the ClassPathXmlApplicationContext then you can use

((ClassPathXmlApplicationContext) context).close();

to close the resource leak problem.

If you are using the AbstractApplicationContext then you can cast this with close method.

((AbstractApplicationContext) context).close();

It depends on the type of context using in the application.

Kalimah
  • 11,217
  • 11
  • 43
  • 80
0
import org.springframework.context.ConfigurableApplicationContext;

((ConfigurableApplicationContext)ctx).close();
Yao Pan
  • 524
  • 9
  • 26
  • 2
    Can you elaborate on why you think this answer the question? – Jeen Broekstra Oct 03 '16 at 05:50
  • ClassPathXMLApplicationContext super class implements ConfigurableApplicationContext which contains the close() method. We can typecast the context into ConfigurableApplicationContext to call the close() method, it frees the resources. Simply also we can do like ((ClassPathXmlApplicationContext)ctx).close(); – Suseendran P Dec 01 '16 at 06:20
0

You make the context a static variable, which means that the context is available to all the static methods in the class, and not limited to the scope of the main method anymore. So the tool can't assume that it should be closed at the end of the method anymore, so it doesn't issue the warning anymore.

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

       }
}
Nanhe Kumar
  • 15,498
  • 5
  • 79
  • 71
0

Yes, interface ApplicationContext doesn't have close() method, so I like to use class AbstractApplicationContext to use that close method explicitly and also here you can use your Spring Application configuration class using annotation instead of XML type.

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

//do some work with foo

context.close();

your Resource leak: 'context' is never closed warning is gone now.

ArifMustafa
  • 4,617
  • 5
  • 40
  • 48
0

it has a simple solution just input the Core jar into the libraries, given at this link [download the core jar files for spring][1] [1]: https://static.javatpoint.com/src/sp/spcorejars.zip

  • 1
    Please check the Markdown docs and use the preview, your URL seems to have been truncated. – Leo Jun 25 '20 at 11:22
0

for ApplicationContext you can't use close() method because this method doesn't define int it but instead you can use:(ClassPathXmlApplicationContext(context)).close()

Mehdi_mh
  • 1
  • 2
-1

The method close has been added to ConfigurableApplicationContext interface, so the best you can do to get access to it is:

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

// Use the context...

context.close();
Chuck
  • 998
  • 8
  • 17
  • 30