I am using the Spring MVC for a project, and I am using the Spring DispatcherServlet to map the request's coming into the application to the controllers written elsewhere. I am looking for a way to have a default handler ( a catch all handler) if the request doesn't map to any of the exisiting controller-view maps. This currently shows a Resource not found exception, but I want to know if a catch all unmatched requests function is available in the Spring.
Every HandlerMapping strategy in Spring MVC has a defaultHandler property for just this purpose.
This is easy if your Spring config is already specifying a HandlerMapping object explicitly (e.g. a SimpleUrlHandlerMapping), but it's less obvious if you're relying on the defaults to supply a HandlerMapping for you.
For example, if you're using annotated controllers, then you're probably relaying on the default declaration of DefaultAnnotationHandlerMapping which Spring supplies automatically. However, you can provide your own bean to override the default:
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="defaultHandler" ref="myDefaultHandler"/>
</bean>
This same pattern will work with any Handlermapping type, just substitute the class name.
Related
I'm trying to get a better understanding of the #Autowired annotations component scanning, but all the examples I found so far use context.getBean(..) at some point to get at least one Bean to start with.
I also read that doing that is considered bad practice , but I can't seem to find any information on how to do it without context.getBean(..)
Could somebody please enlighten me with an example and information on how to do this ?
Define your bean in xml and use
<context:component-scan base-package="com" />
<mvc:annotation-driven />
Bean def
<bean id="processEngine" class="com.processEngine">
<property name="processEngineConfiguration" ref="processEngineConfiguration" />
</bean>
now you can get bean as following
#Autowired
private ProcessEngine processEngine;
how it works
spring scans the bean's recipes either from xml or java configuration. then spring creates a beanDefinitions which are 'loaded' into BeanFactory. BeanFactory triggers a set of BeanPostProcessors (BPP) which are scanning classes for particular annotations like Autowired/Resource/PostProcessor and etc. and do appropriate actions. in case when your class contains #Autowired annotation, AutowiredAnnotationBeanPostProcessor would auto wire required field (dependencies), and when creation of an object is done and all BPP worked out, object is ready to be used by the app, from this point your code can get 'ready' objects from container.
there are some cases when you would need to access this beans from the code which is out of spring's control and not managed by container. in order to do so, you would need to get the ApplicationContext (container) and call #getBean specifying either name or type. using applicationContext directly is not a good practice because there are some problems that you can come to, f.ex. id of a bean might be changed and if you refer to bean by id then NPE would be thrown.
configuration
there are several approaches to configure spring to scan the classes for finding bean recipes. one would be defining component-scan, in this case classes which are located in the path that you've set and having any of valid spring annotations like #Component, #Service, #Repository, #Controller (for web container) would be considered. another way would be specifying each bean separately using <bean> or #Bean.
examples.
if you want to create a web app then you should see DispatcherServlet with ContextLoaderListener classes. this classes would boot your app and load everything according to configuration. f.ex. here,
but if you want to create a desktop app, then you would end up with something like this
From time to time (usually when not using Spring Boot), I use something along the lines of the following code:
public static <T> T autowire(ApplicationContext ctx, T bean) {
ctx.getAutowireCapableBeanFactory().autowireBean(bean);
return bean;
}
In my main, I create an instance of the main application class that contains a few #Autowired annotations for the main services / entry points to my Spring application.
I am using Spring Boot, and largely just using the autoconfiguration options for most of the components. However, I have found a few instances where I just want slightly different behaviour from the Beans.
What is the best/suggested approach to doing this? In many cases I don't want to have to turn off autoconfig just to change one property on the bean, so hoping there is some way I can sensibly update beans properties?
The case I have is the DispatcherServlet - I am happy with the autoconfig but I just want to change my DispatcherServlet so the DispatchOptionsRequest is set to true. I am hoping I don't need to turn off autoconfig and copy the configuration locally just to call that setter method?
The dispatcher servlet can be configured by declaring a bean of type DispatcherServlet named dispatcherServlet, then return an instance configured to your liking. This will override the previous declaration.
Example:
#Bean
public DispatcherServlet dispatcherServlet() {
DispatcherServlet servlet = new DispatcherServlet();
servlet.setDispatchOptionsRequest(true);
return servlet;
}
With Spring it is possible to inject a list of beans by the interface class like:
#Component
public class Service {
#Autowire
private List<InterfaceType> implementingBeans;
...
}
All defined beans that implement this interface will be present in this List.
The annotation based approach is not possible for me, as the Service class is in a module that must not have spring dependencies.
I need to use this mechanism from outside via xml configuration.
<bean id="service" class="...Service">
<property name="implementingBeans">
??? tell spring to create a list bean that resolves all beans of the interfaceType.
</property>
</bean>
Does anyone know how to solve this?
EDIT: Additionally, there are more than one spring applications that use this service. So the best solution would be to handle this szenario completely via xml configuration. I can then copy the xml parts to all spriong applications that need this.
I want to avoid having a kind of initializer bean that gets the service injected and must then be copied to all spring applications.
Kind regards.
An XML-only solution would simply have you declare a <bean> of the "external" type and provide an autowire value of "byType".
Controls whether bean properties are "autowired". This is an
automagical process in which bean references don't need to be coded
explicitly in the XML bean definition file, but rather the Spring
container works out dependencies.
[...]
"byType" Autowiring if there is exactly one bean of the property type in the container. If there is more than one, a fatal error is
raised, and you cannot use byType autowiring for that bean. If there
is none, nothing special happens.
The explanation is a little confusing in that we expect multiple InterfaceType beans, but the actual field is of type List and Spring will be able to dynamically instantiate one and add all the InterfaceType beans to it, then inject it.
Your XML would simply look like
<bean id="service" class="...Service" autowire="byType">
</bean>
My original suggested solution made use of SpEL.
In the module that does have Spring dependencies, create a DTO
#Component(value = "beanDTO")
public class BeanDTO {
#Autowire
private List<InterfaceType> implementingBeans;
public List<InterfaceType> getImplementingBeans() {
return implementingBeans;
}
}
and then use SpEL to retrieve the value of implementingBeans from the beanDTO bean.
<bean id="service" depends-on="beanDTO" class="...Service">
<property name="implementingBeans" value="{beanDTO.implementingBeans}" />
</bean>
Spring will create the BeanTDO bean, inject all the beans that are of type InterfaceType. It will then create the service bean and set its property from beanDTO's implementingBeans property.
Following comments on question:
In an effort to be more JSR 330 compliant, Spring has introduced support for Java EE's javax.inject package. You can now annotate your injection targets with #javax.inject.Inject instead of #Autowired. Similarly, you can use #Named instead of #Component. The documentation has more details.
Anyone knows why apparently it is not possible to use AOP with annotated MVC Controllers? (see Post).
I have a #Controller that stops working as soon as I add a pointcut to it.
The problem is not that the interceptor is not being called, but rather the #Controller simply stops working (in the log you can see that instead of "Mapped URL path [/xx] onto handler 'Yyy'" you get a "no URL paths identified").
I know there is a mechanism for adding interceptors to controllers via the handlerMapping but my question is specific to AOP interceptors. Aren't annotated controllers just pojos in the Spring container as any other pojo? What is the difference? Why?
#Controller
#RequestMapping("/user")
public class RestTestImpl implements RestTest {
#RequestMapping(value="/", method={RequestMethod.GET})
public #ResponseBody String deleteUsers(String arg) {
return "Xxxxx";
}
}
In my servlet-Context I have:
<context:component-scan base-package="org.xxx.yyy"></context:component-scan>
<mvc:annotation-driven />
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
. . .
</bean>
And everything works just great.
But when I add:
<aop:config>
<aop:pointcut expression="execution(* org.xxx.*(..))" id="pc1"/>
<aop:advisor advice-ref="hibernateInterceptor" pointcut-ref="pc1" order="2" />
</aop:config>
The controller stops being a controller (no errors, simply it stops binding to the specified URL)!
From the Spring MVC Reference:
Note
When using controller interfaces (e.g. for AOP proxying),
make sure to consistently put all your
mapping annotations - such as
#RequestMapping and #SessionAttributes
- on the controller interface rather than on the implementation class.
Granted, this note is well hidden :-)
I ran into the same issue and found out the solution.
Indeed your controller (annotated by #Controller) and your aspects (annotated by #Aspect) should be in the same Spring context.
Usually people define their controllers in the dispatch-servlet.xml or xxx-servlet.xml and their service beans (including the aspects) in the main applicationContext.xml. It will not work.
When Spring initializes the MVC context, it will create a proxy for your controller but if your aspects are not in the same context, Spring will not create interceptors for them.
The above ssertion does not depend
on the way your declare your controllers/aspects (by manual XML declaration or annotation style)
on the proxying style you choose (JDK proxy or CGLIB)
I've tested all the combinations and they all work as long as the controller & aspects are in the same Spring context
My best guess without doing some serious digging is because Spring's AOP mechanism that you are using is wrapping the target classes in proxy classes which end up loosing their annotation or the original annotation gets dropped after weaving.
I am sure there is a better answer and I'll expand on mine as I think of a better more clear way to present it.
I have several controllers in a spring mvc application. They are regular beans that inherit from MultiActionController. They also have a custom MethodNameResolver that inspects a certain request parameter.
Now I am trying to use a new controller - a pojo with #Controller annotation. I am using #RequestMapping to resolve methods.
I am not sure if I understand this correctly, but as explained here in the spring reference, it is possible to use #RequestMapping with various filters (e.g. GET vs POST) without specifying a path, and then if a url applies to several methods then Spring falls back to InternalPathMethodNameResolver to decide which method to invoke.
How can I tell Spring to fall back to my custom MethodNameResolver? Is it enough to inject the resolver to my pojo controller?
(my controller doesn't inherit from any Spring specific class)
I guess you need to declare AnnotationMethodHandlerAdapter bean and set its methodNameResolver property.