Reputation: 2111
I'm attempting to update an old Spring application. Specifically, I'm trying to pull all of the beans out of the old xml-defined form and pull them into a @SpringBootApplication format (while dramatically cutting down on the overall number of beans defined, because many of them did not need to be beans). My current issue is that I can't figure out how to make the ServletContext available to the beans that need it.
My current code looks something like this:
package thing;
import stuff
@SpringBootApplication
public class MyApp {
private BeanThing beanThing = null;
@Autowired
private ServletContext servletContext;
public MyApp() {
// Lots of stuff goes here.
// no reference to servletContext, though
// beanThing gets initialized, and mostly populated.
}
@Bean public BeanThing getBeanThing() { return beanThing; }
@PostConstruct
public void populateContext() {
// all references to servletContext go here, including the
// bit where we call the appropriate setters in beanThing
}
}
The error I get back: Field servletContext in thing.MyApp required a bean of type 'javax.servlet.ServletContext' that could not be found.
So... what am I missing? Is there something I'm supposed to be adding to the path? Is there some interface I need to implement? I can't provide the bean myself because the whole point is that I'm trying to access servlet context info (getContextPath() and getRealPath() strings) that I don't myself have.
Upvotes: 8
Views: 14907
Reputation: 328724
Make the bean lazy and use a parameter:
@Lazy
@Bean
public BeanThing getBeanThing(ServletContext servletContext) {
return new BeanThing(servletContext);
}
It needs to be lazy because the ServletContext
won't exist when the instance of the MyApp
is created. When the ServletContext
becomes available, Spring will remember it somewhere and it will be able to fill in the parameter.
To make this work, you just have to make sure the bean isn't requested before that.
Now you might have to create beans which need BeanThing
earlier than that. The solution then is to inject a Provider<BeanThing>
and make sure the provider is only used after the ServletContext
exists (i.e. not in @PostConstruct
or similar).
Upvotes: 0
Reputation: 7033
Please be aware of the best practice for accessing the ServletContext
: You shouldn't do it in your main application class, but e. g. a controller.
Otherwise try the following:
Implement the ServletContextAware
interface and Spring will inject it for you.
Remove @Autowired
for the variable.
Add setServletContext
method.
@SpringBootApplication
public class MyApp implements ServletContextAware {
private BeanThing beanThing = null;
private ServletContext servletContext;
public MyApp() {
// Lots of stuff goes here.
// no reference to servletContext, though
// beanThing gets initialized, and mostly populated.
}
@Bean public BeanThing getBeanThing() { return beanThing; }
@PostConstruct
public void populateContext() {
// all references to servletContext go here, including the
// bit where we call the appropriate setters in beanThing
}
public void setServletContext(ServletContext servletContext) {
this.context = servletContext;
}
}
Upvotes: 7