以下文章为转载内容,但有些疑问再下方提出,请各位老师赐教。

SpringMVC 里上下文的概念

web.xml 里的配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://java.sun.com/xml/ns/javaee"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
        version="2.5">
   <display-name>uniweibov2</display-name>


   <listener>
       <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
   </listener>

   <context-param>
       <param-name>contextConfigLocation</param-name>
       <param-value>classpath:spring.xml</param-value>
   </context-param>

   <servlet>
       <servlet-name>mvc-dispatcher</servlet-name>
       <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
       <init-param>
           <param-name>contextConfigLocation</param-name>
           <param-value>classpath:spring-servlet.xml</param-value>
       </init-param>
       <load-on-startup>1</load-on-startup>
   </servlet>
   <servlet-mapping>
       <servlet-name>mvc-dispatcher</servlet-name>
       <url-pattern>/</url-pattern>
   </servlet-mapping>

</web-app>


在SpringMVC里,有两种上下文。一种是:Application Context,还有一种是Web Application Context.

application context (parent)

<listener>
   <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<context-param>
   <param-name>contextConfigLocation</param-name>
   <param-value>classpath:spring.xml</param-value>
</context-param>


这样的配置,就是在配置application context,也就是parent application context


web application context (child)

<servlet>
       <servlet-name>mvc-dispatcher</servlet-name>
       <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
       <init-param>
           <param-name>contextConfigLocation</param-name>
           <param-value>classpath:spring-servlet.xml</param-value>
       </init-param>
       <load-on-startup>1</load-on-startup>
   </servlet>
   <servlet-mapping>
       <servlet-name>mvc-dispatcher</servlet-name>
       <url-pattern>/</url-pattern>
   </servlet-mapping>

parent 是共享于 child的,也就是说,在parent中定义的东西,都可以在child中使用.

Bean加载两次的原因:

这是由于在这两个context里,配置的时候导致Spring扫描时,扫描并加载了两次Bean.

例如,在这两个spring.xmlspring-servlet.xml配置文件里,都配置了:

<context:component-scan base-package="xx.yy" />


解决办法

方法一

只使用一个上下文环境。即Bean的定义,只放在一个配置文件里,让另一个配置文件为空,即如下:

<?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"
xmlns:task="http://www.springframework.org/schema/task" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">


</beans>

这两个,只要一个为空,另一个不为空即可.


方法二

在这两个配置文件里,只是没有配置重复的内容即可.即如果在parent里定义了的Bean,就不要在child里定义了。这时,可以使用如下的方式来配置:

spring.xml里配置:

<context:annotation-config />
  <context:component-scan base-package="xx.yy">
      <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
  </context:component-scan>

这样子,就表明扫描除了有@Controller之外的所有注解的Bean.

spring-servlet.xml里配置:

这样子,就表明只扫描@Controller注解的Bean.注意这里的user-default-filters="false"

包扫描详解

<context:component-scan base-package="xx.yy" use-default-filters="false">

base-package:要扫描的包
use-default-filters:是否使用默认的过滤器,默认为true,即扫描@Component, @Repository, @Service, @Controller这些注解的Bean
context:include-filter:使用白名单过滤器
context:exclude-filter:使用黑名单过滤器

Spring 的使用顺序是: 先 exclude-filter,再到include-filter

在源码org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider的方法里:

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, this.metadataReaderFactory)) {
return false;
}
}
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, this.metadataReaderFactory)) {
AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
if (!metadata.isAnnotated(Profile.class.getName())) {
return true;
}
AnnotationAttributes profile = MetadataUtils.attributesFor(metadata, Profile.class);
return this.environment.acceptsProfiles(profile.getStringArray("value"));
}
}
return false;
}

type的类型还有:



type=`annotation`
type=`assignable`
type=`aspectj`
type=`regex`
type=`custom`


转自:http://emacsist.github.io/2015/11/23/Spring-MVC-%E9%87%8C%E5%8A%A0%E8%BD%BD%E4%B8%A4%E6%AC%A1Bean%E7%9A%84%E8%A7%A3%E5%86%B3%E5%8A%9E%E6%B3%95/


以上文章为转载内容,这里有个疑问,web容器启动时若按照方法二进行配置,在controller中引入了service层的一个 bean(@Service("iAdminUserService")),controller中配置如下:

@Resource
private IAdminUserService iAdminUserService;

此时就会报以下异常:

.NoSuchBeanDefinitionException: No qualifying bean of type [com..service.IAdminUserService]

所以只能先用第一种方法,删除spring容器中的自动扫描,只加springmvc中的自动扫描。


此处留下个疑问,待以后有时间再进行测试,若有大师看到此处有好的解决办法,就请留言给我,小弟不胜感激。