Reputation: 2440
I have a controller in my codebase whose package is not component scanned. This controller is also not defined in a bean in any XML.
Somehow, the controller is working. I'm guessing this is because there is some way of defining a controller in Spring without component scanning or defining it in a bean. However, this controller implements a class called AbstractControllerImpl, and the Helper implementation class IS getting component scanned.
Does the fact that the Helper is getting component scanned mean the Controller gets scanned too? Or if not, how is it possible that this controller works?
@Controller
@RequestMapping("/something")
public class SomeController extends AbstractControllerImpl<SomeControllerHelper> {
//Some request mappings here
}
The abstract controller class it extends:
public abstract class AbstractControllerImpl<H extends Helper>
implements Controller<H>
{
private H helper;
private BaseValidator validator;
public H getHelper()
{
return helper;
}
public void setHelper(H helper)
{
this.helper = helper;
}
public void setValidator(BaseValidator validator)
{
this.validator = validator;
}
public BaseValidator getValidator()
{
return validator;
}
public Errors doValidation(Object obj)
{
Errors validationErrors = new BindException(this, "");
if (validator != null)
{
validator.validate(obj, validationErrors);
}
return validationErrors;
}
}
The Controller interface:
public interface Controller<H extends Helper>
{
H getHelper();
}
The helper definition:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="someHelper" class="com.controller.SomeHelperImpl" />
</beans>
The helper impl class (which is getting component scanned):
@Component("SomeControllerHelper")
public class ASomeControllerHelperImpl implements SomeControllerHelper {
//Some methods here
}
Edit: My web.xml. I removed a few of the servlet mappings and changed some of the names, but this is what it looks like:
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>SomeApp</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<listener>
<listener-class>
com.Log4jLoaderServlet
</listener-class>
</listener>
<context-param>
<param-name>crossContext</param-name>
<param-value>true</param-value>
</context-param>
<!-- This listener will load other application context file in addition to springweb-servlet.xml -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- The context params that read by ContextLoaderListener -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-application-context.xml</param-value>
</context-param>
<!-- Spring security filter -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
<servlet>
<servlet-name>rest</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/servlets/rest-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>rest</servlet-name>
<url-pattern>/service/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>appservlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/servlets/app-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<error-page>
<error-code>404</error-code>
<location>/portal/error/notfound/</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/portal/error/internalsystem/</location>
</error-page>
<jsp-config>
<taglib>
<taglib-uri>http://java.sun.com/jsp/jstl/core</taglib-uri>
<taglib-location>/WEB-INF/tags/c.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>http://jakarta.apache.org/taglibs/unstandard-1.0</taglib-uri>
<taglib-location>/WEB-INF/tld/unstandard.tld</taglib-location>
</taglib>
</jsp-config>
Here is app-servlet.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView" />
<property name="order" value="0" />
</bean>
<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="order" value="1" />
</bean>
<bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
<property name="basename" value="views"/>
</bean>
<bean id="tilesConfigurer"
class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/views/something/views.xml</value>
<value>/WEB-INF/views/views.xml</value>
</list>
</property>
<property name="preparerFactoryClass"
value="org.springframework.web.servlet.view.tiles2.SpringBeanPreparerFactory"/>
</bean>
</beans>
rest-servlet.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.dw.spring3.rest.controller" />
<!-- To enable @RequestMapping process on type level and method level -->
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jsonConverter" />
</list>
</property>
</bean>
<bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="supportedMediaTypes" value="application/json" />
</bean>
</beans>
root-application-cnntext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan
base-package="com.base.notcontroller" />
<import resource="/something/common-context.xml" />
</beans>
Upvotes: 1
Views: 1586
Reputation: 280122
Does the fact that the Helper is getting component scanned mean the Controller gets scanned too? Or if not, how is it possible that this controller works?
No, that is not possible.
It is not entirely clear what your context configuration looks like given that you've
removed a few of the servlet mappings and changed some of the names
but your @Controller
class must be loaded into the context somewhere, possibly in
rest-servlet.xml:
which has
<context:component-scan base-package="com.dw.spring3.rest.controller" />
which is loaded by the DispatcherServlet
named `rest
.
<servlet>
<servlet-name>rest</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/servlets/rest-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
You can add a no-arg constructor to your @Controller
class and put a breakpoint in, look at the stack trace and identify in which context it is being initialized.
Note that AnnotationMethodHandlerAdapter
has been deprecated in Spring 3.2. Consider using <mvc:annotation-driven>
to configure your MVC environment.
Upvotes: 2