8

I am developing a spring MVC application. When I try to use AnnotationConfigApplicationContext in my controller class I am getting the following error. I have no idea what this statement exactly means.

@RequestMapping(value = "/generate", method = RequestMethod.POST)
public ModelAndView generateMappingFile(@ModelAttribute Mapping mapping) 
{
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
    MappingFileGenerator mfg = ctx.getBean(MappingFileGenerator.class);
}

Error Message -->

java.lang.IllegalStateException:org.springframework.context.annotation.AnnotationConfigApplicationContext@116b3c0 has not been refreshed yet

Can someone explain me what went wrong here ? I am using Spring 4.0.1.. I am new to spring mvc.

ekostadinov
  • 6,880
  • 3
  • 29
  • 47
KarthickN
  • 335
  • 1
  • 6
  • 20
  • 4
    Why are you creating a new instance in the first place… Basically you should never create a new instance yourself. Just inject the `MappingFileGenerator`. This construct you are using now will eventually lead to bad performance, memory issues, transactional problems etc. – M. Deinum Sep 15 '14 at 07:08

3 Answers3

8

When you are creating a new instance of an ApplicationContext (regardless which type) you are basically creating new instances of each and every bean configured in that ApplicationContext. That is nice the first time, it might work the second and depending on the amount of beans, the type of beans will crash after that. As the context will never be destroy (until the app crashed and is restarted) you will run into possible memory issues, performance issues, strange transactional problems etc.

A general rule of thumb is to never construct a new instance of an ApplicationContext but to use dependency injection instead.

If you really want access to the ApplicationContext put a field of that type in your controller and put @Autowired on it.

@Controller
public class MyController {

    @Autowired
    private ApplicationContext ctx;

    ….

}

Then you can do a lookup for the bean you need in the method. This can be handy if you use the ApplicationContext as a factory for your beans. If all the beans you need are singletons it is better to simply inject the bean you need.

@Controller
public class MyController {

    @Autowired
    private MappingFileGenerator mfg ;

    ….

}

Now Spring will inject the MappingFileGenerator and it is available for use in your methods. No need to create a new instance of an ApplicationContext.

More information is in the Spring Reference Guide.

M. Deinum
  • 115,695
  • 22
  • 220
  • 224
  • Think *never* using `new ApplicationContext` could be an exaggeration? Spring provide [examples](http://docs.spring.io/spring-amqp/reference/html/sample-apps.html#hello-world-sync) of doing this in a `main()` method. – Steve Chambers Dec 23 '14 at 15:19
  • Well as a general rule of thumb (as most applications are web based applications) it works very well. If you have a standalone application it is different but then again you should only create it once and once only. – M. Deinum Dec 23 '14 at 19:02
3

@M.Deinum's comment will get quite a few more upvotes.

Think of creating a new ApplicationContext as instantiating a new (instance of an) application. Do you want to do that every time this (or any other method in said application) is called? No, you don't.

I'm guessing you think you do because you need access to your ApplicationContext in this method. To do that - i.e. to get access to the running application context (rather than creating a new one), you want to do

@Controller // or @Service / @Component / ... : tells Spring that this is a bean, and to inject the specified dependencies 
class YourClass {

     @Autowired // tells Spring that this object is a dependency should should be injected 
     ApplicationContext ctx;

     @RequestMapping(value = "/generate", method = RequestMethod.POST)
     public ModelAndView generateMappingFile(@ModelAttribute Mapping mapping) {
         MappingFileGenerator mfg = ctx.getBean(MappingFileGenerator.class);
     }

The key here is the Autowired annotation, which tells Spring to inject the annotated object as a dependency.

I highly suggest following the links I've included (for starters), as what you're doing here suggests pretty strongly that you haven't wrapped your head around what DI is and does for you, and until you do, using it is likely to be counterproductive toward it's own ends for you.

Community
  • 1
  • 1
drew moore
  • 31,565
  • 17
  • 75
  • 112
  • That was really helpful in understanding my mistake. Thank you :) – KarthickN Sep 15 '14 at 07:25
  • 1
    @KarthickN You unaccepted my answer when I added the last paragraph. That's fine - his is a better answer anyway. But really... do the reading. DI can do a lot for you, but it's a big concept to grasp, and until you really grasp it on a fundamental level, you'll waste *far* more time pulling your hair out over errors like this one than Spring or any other DI framework will ever save you. Your code will also start to make far less sense (to you and everyone else), which is *the opposite of the point of DI* – drew moore Sep 15 '14 at 07:37
  • Sorry for that.. I thought to vote up both the answers. I didnt know I unaccepted. Thanks for the answer.. That was really helpful.. No offence (y) Yes as you said I got few more new problems. I am working on it :/ – KarthickN Sep 15 '14 at 08:43
  • No worries :) FYI - upvoting and accepting are two different things: you can only *accept* one, by clicking the checkmark, but now that you have 15 reputation you can also *upvote* as many as you like by clicking the arrow above of the number beside an answer (that's the number of upvotes, btw). As for the other problems, feel free to post new questions - but I really can't emphasize enough that Spring is a technology you really don't want to start using until you understand it on a basic conceptual level. (if you can't tell, I'm speaking from experience there...) – drew moore Sep 15 '14 at 17:19
0

In case it helps someone, i was having this issue on a new URL Mapping added to a gradle project, i was missing the first slash of the url and that causing this "illegalstate not refreshed yet" on my tests

John doe
  • 3
  • 4