先来看一段配置
web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring/applicationContext.xml</param-value>
</context-param>
<!--若无context-param则ContextLoaderListener默认加载WEB-INFO目录下的applicationContext.xml文件 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--若无init-param则默认加载WEB-INFO目录下的xxx-servlet.xml(即此处默认加载springMVC-servlet.xml)文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
spring-mvc.xml
<context:component-scan base-package="com.example.**.*" >
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
<bean id="javaMailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="smtp.163.com" />
<property name="port" value="465" />
<property name="username" value="" />
<property name="password" value="" />
<property name="defaultEncoding" value="utf-8" />
<property name="javaMailProperties">
<props>
<prop key="mail.smtp.auth">true</prop>
<prop key="mail.smtp.ssl.enable">true</prop>
<prop key="mail.transport.protocol">smtp</prop>
<prop key="mail.smtp.timeout">25000</prop>
</props>
</property>
</bean>
applicationContext.xml
<context:component-scan base-package="com.example.services" />
基于上面这些配置信息,当我们在service
内获取spring
容器中的javaMailSender
对象时出现NoSuchBeanDefinitionException
。
单元测试时正常,但正常调用时却发生异常。对比单元测试使用的配置文件,发现两处的文件是一致的。于是想到会不会是父子容器的问题。
将spring-mvc.xml
中关于javaMailSender
的配置迁移到applicationContext.xml
后,不再报错。
spring只允许子容器中的元素访问父容器中的元素,而不允许将此顺序反过来。
通过ContextLoaderListener
加载的元素均保存在父容器中,而通过DispatcherServlet
加载的元素则保存在子容器中。