spring的xml配置与annotation注解混合

spring的xml配置与annotation注解混合使用无法Autowired的问题

问题:

在LVMMCrawlerSuit.java是xml配置的bean, 需要注入用@Component声明的bean. 但是运行的时候却报NullPointerException. 说明没有注入进来.

 

代码:

1. java

Java代码   收藏代码
  1. 1. LVMMCrawlerSuit.java  
  2.  public class LVMMCrawlerSuit extends AbstractCrawlerSuit{  
  3.   
  4.     @Resource  
  5.     private LVMMURLBuilder lvmmurlBuilder;  
  6.   
  7.     public LVMMCrawlerSuit() {  
  8.     }  
  9. }  
  10.   
  11. 2. LVMMURLBuilder.java  
  12. @Component  
  13. public class LVMMURLBuilder extends AbstractResourceURLBuilder {  
  14.     public LVMMURLBuilder() {    }  
  15. }  

 

2. 配置.

Xml代码   收藏代码
  1. <bean id="LVMMCrawlerSuit" class = 'com.qunar.b2c.crawlersuit.impl.LVMMCrawlerSuit'/>   

 

问题查找:

1. 查找网上资源,未果.

2. 果断debug,跟踪源码.

       将断点定位到 org.springframework.context.support.AbstractRefreshableApplicationContext#loadBeanDefinitions ,该方法是加载bean的必经之路.跟踪发现,该方法共执行两次,生成了两个不同的 org.springframework.beans.factory.support.DefaultListableBeanFactory, 并且后者的parentBeanFactory为前者,根据原设计是后者可以调用前者的bean 并完成注入.

      现在报NullPointerException,很明显是"父调用子",所以肯定拿不到.在打印的log中进行了佐证.

      在debug中发现,两次执行分别来自不同的beans资源文件: app-web.xml 和 applicationContext-*.xml, 按key查找,很容易找到了配置信息如下.

Xml代码   收藏代码
  1. <servlet>  
  2.         <servlet-name>dispatcherServlet</servlet-name>  
  3.         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
  4.         <init-param>  
  5.             <param-name>contextConfigLocation</param-name>  
  6.             <param-value>  
  7.                 classpath:classpath:app-web.xml  
  8.             </param-value>  
  9.         </init-param>  
  10.         <load-on-startup>1</load-on-startup>  
  11.     </servlet>  
  12.   
  13.         <context-param>  
  14.         <param-name>contextConfigLocation</param-name>  
  15.         <param-value>classpath:applicationContext-*.xml</param-value>  
  16.     </context-param>  

 

    既然,两次加载,并且加载了不同的beans,虽然有父子的层级关系,但是限制多多. 那么就尝试合二为一.

    在test中,发现因为修改了spring默认加载的文件名,所以删除任何一个配置都不能正确运行.那么就全部设置成一样的吧. test success......

 

解决方案:

    方案一. 将配置文件路径合并, 分别指定给不同配置.

Xml代码   收藏代码
  1. <servlet>  
  2.         <servlet-name>dispatcherServlet</servlet-name>  
  3.         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
  4.         <init-param>  
  5.             <param-name>contextConfigLocation</param-name>  
  6.             <param-value>  
  7.                 classpath:applicationContext-*.xml,classpath:app-web.xml  
  8.             </param-value>  
  9.         </init-param>  
  10.         <load-on-startup>1</load-on-startup>  
  11.     </servlet>  
  12.   
  13.         <context-param>  
  14.         <param-name>contextConfigLocation</param-name>  
  15.         <param-value>classpath:applicationContext-*.xml,classpath:app-web.xml</param-value>  
  16.     </context-param>  

 

 

    方案二. 原有配置不变,合理规划Bean的定义及合理使用.

         在方案一中, 使用的简单,粗暴的解决办法. 没有考虑到spring的设计思想. 既然有ioc容器的父子级划分,那么在使用的时候,一定会有用的.

         在使用annotation定义bean 的时候,是需要增加如下代码,对使用何种注解的类才管理到ioc容器中.

 

Xml代码   收藏代码
  1. <context:component-scan base-package="com.qunar.b2c">  
  2.        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />  
  3.        <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository" />  
  4.        <context:include-filter type="annotation" expression="org.springframework.stereotype.Service" />  
  5.        <context:include-filter type="annotation" expression="org.springframework.stereotype.Component" />  
  6.    </context:component-scan>  

 

        上述提到, 在 spring web的使用中, 会加载两个ioc容器,

          1. 一个是contextConfigLocation定义,用来启动spring核心框架的. 所以在该步骤中,应加载应用中的基础服务信息的bean,如 dao,Service 等等.

          2. 另外一个ioc容器是web加载的容器, 那么只需加载Controller相关的bean.

        因为在spring ioc的 DefaultListableBeanFactory类是支持父子关系,

            1. 子容器是可以访问到父容器中的bean,

            2. 然而父容器访问不了子容器的bean,

        这就保证了, Controller可以访问 Service等, 但是Service 访问不了web层的bean, 这样就将职责分开了.所以修改的配置如下:

 

Xml代码   收藏代码
  1. applicationContext-beans.xml:  
  2.   
  3. <context:component-scan base-package="com.qunar.b2c">  
  4.         <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository" />  
  5.         <context:include-filter type="annotation" expression="org.springframework.stereotype.Service" />  
  6.         <context:include-filter type="annotation" expression="org.springframework.stereotype.Component" />  
  7.     </context:component-scan>  
  8.   
  9. app-web.xml  
  10.   
  11.  <context:component-scan base-package="com.qunar.b2c">  
  12.         <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />  
  13.    </context:component-scan>  

 

     在开发定义bean的时候, 也需要注意,把bean定义到哪一层级.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值