Clarification needed on Spring MVC without using Annotation - spring

I am trying to understand Spring MVC in more detail what I currently know. I am referring to online tutorials and books. As I understand, Spring MVC framework has "Front controller" and "MVC" design patterns.
The front controller (DispatcherServlet) uses the HandlerMapping for mapping URL to the controller classes. I am not using annotations because I want to understand what the framework does behind the scenes.
In this quest, I created a simple web-application based on Spring MVC, the code is below:
Controller code:
public class SimpleSpringController extends AbstractController {
#Override
protected ModelAndView handleRequestInternal(HttpServletRequest req, HttpServletResponse res) throws Exception {
ModelAndView mw = new ModelAndView("welcome","welcomeMessage", "welcome user!");
return mw;
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<display-name>FirstSpringMVCProject</display-name>
<servlet>
<servlet-name>spring-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>spring-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
Spring xml configuration
<beans>
<bean id="HandlerMapping1" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean name="/welcome" class="com.example.controller.SimpleSpringController"/>
<bean id="viewResolver1" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix"> <value>/WEB-INF/</value> </property>
<property name="suffix"> <value>.jsp</value> </property>
</bean>
</beans>
The application works as expected.
The concepts which I am not able to understand is on the spring configuration xml where we specify the HandlerMapping and ViewResolver implementations.
For example, we have the following bean definition in the above spring xml configuration:
<bean id="HandlerMapping1" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
In above xml config, org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping is one of the implementations of the HandlerMapping interface.
The bean id for this is HandlerMapping1, which is just a random identifier ( I could have very well chosen MyHandlerMapping). The following are the doubts:
Who reads this configuration file? Do front controller read this configuration file?
How does the framework knows that the id of HandlerMapping implementation in above case is HandlerMapping1. Usually we do getBean("beanId"), where we specifically know what a particular bean id is. How come spring framework is automatically infer that this is the implementation class of HandlerMapping.
Any inputs to understand this would be of great help.

Initialization
In Spring the front controller is the DispatcherServlet, this extends the FrameworkServlet. The FrameworkServlet by default creates a XmlWebApplicationContext and tries to read an XML file named <servlet-name>-servlet.xml (this is when using a web.xml!). (All this can be overridden by setting the appropriate init-params for the configured DispatcherServlet).
The DispatcherServlet will after loading eventually call the initStrategies method. This method will configure the delegation strategies for the DispatcherServlet. It will first try and detect most of the strategies by type (like HandlerMaping, HandlerAdapter, ViewResolver etc) and some by name (localeResolver, themeResolver, messageSource etc.). If that cannot be found the default strategies for a given interface will be installed. Those defaults are defined in the DispatcherServlet.properties inside Spring.
Important: As soon as you define a strategy yourself the defaults for that strategy don't apply anymore!. For instance if you have a BeanNameUrlHandlerMapping in your configuration, the default configuration for HandlerMapping isn't loaded anymore as you provided explicit configuration.
Request Handling
After startup the DispatcherServlet is ready to handle request.
Image comes from the Spring Framework reference guide
Handler Selection and execution
What happens is when a request is handled by the DispatcherServlet it will check all configured HandlerMappings to see if one is able to provide a handler (a Controller or #Controller is just one of the handler types that can be handled) for the given request. As soon as a handler is found, it will lookup a HandlerAdapter for the detect handler. If that is also found the found handler together with the current HttpServletRequest and HttpServletResponse are passed to the HandlerAdapters handle method.
View resolution
Now if a ModelAndView is being returned from the HandlerAdapter.handle method a View is going to be resolved if the ModelAndView.getViewName() method returns a name, this is going to be passed on the an to a ViewResolver to be resolved into a View.
When a View is either being resolver or being returned from the ModeAndView.getView() method, the render method is going to be called to let the chosen View render itself. With the (optional) model from the ModelAndView class.
Exception Handling
When an exception occurs during processing of the request this exception is first being passed to the configured HandlerExceptionResolvers. If one of them can handle it the selected HandlerExceptionResolvers resolveException method is being invoked. This method, just like the HandlerAdapter.handle method can return a ModelAndView, when this happens this is processed in the same way as a normal request (see View Resolution).
Note: This is also to some degree documented in the javadoc of the DispatcherServlet. You can find all the default strategies and well known names in there, as well as a explanation of the request handling flow.

The controller does not read the xml file, Spring does.
Your spring xml configuration is loaded in by Spring which wires everything together. Autowiring is taking place which is wiring by the Type, of which HandlerMapping1 can provide for the interface HandlerMapping.
Interestingly BeanNameUrlHandlerMapping is the default handler mapping class, so it is the one created by the DispatcherServlet when Spring cannot find any handler mapping class declared.
If you want to try and see something break, create a duplicate bean named HandlerMapping2 and read the error logging.

Spring framework reads the xml.
Well, for spring MVC to work, the handler should be instantiated.
The spring MVC framework needs to resolve the mappings and so we
have handlers like BeanNameUrl..., ControllerBeanNameHandlerMapping,
etc
However, HandlerMapping is not generally used by your application
code. So you need not specify whether this bean is autowired by type
or not. It is used by the framework. So it is autowired in the
framework classes by type.
You can try defining the bean in the xml without any id, name
something like
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
and it should still work.
Id or name is required only when you want to refer to the bean by id
or name for your use. Framework classes which need this handler
mapping don't refer to the bean of HandlerMapping type by id or
name. Framework will 'scan' the xml (or the loaded classes) and if
it finds a concrete class in there of type
(org.springframework.web.servlet.HandlerMapping) then it won't
complain.
To think of a similar case for example, when you run the junit
tests, the engine will scan for all the methods annotated with #Test
and it will 'know' that these are the methods it needs to execute as
tests. It does not matter what the names of test methods are.
Hope this answers the query.

Related

Can't a Filter or Listener use spring beans?

I have a listener class in web.xml like this:
<listener>
<listener-class>com.datx.monitoring.model.MonitoringHttpSessionListener</listener-class>
</listener>
And for this class, I have defined a bean like this:
<bean id="monitoringHttpSessionListener"
class="com.datx.monitoring.model.MonitoringHttpSessionListener" autowire="byName"/>
But this bean is not able to use other beans. Every time this class is called, it has null properties.
This class is the exact same as the other which is working fine. The only difference is, this class is used as a listener and the other is not. Why is that?
There is a simple reason for this: There are two beans. One was created by your web container (which uses web.xml) and the other by Spring (which uses your bean definition). The web container and Spring know nothing about each other.
What you need to do is create a normal listener which gets the application context with
WebApplicationContextUtils.getWebApplicationContext(session.getServletContext());
This will allow you to look up beans. Now you can define a bean which the filter can modify.
Note: You will want to give this bean the request scope or there will be chaos.

LocaleResolver in filter null yet shows it has been autowired! Spring MVC 3.1.1/Spring Security 3.1.0

I am using Spring Security 3.1.0 and Spring MVC 3.1.1.
I would like to be able to change the locale based on URL i.e.:
http://localhost:8080/abc?lang=fr
Now, this works under "normal" circumstances, i.e. going from one page to another page HOWEVER, in my application, if I go from a non-secure page to a secure page, it first hit's my login page, courtesy of Spring Security BEFORE it hits the page I want.
This is normal Spring Security behaviour (to intercept a secure resource) so there are no problems with this behavuour.
The problem is rather that the locale does not change when I arrive at the secured page! It stays as the default locale. i..e lang=fr is not parsed out.
I have played with defining the locale related beans inside dispatcher-servlet.xml AND outside, in an app-context file to do the following:
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" p:paramName="lang" />
</mvc:interceptors>
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver" p:defaultLocale="en" />
I have also tried to split up the above 2 beans, having just localResolver in the app-context config.
I have done TONS of research on this and basically, I understand I need to change the locale manually.
Even the Spring Docs for Spring Security 3.1.0 say that you need your own "filter" or you can use RequestContextFilter. RequestContextFilter, however does not parse out the locale param in the query String.
Spring Security relies on Spring's localization support in order to actually lookup
the appropriate message. In order for this to work, you have to make sure that the
locale from the incoming request is stored in Spring's
org.springframework.context.i18n.LocaleContextHolder. Spring MVC's DispatcherServlet
does this for your application automatically, but since Spring Security's filters are
invoked before this, the LocaleContextHolder needs to be set up to contain the correct
Locale before the filters are called. You can either do this in a filter yourself
(which must come before the Spring Security filters in web.xml) or you can use
Spring's RequestContextFilter.
I would like to intercept the request BEFORE it hits the Controller and so, I have written my own filter.
My solution, based on what others have done as well, is to autowire the LocaleResolver. When tomcat fires up, it shows in my logs that "localeResolver" has been autowired (otherwise the app would fail right there) HOWEVER at run time, localeResolver is NULL.
Again, there have been posts that say to define LocaleResolver in the application-context...I have done so but I still end up getting a null LocaleResolver when a request happens.
Any ideas?? Much appreciated.
p.s. the filter I have defined comes before the Spring Security filters. I can debug it, it hits it first but then it dies because of the NPE on LocaleResolver.
Appreciate this, thanks.
Did you define the filter in web.xml? If so, then the filter class is not instantiated by Spring, it is instantiated by the servlet container. Spring cannot autowire what it does not know about.
The general solution here is to declare the <filter-class> in web.xml as org.springframework.web.filter.DelegatingFilterProxy and point the targetBeanName at a bean in your context, such as:
<filter>
<filter-name>My Locale Filter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetBeanName</param-name>
<param-value>myLocaleFilter</param-value>
</init-param>
</filter>
And in your Spring context, <bean id="myLocaleFilter"> should point at your Filter class.
You might also find it convenient for your custom Filter class to extend GenericFilterBean rather than implementing the Filter interface directly.

Why doesn't just autowiring a field in a GWT servlet in Spring work?

Simply marking a field as #Autowired in a GWT servlet does not work as intended. The code will compile and the web application will start up - which means Spring was successfully able to autowire the field, but when the servlet is actually hit by client-side code, it will yield a NullPointerException - like there's a different, uninitialized copy of the servlet being hit.
I've found several ways on the web to get this working, one is by using a base servlet class that does some Spring logic but doing this means every GWT servlet must extend this base class. The other way was by using AspectJ and the #Configurable Spring annotation. There was very little configuration involved here and it just magically worked.
My question is why doesn't just autowiring the field just work as intended? What is GWT doing that causes this to break.
The code will compile and the web application will start up - which
means Spring was successfully able to autowire the field
Not necessarily. The web container can instantiate a servlet without any help from Spring. Which you could be experiencing:
but when the servlet is actually hit by client-side code, it will
yield a NullPointerException - like there's a different, uninitialized
copy of the servlet being hit.
try overriding Servlet's init():
#Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
WebApplicationContextUtils.getWebApplicationContext(config.getServletContext())
.getAutowireCapableBeanFactory().autowireBean(this);
}
When the RPC service is called from the client, the "server-side" looking at the called URL and the servlets mapping will find the class, will make the instance and it will serve the request. Meaning if you have #Autowired annotation, or you already have an instance of the RPC class in the spring context, it does not matter. The new instance will be created and it won't "know" about Spring.
I resolve this by implementing a class which extends RemoteServiceServlet and implements Controller (from Spring MVC) and ServletContextAware.
This way you can map every RPC service by URL using the Spring MVC approach, for ex:
<bean id="publicUrlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/myFirstRpc">firstRpcServiceBeanRef</prop>
<prop key="/mySecondRpc">secondRpcServiceRef</prop>
</props>
</property>
</bean>
You also avoid the declarations for every single RPC servlet in web.xml, the mappings are clean and you have the Spring injection.
You declare only a single mapping in web.xml for org.springframework.web.servlet.DispatcherServlet which will serve all RPC calls.
There are couple of examples on the web with explanation about GWT RPC and Spring MVC controller integration.
Hope this will help.
It turns out that when using Spring at least, there's a MUCH simpler way to do this such that you can use #Autowired and it doesn't involve massive configuration or base classes. The caveat is that you must also use AspectJ. Here's what you need for your GWT servlet:
#Configurable
public class MyGwtServiceImpl extends RemoteServiceServlet implements MyGwtService
{
#Autowired
private MyService service;
// ...
}
And in your Spring config make sure you also have:
<!-- enable autowiring and configuration of non-spring managed classes, requires AspectJ -->
<context:spring-configured/>
One final note. If you are also using Spring security with your GWT application (and in your GWT servlets), you will need to make sure you define the correct mode to ensure the AspectJ weaving is done correctly (i.e., you get both #Secured annotation processing AND the #Autowired processing) you will need:
<!-- turn on spring security for method annotations with #Secured(...) -->
<!-- the aspectj mode is required because we autowire spring services into GWT servlets and this
is also done via aspectj. a server 500 error will occur if this is changed or removed. -->
<security:global-method-security secured-annotations="enabled" mode="aspectj"/>

Trying to supply an alternative implementation for Spring's FilterChainProxy

I'm working on an application using Spring security.
The application is extensible and I would like to block extensions from programmatically changing the filters in the filter chain map of Spring's FilterChainProxy. What I intend to do is the following:
Implement a CustomFilterChainProxy implementing all of FilterChainProxy's implemented interfaces (Filter, InitializingBean, ApplicationContextAware). In it I will hold a private FilterChainProxy member and delegate all of the interface calls to it.
Use Spring's DelegatingFilterProxy by declaring in the web.xml file:
<filter>
<filter-name>customSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
In the Spring configuration files, instead of using Spring's FilterChainProxy directly I will have my bean have the CustomFilterChainProxy as its class, as follows:
<bean id="customSecurityFilterChain" class="....CustomFilterChainProxy">
<security:filter-chain-map ...>
<security:filter-chain pattern="..." filters="..." />
<security:filter-chain pattern="..." filters="..." />
...
</security:filter-chain-map>
</bean>
In order to be able to set the filter chain map during Spring bean loading I must supply a setter in my CustomFilterChainProxy class. That I will do. And in order to prevent setting the filter chain map after Spring bean loading I will make sure that after bean construction (in a #PostConstruct method) an exception will be thrown from that setter.
By having a CustomFilterChainProxy instead of a FilterChainProxy, am I causing any Spring process to malfunction?
I saw the only Spring class referencing the FilterChainProxy object itself is FilterChainProxyPostProcessor but couldn't find out if this should affect my implementation choice. Any input?
Thanks a lot.
This is unlikely to be sufficient to protect you from malicious extension code.
If the extension can access your bean, then it can also just access the original FilterChainProxy through the ApplicationContext. In fact, it can probably access any other bean in the same configuration, so it could potentially:
Load user account data, including passwords
Modify or read settings on other beans to break the system
Use reflection to read instance fields directly
Modify the current security context
Lots of other nasty things depending on what you are using
If you have untrusted code in your app then you would need to use a SecurityManager to prevent this kind of thing and you can then also prevent access to Spring Security classes. Configuring a SecurityManager can be a pain, but it's probably the only option if you have code you don't trust running in the same VM.
Update: If your only concern is preventing anyone from calling the setFilterChainMap method then overriding this method will obviously prevent anyone from accidentally calling this through a reference to your bean (this method is actually deprecated in 3.1 in favour of a constructor. However, it's not clear from your question why someone would obtain a reference to your instance rather than the original bean, or why this is your main concern. The FilterChainProxy is not normally accessed by user code in an application. To do so, you'd have to explicitly request it from the bean factory.

Inject Spring beans into EJB3

I'm trying to inject Spring beans into an EJB using #Interceptors(SpringBeanAutowiringInterceptor.class) but I cannot get it working with the beanRefContext.xml examples I've seen.
Here's my EJB:
#Stateless
#Interceptors(SpringBeanAutowiringInterceptor.class)
public class AlertNotificationMethodServiceImpl implements
AlertNotificationMethodService {
#Autowired
private SomeBean bean;
}
I've provided a beanRefContext.xml as follows:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="...">
<!-- Have also tried with ClassPathXmlApplicationContext -->
<bean id="context"
class="org.springframework.web.context.support.XmlWebApplicationContext">
<property name="configLocations" value="/config/app-config.xml" />
</bean>
</beans>
But, it seems to be recreating the beans instead of obtaining the existing ApplicationContext. I end up with the following exception because one of my beans is ServletContextAware.
java.lang.IllegalArgumentException: Cannot resolve ServletContextResource
without ServletContext
When using the SpringBeanAutowiringInterceptor, shouldn't it obtain the ApplicationContext instead of create a new one?
I also tried changing my web.xml so the contextConfigLocation points to the beanRefContext.xml, hoping it'd load my Spring config but I end up with the same exception as above.
Does anyone know how to do this properly? The examples I've seen seem to use the same method I'm using which I assume means the beans are being recreated when the Interceptor is invoked (or is that how it's supposed to work and I've misunderstood).
When using the SpringBeanAutowiringInterceptor, shouldn't it obtain the ApplicationContext instead of create a new one?
Yes, and this is in fact what it does. It uses the ContextSingletonBeanFactoryLocator mechanism, which in turn manages a number of ApplicationContext instances as static singletons (yes, even Spring has to resort to static singletons sometimes). These contexts are defined in beanRefContext.xml.
Your confusion seems to stem from the expectation that these contexts have any relation to your webapp's ApplicationContext - they don't, they're entirely separate. So your webapp's ContextLoader is creating and managing a context based on the bean definitions in app-config.xml, and the ContextSingletonBeanFactoryLocator creates another one. They won't communicate unless you tell them to. The EJBs cannot get hold of the webapp's context, since EJBs sit outside of that scope.
What you need to do is to move the beans that need to be used by your EJBs out of app-config.xml and into another bean definition file. This extracted set of bean definitions will form the basis of a new ApplicationContext which will (a) be accessed by the EJBs, and (b) will act as the parent context of your webapp's context.
In order to activate the parent-child link between your webapp's context and the new context, you need to add an additional <context-param> to your web.xml called parentContextKey. The value of this parameter should be the name of the context defined in beanRefContext.xml (i.e. context, in your example).
The beans that stay behind in the webapp's context will be able to reference the beans in the parent context, as will the EJBs. However, the EJBs will not be able to reference anything in the webapp's context.
Also, you cannot use XmlWebApplicationContext in beanRefContext.xml, since that class requires awareness of the webapp, and ContextSingletonBeanFactoryLocator cannot supply that awareness. You should stick with ClassPathXmlApplicationContext there.

Resources