问题:
在LVMMCrawlerSuit.java是xml配置的bean, 需要注入用@Component声明的bean. 但是运行的时候却报NullPointerException. 说明没有注入进来.
代码:
1. java
- 1. LVMMCrawlerSuit.java
- public class LVMMCrawlerSuit extends AbstractCrawlerSuit{
- @Resource
- private LVMMURLBuilder lvmmurlBuilder;
- public LVMMCrawlerSuit() {
- }
- }
- 2. LVMMURLBuilder.java
- @Component
- public class LVMMURLBuilder extends AbstractResourceURLBuilder {
- public LVMMURLBuilder() { }
- }
2. 配置.
- <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查找,很容易找到了配置信息如下.
- <servlet>
- <servlet-name>dispatcherServlet</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <init-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>
- classpath:classpath:app-web.xml
- </param-value>
- </init-param>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>classpath:applicationContext-*.xml</param-value>
- </context-param>
既然,两次加载,并且加载了不同的beans,虽然有父子的层级关系,但是限制多多. 那么就尝试合二为一.
在test中,发现因为修改了spring默认加载的文件名,所以删除任何一个配置都不能正确运行.那么就全部设置成一样的吧. test success......
解决方案:
方案一. 将配置文件路径合并, 分别指定给不同配置.
- <servlet>
- <servlet-name>dispatcherServlet</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <init-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>
- classpath:applicationContext-*.xml,classpath:app-web.xml
- </param-value>
- </init-param>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>classpath:applicationContext-*.xml,classpath:app-web.xml</param-value>
- </context-param>
方案二. 原有配置不变,合理规划Bean的定义及合理使用.
在方案一中, 使用的简单,粗暴的解决办法. 没有考虑到spring的设计思想. 既然有ioc容器的父子级划分,那么在使用的时候,一定会有用的.
在使用annotation定义bean 的时候,是需要增加如下代码,对使用何种注解的类才管理到ioc容器中.
- <context:component-scan base-package="com.qunar.b2c">
- <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
- <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository" />
- <context:include-filter type="annotation" expression="org.springframework.stereotype.Service" />
- <context:include-filter type="annotation" expression="org.springframework.stereotype.Component" />
- </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, 这样就将职责分开了.所以修改的配置如下:
- applicationContext-beans.xml:
- <context:component-scan base-package="com.qunar.b2c">
- <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository" />
- <context:include-filter type="annotation" expression="org.springframework.stereotype.Service" />
- <context:include-filter type="annotation" expression="org.springframework.stereotype.Component" />
- </context:component-scan>
- app-web.xml
- <context:component-scan base-package="com.qunar.b2c">
- <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
- </context:component-scan>
在开发定义bean的时候, 也需要注意,把bean定义到哪一层级.
相关推荐
Spring Annotation 注解 Spring 框架中的注解是用于在 Java 类中添加元数据的,通过这些元数据,Spring 框架可以在运行时提供更多的功能。 Spring 框架提供了多种类型的注解,例如 @Autowired、@Resource、@...
在Spring框架中,@Autowired不仅提供了方便的依赖注入,还与其他注解(如@Service、@Repository、@Component、@Controller等)一起构成了强大的组件模型,使得应用程序的组件更加松耦合,易于测试和维护。...
4. **注解配置与XML配置的对比**:Spring框架既支持XML配置也支持注解配置。XML配置方式直观,但代码量大,维护困难;注解配置简洁,减少了XML配置文件,使代码更加清晰,同时提高了可读性和可维护性。然而,对于...
在Spring框架中,自动检测注解(Autowired)是核心特性之一,它极大地简化了依赖注入的过程,使得开发者能够更加专注于业务逻辑,而不是繁琐的配置。本文将深入探讨Spring中的自动检测注解及其工作原理。 首先,`@...
在Spring框架中,Annotation配置是一种简洁且强大的方式来管理Bean的定义和依赖注入,它消除了传统的XML配置文件,使得代码更加简洁、易读。在Spring 3.0及以上版本中,Annotation配置得到了广泛的应用。 首先,...
**@Autowired 与 @ComponentScan**:在 XML 配置中,<context:component-scan> 标签用于扫描指定包及其子包下的类,寻找使用了 @Component、@Service、@Repository 和 @Controller 等注解的类,这些类会被注册为 ...
Spring注解是Spring框架中的一种核心特性,它允许开发者在Java源代码中嵌入元数据,简化了XML配置,提高了代码的可读性和维护性。从Spring 2.5开始,注解成为主流配置方式,提供了更加简洁和直观的Bean定义和依赖...
Spring框架允许开发者灵活地选择注解或XML配置,甚至可以混合使用。通过`<context:annotation-config/>`元素,可以在XML配置中启用注解驱动的配置,它会自动注册相关的Bean后处理器,如@...
3. **配置DWR**:在`dwr.xml`配置文件中,可以使用`<create>`标签手动配置可远程访问的Java类,但在全注解方式下,这部分配置可以省略,因为Spring会自动处理。 4. **注解Java类**:在需要暴露给DWR的Java类上使用`...
然而,随着框架的发展,为了简化配置,Spring引入了最小化XML配置的概念,以及注解装配的方式,使得配置更加简洁和高效。本文将深入探讨如何实现Spring的最小化XML配置。 一、自动装配 1. 四种类型的自动装配 - ...
2. **创建Spring配置文件**:编写XML配置文件或使用Java配置类来定义Bean和其依赖关系。 3. **使用注解**:在需要注入的地方添加适当的注解,如`@Autowired`、`@Resource`等。 4. **配置处理器**:对于`@Autowired...
Spring Annotation的引入主要是为了解决XML配置的繁琐问题。在传统的Spring应用中,大量的bean配置信息存储在XML文件中,这不仅增加了配置文件的复杂性,也使得代码与配置分离,降低了代码的直观性。Spring ...
随着技术的发展,Spring引入了注解(Annotation),极大地简化了配置,使得代码更加简洁、易读。这篇文档将深入探讨Spring注解的使用,包括它们如何工作以及如何在实际项目中应用。 首先,让我们了解Spring的核心...
本文主要讨论Spring中的@Autowired注解,以及如何通过注解实现依赖注入,从而避免了在.java和.xml文件间频繁切换的问题。 首先,让我们回顾一下传统的Spring配置方式。在不使用注解的情况下,我们需要在.xml文件中...
**Spring Annotation注解** Spring框架允许开发者使用注解来声明Bean、依赖注入、事务管理等。例如: - `@Component`、`@Service`、`@Repository`和`@Controller`注解用于标记组件类,使它们成为Spring容器的一部分...
Spring 2.5引入了@Autowired注解,它极大地简化了配置,允许开发者在不编写XML配置文件的情况下完成bean的自动装配。本文将深入探讨@Autowired注解以及如何在Spring中使用它。 @Autowired注解的主要作用是自动将所...
在这个特定的项目中,开发者选择了SSH2的特定版本:Struts2.1.6、Spring2.5.6和Hibernate3.3,并且强调了全注解开发,这意味着在配置文件中尽可能地使用注解来代替XML配置。 首先,让我们详细了解一下这三个框架的...
Spring注解的使用大大减少了XML配置,提高了代码的可读性和维护性。理解并熟练运用这些注解是每个Spring开发者必备的技能。在实际开发中,根据项目需求选择合适的注解,可以有效地组织和管理代码,提升开发效率。