Accessing beans in portlet specific context programmatically - java

I have a portlet application. It is configured using Spring framework IoC container. I am using org.springframework.web.context.ContextLoaderListener to load my context.
I have an application context at root level (applicationContext.xml) and a portlet specific context (MyPortlet-portlet.xml).
I have a portlet of type org.springframework.web.portlet.DispatcherPortlet which is wired up to a Controller. In the Controller I want to access one of the beans (e.g. bean with id "myBean") I have defined in my portlet specific context. I have tried
MyBean mybean = (MyBean)PortletApplicationContextUtils.getWebApplicationContext(
getPortletContext()).getBean("myBean")
However only the beans in my application context are available here - none of my beans in my portlet specific context are available.
Is there a way to access the beans in my portlet specific context?
Thanks

Firstly, can't you just wire in the bean to your controller in the normal way, rather than retrieving it programmatically?
Failing that, you should realise that getWebApplicationContext() gets a reference to the root webapp context, not the servlet app context:
Find the root WebApplicationContext
for this portlet application, which is
typically loaded via
ContextLoaderListener or
ContextLoaderServlet.
If your controller needs a handle on its own context, then it should implement ApplicationContextAware or BeanFactoryAware, or it can use #Autowired ApplicationContext if you want to use autowiring.

Related

How to create a bean in spring that is available to all users in my app?

I'm building an online chat application in spring just like the one on Facebook. I want to create a bean with a property[Array] called active-users. Then performs the following:
Whenever a user logs in, I'll add his/her userId into the array.
When an other user logs in, I'll display the users that are
currently online.
How do I create a bean which is available at all times?
For Ex : In servlets, this can be achieved by using the Servlet context :
ServletContext context = request.getServletContext();
context.setAttribute("userId", "123");
All beans in Spring are singletons by default, they will be alive during the whole application's lifecycle unless you'll do something with the spring context.
So just create a spring bean and declare a global list in it. You can access it anywhere where the spring bean will be injected from the current context.
It's simpler with Spring than in a pure servlet application, because all beans declared in root application context reside in fact automatically in the ServletContext and as such are unique in the application. And Spring can natively inject them in any controller or service bean to allow you to use them at will.
The only limit, is that they are unique per instance, so it won't be enough it you had a farm of servers for your application.

DispatcherServlet not injected into the controller

I'm developing an application which is run both on Spring Boot (with no web.xml) and on WebSphere (with web.xml). There is a controller which needs to have DispatcherServlet injected into it. While it works on spring boot environment this fails on WebSphere - no bean of type DispatcherServlet can be found.
Down in web.xml i use the parent context (Context Loader Listener) with middle-tier and several dispatchers having their separate contexts. One of them contains such controller (among others).
Why it's not working? My first assumption is that Spring Boot first creates and registers the DispatcherServlet and then scans for controllers while when running with web.xml it happens in reversed order so Controllers are instantiated before DispatcherServlet is accessible from the context.
How can I tackle this problem?
You can not inject DispatcherServlet directly because it is not registered in Spring Context (XmlWebApplicationContext for example).
But you can extend DispatcherServlet, store link to itself to static field (in constuctor invocation). And you this link anywhere in your code.
Other way - if you create DispatcherServlet "manually" - you can register your DispatcherServlet as bean in application-context.xml.

How is Spring actually bootstrap?

Does anybody know how Spring is actually bootstraps?
Which instances created and by whom?
I really want to know who creates instances of WebApplicationContext and ContextLoader. Is it work of Tomcat?
Servlet context listener (web.xml) approach
A web application WAR is being deployed by user.
Servlet container (Tomcat) reads web.xml.
Servlet context listener ContextLoaderListener is being instantiated (if defined as <listener> inside the web.xml) by servlet container.
ContextLoaderListener creates new WebApplicationContext with application context XML configuration.
Your ROOT context beans are registered and instantiated by BeanFactory inside the application context.
DispatcherServlet is being instantiated by servlet container.
DispatcherServlet creates its own WebApplicationContext (WEB-INF/{servletName}-servlet.xml by default) with the ROOT context as its parent.
Your servlet beans are registered and instantiated by BeanFactory inside the application context.
DispatcherServlet registers some default beans in case you did not provide them yourself.
Servlet container initializer (non web.xml) approach
This one is possible with Servlet 3 features.
A web application WAR is being deployed by user.
Servlet container searches for classes implementing ServletContainerInitializer via Java's ServiceLoader.
Spring's SpringServletContainerInitializer is found and instantiated by servlet container.
Spring's initializer reads web application's class-path and searches for WebApplicationInitializer implementations.
Your WebApplicationInitializer is found (btw. check its JavaDoc!!!) and instantiated by SpringServletContainerInitializer.
Your WebApplicationInitializer creates new ROOT WebApplicationContext with XML or #Configuration based configuration.
Your WebApplicationInitializer creates new servlet WebApplicationContext with XML or #Configuration based configuration.
Your WebApplicationInitializer creates and registers new DispatcherServlet with the context from previous step.
Servlet container finishes the web application initialization and instantiates components which were registered by their class in previous steps (none in my example).
Java based approach is much more flexible. You can leave the context creation to DispatcherServlet or even the whole instantiation of DispatcherServlet itself to servlet container (just register servlet DispatcherServlet.class instead of its instance).
See http://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/htmlsingle/#context-create.
The principle is to declare a ServletContextListener in the standard webapp descriptor (web.xml). Such a listener is indeed instantiated by the container and is called when the application is initialized and when it's destroyed.
Spring provides such a ServletContextListener: ContextLoaderListener which, as its name indicates, loads a Spring context when the webapp is initialized.

Why does Spring MVC need at least two contexts?

In Spring MVC, there are two contexts. One is the application context or global context which is booted up by ContextLoaderListener. It takes all the configuration files mentioned in contextConfigLocation parameter.
Now if you are using Spring MVC as well, then Dispatcher servlet is required, which boots up another container which is also known as web application container. This container takes the global container as a parent.
When integrating struts1 with spring, there is only one context. Why does spring mvc need two? Is it possible to use only one context when using spring mvc?
thanks!
Having a root web application context plus a child servlet context is just an option. If you know that your application won't have a second servlet, it's arguably simpler to have one single Spring context for the whole web application.
You can achieve that setup by simply removing the ContextLoaderListener (and the accompanying contextConfigLocation context-param) from your web.xml and moving all bean definitions into the xml defining the servlet context ([servlet-name]-servlet.xml).
This is possible, because the FrameworkServlet (super-class of DispatcherServlet) doesn't care if there is a root application context when creating the servlet context. It just relays the root context as the parent if available. See related code here.
Imagine you had two separate Dispatchers, each serving a different purpose, and each having its own dependencies. You would configure those independently using separate contexts.
If there is any shared configuration, this can go in the 'global' context.
I don't think it's possible to have only one context using DispatcherServlet, as it creates its own context and links it to the parent context (via the FrameworkServlet superclass).
FrameworkServlet.createWebApplicationContext
Check this answer About multiple containers in spring framework
Yes ,you can have one context only.
For code reuse it would be better to isolate services in Application Context rather then WebApplicationContext.but this not compulsion.you can keep only webApplicationcontext only.

How do I Spring enable a Tomcat valve

I wrote a Tomcat valve and configured it in server.xml.
So far so good. However, I want one of the valve's data members to be a Spring managed bean.
So, how can I make the valve also be Spring managed so that I can have Spring's IoC inject that dependency into the valve?
Valves aren't associated with an application, while spring contexts are. So you can't have a spring-managed bean in a Valve.
You can, of course, instantiate the spring context in the Valve constructor, and use context.autowireBean(this) there, but this will be a separate spring context, not one from any of the contexts available.
Technically, you have access to the contexts from the Valve, but afaik it is from the request, so you can obtain the ApplicationContext for each servlet context, and from there - get a reference to a bean, but that sounds odd.

Categories

Resources