Spring MVC: difference between <context:component-scan> and <annotation-driven /> tags?
<mvc:annotation-driven />
means that you can define spring beans dependencies without actually having to specify a bunch of elements in XML or implement an interface or extend a base class. For example @Repository
to tell spring that a class is a Dao without having to extend JpaDaoSupport
or some other subclass of DaoSupport. Similarly @Controller
tells spring that the class specified contains methods that will handle Http requests without you having to implement the Controller interface or extend a subclass that implements the controller.
When spring starts up it reads its XML configuration file and looks for <bean
elements within it if it sees something like <bean class="com.example.Foo" />
and Foo was marked up with @Controller
it knows that the class is a controller and treats it as such. By default, Spring assumes that all the classes it should manage are explicitly defined in the beans.XML file.
Component scanning with <context:component-scan base-package="com.mycompany.maventestwebapp" />
is telling spring that it should search the classpath for all the classes under com.mycompany.maventestweapp and look at each class to see if it has a @Controller
, or @Repository
, or @Service
, or @Component
and if it does then Spring will register the class with the bean factory as if you had typed <bean class="..." />
in the XML configuration files.
In a typical spring MVC app you will find that there are two spring configuration files, a file that configures the application context usually started with the Spring context listener.
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
And a Spring MVC configuration file usually started with the Spring dispatcher servlet. For example.
<servlet>
<servlet-name>main</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>main</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Spring has support for hierarchical bean factories, so in the case of the Spring MVC, the dispatcher servlet context is a child of the main application context. If the servlet context was asked for a bean called "abc" it will look in the servlet context first, if it does not find it there it will look in the parent context, which is the application context.
Common beans such as data sources, JPA configuration, business services are defined in the application context while MVC specific configuration goes not the configuration file associated with the servlet.
Hope this helps.
What's the difference between <mvc:annotation-driven /> and <context:annotation-config /> in servlet?
<context:annotation-config>
declares support for general annotations such as @Required
, @Autowired
, @PostConstruct
, and so on.
<mvc:annotation-driven />
declares explicit support for annotation-driven MVC controllers (i.e. @RequestMapping
, @Controller
, although support for those is the default behaviour), as well as adding support for declarative validation via @Valid
and message body marshalling with @RequestBody
/ResponseBody
.
Difference between register() and @ComponentScan
There is no difference. It are different ways of registering a bean in the Spring application context. Like you can use XML or Java based configuration. In the end it is all metadata used to construct the ApplicationContext
. The one with the registerBean
is considered the (sort of) functional style of registering beans. This is mainly being utilized to be able to write the Kotlin bean registration DSL (AFAIK).
Although they work differently, i.e. registering components directly as opposed to scan the classpath for beans that match the selection criteria (default is to detect @Component
). The end result is the same.
For all of them a BeanDefinition
is being created by Spring. The exact type of BeanDefinition
will differ based on the type of configuration. For XML and Properties based it will, generally, be a RootBeanDefinition
, when detected with component scanning a ScannedBeanDefinition
etc. For the registerBean
it will be a ClassDerivedBeanDefinition
.
BeanDefinition
s are the recipes on how to create beans.
All the different ways as shown below will have the same end result. An ApplicationContext
with a FooService
.
public class FooService { ... }
XML
<bean id="fooService" class="FooService"/>
XML with Component Scan
@Service
public class FooService { ... }
<context:component-scan />
Java Config
@Bean
public FooService fooService() {
return new FooService();
}
Java Config with Component Scan
@Service
public class FooService { ... }
@ComponentScan
public FooConfig {}
Functional Style DSL
context.registerbean("fooService", FooService.class, () -> new FooService());
Properties Based
fooService.(class)=FooService
Then use the PropertiesBeanDefinitionReader
to load it (going to be deprecated or removed as of Spring 5.3).
Spring: annotation-config base-package
Using <context:component-scan base-package="com.org.pkg1"/>
doesn't imply that you are
enabling annotation scanning in the whole project
It's true that <context:component-scan>
also enables <context:annotation-config>
. But the latter only allows the recognition of annotations in the already registered beans (no matter if they come from a scan or from XML).
Answering your question:
Is that true, and if so, can it be avoided
No.
This is the official doc for annotation-scanning:
Activates various annotations to be detected in bean classes: Spring's
@Required and @Autowired, as well as JSR 250's @PostConstruct,
@PreDestroy and @Resource (if available), JAX-WS's @WebServiceRef (if
available), EJB 3's @EJB (if available), and JPA's @PersistenceContext
and @PersistenceUnit
How to use context:component-scan base-package on Dispatcher-servlet.xml
You have to write the name of the package that include all your spring annotated class. In your case you only have a controller and its package name is Controller
, so this is the correct way to use it:
<context:component-scan base-package="Controller" />
If you have more that one package that includes spring annotated class use a common path to each package and use it in component scan, for example:
Let's say you have Entities, Repositories and Controllers classes. Put them respectively in myProject.Entities
, myProject.Repositories
and myProject.Controllers
packages and use component scan like this:
<context:component-scan base-package="myProject" />
Related Topics
Classpath Including Jar Within a Jar
Appending to an Objectoutputstream
Jcomponents Not Showing Up With Picture Background
Instantiating a Generic Class in Java
Why in Java 8 Split Sometimes Removes Empty Strings At Start of Result Array
Simpledateformat Ignoring Month When Parsing
How to Implement a Single Instance Java Application
How Does the "Final" Keyword in Java Work (I Can Still Modify an Object.)
To Prevent a Memory Leak, the Jdbc Driver Has Been Forcibly Unregistered
How Can a Java Program Get Its Own Process Id
How to Read and Write Excel File
How to Sort by Two Fields in Java
How to Convert Epoch to MySQL Timestamp in Java
How to Use a Servlet Filter in Java to Change an Incoming Servlet Request Url