Have two servlet contexts in one Spring Boot application context under Jetty - java

Imagine I have one Spring Boot instance, pretty boring, one ApplicationContext, starter-jetty. By default, it does one ServletContext on /, puts a DispatcherServlet on / too. Every servlet and filter then placed under this context.
Now, I want to have one servlet context with contextPath=/api with a few servlets and another servlet context under /internal with a different set of servlets. They have to share ApplicationContext and most beans. And yes, it has to be plain old servlets & filters, not just two WebMvc instances.
How do I configure that? The most crucial question is how to make two ServletContext's for Jetty to consume. Just class names are enough, links to examples are encouraged. Hints on how to painlessly configure the distribution of Servlet's and Filter's between servlet contexts are appreciated too.

Related

What is the purpose of having multiple spring "application context"

Per the Spring Documentation, application context is:
Central interface to provide configuration for an application. This is read-only while the application is running, but maybe reloaded if the implementation supports this.
In some applications, there are multiple application contexts. What's the purpose and benefit of having multiple application contexts? I want to understand the logic behind it. Why would one do it?
P.S: In spring doc use is written. I want to know the pros of having multiple application contexts and the rationale behind it.
The root context is the parent of every dispatcher servlet context/child context. Beans defined in root context are visible to each dispatcher servlet context/child context but not vice-versa.
Typically, root context is used to define all cross-cutting beans such as security, transactions, and other configurational beans, while the dispatcher context or child context contains those beans that are specifically related to MVC.
We create multiple dispatcher servlets when we need multiple sets of MVC configuration. For e.g. we may have a REST API alongside a traditional MVC application or an unsecured and a secure section of a website.
Cannot comment so putting the answer:-
Java Spring multiple ApplicationContext
Hope this answer your question
It is useful to implement a layered architecture (model objects, data access, services, web services, mvc app etc).
As M.Deinum said it is good to have one root context that loads the others and helps keeping them separated.
Here is the official doc for the architecture of Spring Framework applications: https://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/overview.html

Convert traditional projects to spring boot, without changing applicationContext.xml, dispatcher-servlet.xml & tomcat's context.xml

The background & requirements are:
there are a lot of old projects which have an applicationContext.xml and one or more dispatcher[-XXX]-servlet.xml. We hope those projects can still works while using spring boot(we developed a deployment tools to deploy spring boot applications, but the old projects are still deployed manually). But, #SpringBootApplication can't build the contexts as they were. And rewriting them into codes one by one costs too much, I think.
In those project, we use an extended RequestMappingHandlerMapping, so we can't use the native MVC.
the context.xml of tomcat, which contains jndi definitions, is maintained by OPs. We have to load it just like tomcat does.
i can't find where to set welcome file, which were set in web.xml
I currently using:
#Configuration
#ImportResource({"classpath:/applicationContext.xml", "classpath:/dispatcher-servlet.xml"})
Those simple projects without using jndi can startup.
But as my understanding, in this case, the applicationContext and dispatcher-servlet are in the same level(dispatcher-servlet should the child of applicationContext, isn't it?). So, i can't even ensure this one works properly.
We did a similar thing about a year ago and your setup was more or less the same as ours and importing those XML files did the trick; the only thing we had to do was to ensure our application class was in a different package hierarchy in order to avoid conflicting/duplicate bean definitions due to its inherent #ComponentScan.
And having dispatcher servlet and application context in the same context won't cause any issues - yes, dispatcher servlet's context is usually defined as a separate context and is a child of the more broad applicationContext but what most people fail to grasp is that that separation only matters if your application wants to have more than one dispatcher servlet, which is rarely the case any more, if it ever was.
In case of multiple dispatcher servlets it was a must to enable them to have different WebMVC configurations, and applicationContext was there to allow you to share common beans and configuration between your servlet contexts so that you don't have to do the same work twice.

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 to get WebApplicationContext outside current servlet context?

There are two WARs deployed in Tomcat (or other server), foo1.war and foo2.war.
All spring beans are defined in foo1.war, but is it possible to get these spring beans in the servlet that deployed in foo2.war?
I cannot just use WebApplicationContextUtils to get the WebApplicationContext, right? They are different WAR.
thanks
Technically, you can get the WebApplicationContext of the other app, if you expose the servlet context and call servletContext.getContext("/otherapp").getAttribute(..), but that's ugly.
You can have instances of the same bean definitions if you simply move the common definitions to a common.xml and include it in both projects.
If you need to communicate some data betweent the two apps, use another mechanism: web services (soap, rest), messaging (jmx).
Adding to #Bozho answer: you can also share instance data (e.g. singletons), when the two WARs are deployed in a single EAR. You should be able to expose the appContexts as statically visible fields in a class provided by EAR and thus visible to both WARs.

What's the point of Spring MVC's DelegatingFilterProxy?

I see this in my Spring MVC app's web.xml:
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
I'm trying to figure out why it's there and whether it's actually needed.
I found this explanation in the Spring docs but it doesn't help me make sense of it:
It seems to suggest that this component is the "glue" between the servlets defined in web.xml and the components defined in the Spring applicationContext.xml.
7.1 DelegatingFilterProxy
When using servlet filters, you obviously need to declare them in your web.xml, or they will be ignored by the servlet container. In Spring Security, the filter classes are also Spring beans defined in the application context and thus able to take advantage of Spring's rich dependency-injection facilities and lifecycle interfaces. Spring's DelegatingFilterProxy provides the link between web.xml and the application context.
When using DelegatingFilterProxy, you will see something like this in the web.xml file:
<filter>
<filter-name>myFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Notice that the filter is actually a DelegatingFilterProxy, and not the class that will actually implement the logic of the filter. What DelegatingFilterProxy does is delegate the Filter's methods through to a bean which is obtained from the Spring application context. This enables the bean to benefit from the Spring web application context lifecycle support and configuration flexibility. The bean must implement javax.servlet.Filter and it must have the same name as that in the filter-name element. Read the Javadoc for DelegatingFilterProxy for more information
So, if I take this out of my web.xml, what will happen? My servlets won't be able to communicate with the Spring container?**
There's some kind of magic here, but at the end, everything is a deterministic program.
The DelegatingFilterProxy is a Filter as it was explained above, whose goal is "delegating to a Spring-managed bean that implements the Filter interface", that is, it finds a bean ("target bean" or "delegate") in your Spring application context and invokes it. How is it possible? Because this bean implements javax.servlet.Filter, its doFilter method is called.
Which bean is called? the DelegatingFilterProxy "Supports a "targetBeanName" [...], specifying the name of the target bean in the Spring application context."
As you saw in your web.xml that the bean's name is "springSecurityFilterChain".
So, in the context of a web application, a Filter instantiates a bean called "springSecurityFilterChain" in your application context and then delegate to it via the doFilter() method.
Remember, your application context is defined with ALL THE APPLICATION-CONTEXT (XML) files. For instance: applicationContext.xml AND applicationContext-security.xml.
So try to find a bean called "springSecurityFilterChain" in the latter...
...and probably you can't (for instance if you followed a tutorial or if you configured the security using Roo)
Here is the magic: there's a new element for configuring the security, something like
<http auto-config="true" use-expressions="true">
as it is allowed by http://www.springframework.org/schema/security/spring-security-3.0.xsd, will do the trick.
When Spring loads the application context using XML files, if it finds a element, it will try to set up the HTTP security, that is, a filter stack and protected URLs and to register the FilterChainProxy named "springSecurityFilterChain".
Alternatively, you can define the bean in the classic way, that is:
<beans:bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
But it's less recommended, since you need to do a lot of configuration (all the filters that you're going to use. And there are more than a dozen of them)
Do you know what a Servlet Filter is and how it works? It's a very useful piece of the Servlet Spec, allowing us to apply AOP-like concepts to servicing of HTTP requests. Many frameworks use Filter implementations for various things, and it's not uncommon to find custom implementations of them because they're very simple to write and useful. In a Spring app, most of the stuff that your app can do is in your Spring beans. A Filter instance, though, is controlled by the Servlet container. The container instantiates, initializes, and destroys it. The Servlet Spec doesn't require any kind of Spring integration, though, so you're left with a really useful concept (Filters) with no convenient way of tying it to your Spring app and the beans that do the work.
Enter the DelegatingFilterProxy. You write a Filter implementation and make it a Spring bean, but instead of adding your own Filter class to the web.xml, you use the DelegatingFilterProxy, and give it the bean name of your filter in the Spring context. (If you don't explicitly provide a name, it uses the "filter-name".) Then at runtime, the DelegatingFilterProxy handles the complexity of finding the real implementation - the one you wrote and configured in Spring - and routing requests to it. So at runtime, it's as if you had listed your filter in the web.xml, but you get the benefit of being able to wire it like any other Spring bean.
If you take that filter mapping out of your web.xml, everything will continue working, but none of your URLs will be secured. (That's assuming the name "springSecurityFilterChain" accurately describes what it does.) That's because this mapping is filtering every incoming request and handing it off to a security filter that's defined in your Spring context.
What are Servlet Filters?
Servlet filters are, in general, a Java WebApp concept. You can have servlet filters in any webapp, whether or not you use Spring framework in your application.
These filters can intercept requests before they reach the target servlet. You can implement common functionality, like authorization, in servlet filters. Once implemented, you can configure the filter in your web.xml to be applied to a specific servlet, specific request url patterns or all url patterns.
Where servlet filters are used?
Modern web-apps can have dozens of such filters. Things like authorization, caching, ORM session management, and dependency injection are often implemented with the aid of servlet filter. All of these filters need to be registered in web.xml.
Instantiating Servlet Filters - without Spring Framework
Your servlet container creates instances of Filters declared in web.xml and calls them at appropriate times (i.e., when servicing servlet requests). Now if you are like most of the Dependency Injection (DI) fans, you would likely say that creation of instances is what my DI framework (Spring) does better. Can't I get my servlet filters created with Spring so they are amenable to all DI goodness?
DelegatingFilterProxy, so that Spring creates your filter instances
This is where DelegatingFilterProxy steps in. DelegatingFilterProxy is an impelmentation of the javax.servlet.Filter interface provided by Spring Framework. Once you configure DelegatingFilterProxy in web.xml, you can declare the actual beans that do the filtering in your spring configuration. This way, Spring creates the instances of beans that do the actual filtering, and you can use DI to configure these beans.
Note that you need only a single DelegatingFilterProxy declaration in web.xml but you can have several filtering beans chained together in your application context.
The thing is, servlet filters are managed by the servlet container, and not by spring. And you may need to inject some spring components into your filters.
So, if you need something like:
public class FooFilter {
#Inject
private FooService service;
public void doFilter(....) { .. }
}
then you need the delegating filter proxy.
You are right about 'glue' stuff. As written in JavaDocs of FilterChainProxy:
The FilterChainProxy is linked into the servlet container filter chain by adding a standard Spring DelegatingFilterProxy declaration in the application web.xml file.
Please see FIlterChainProxy section of blog Behind the Spring Security Namespace for an excellent explanation.
I have been perplexed by "springSecurityFilterChain" in web.xml and found this answer in springframework security document:
The <http> element encapsulates the security configuration for the web layer of your application. >It creates a FilterChainProxy bean named "springSecurityFilterChain" which maintains the stack of >security filters which make up the web security configuration [19]. Some core filters are always >created and others will be added to the stack depending on the attributes child elements which are >present. The positions of the standard filters are fixed (see the filter order table in the >namespace introduction), removing a common source of errors with previous versions of the framework >when users had to configure the filter chain explicitly in theFilterChainProxy bean. You can, of >course, still do this if you need full control of the configuration.
Here is the link http://docs.spring.io/spring-security/site/docs/3.0.x/reference/appendix-namespace.html
Its been a long time but I had the same question and I found this: https://www.javacodegeeks.com/2013/11/spring-security-behind-the-scenes.html
I tried to run my spring security project by removing the filter in question and also by adding it. What I found is if we add the filter, only then the call will redirect to required login page as defined in the spring-security configuration.
Hence, agreeing to #Ryan's answer.

Categories

Resources