原文链接:http://outofmemory.cn/java/spring/spring-DI-inner-class

在spring中注入内部类,有可能会遇到如下异常信息:

2014-5-14 21:52:45 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1c56c60: startup date [Wed May 14 21:52:45 CST 2014]; root of context hierarchy
2014-5-14 21:52:45 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [spring.xml]
2014-5-14 21:52:46 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@7244ca: defining beans [person]; root of factory hierarchy
2014-5-14 21:52:46 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry destroySingletons
信息: Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@7244ca: defining beans [person]; root of factory hierarchy
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'person' defined in class path resource [spring.xml]: Cannot create inner bean 'cn.outofmemory.spring.Person$Hand#ab7165' of type [cn.outofmemory.spring.Person$Hand] while setting bean property 'hands' with key [0]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cn.outofmemory.spring.Person$Hand#ab7165' defined in class path resource [spring.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [cn.outofmemory.spring.Person$Hand]: No default constructor found; nested exception is java.lang.NoSuchMethodException: cn.outofmemory.spring.Person$Hand.<init>()
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:281)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:120)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveManagedList(BeanDefinitionValueResolver.java:353)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:153)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1325)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1086)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:580)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at cn.outofmemory.spring.App.main(App.java:14)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cn.outofmemory.spring.Person$Hand#ab7165' defined in class path resource [spring.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [cn.outofmemory.spring.Person$Hand]: No default constructor found; nested exception is java.lang.NoSuchMethodException: cn.outofmemory.spring.Person$Hand.<init>()
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:965)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:911)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:270)
... 17 more
Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [cn.outofmemory.spring.Person$Hand]: No default constructor found; nested exception is java.lang.NoSuchMethodException: cn.outofmemory.spring.Person$Hand.<init>()
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:70)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:958)
... 21 more
Caused by: java.lang.NoSuchMethodException: cn.outofmemory.spring.Person$Hand.<init>()
at java.lang.Class.getConstructor0(Class.java:2715)
at java.lang.Class.getDeclaredConstructor(Class.java:1987)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:65)
... 22 more

这个异常信息很长,他的意思是说我们没有给内部类指定构造函数,我们看下我们的代码和spring配置文件:

我们定义了一个Person类,这个类中有一个内部类Hand,Person类有一个hands的属性的类型是内部类数组

package cn.outofmemory.spring;

public class Person {
private Hand[] hands; public Hand[] getHands() {
return hands;
} public void setHands(Hand[] hands) {
this.hands = hands;
} public class Hand {
private int strength; public int getStrength() {
return strength;
}
public void setStrength(int strength) {
this.strength = strength;
} }
}

我们的spring配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="cn.outofmemory.spring.Person" id="person">
<property name="hands">
<list>
<bean class="cn.outofmemory.spring.Person$Hand">
<property name="strength" value="90"/>
</bean>
</list>
</property>
</bean>
</beans>

配置文件很简单,内部类的类名由外部类的全称+$+内部类的名称,这是无疑的。

内部类注入方式一:添加内部类默认构造函数参数

我们遇到上面的错误是因为非静态的内部类默认的构造函数有一个参数,这个参数指向其外部类的实例,所以我们需要给此内部类的bean添加constructor-arg节点,并指向外部类即可,我们修改下配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="cn.outofmemory.spring.Person" id="person">
<property name="hands">
<list>
<bean class="cn.outofmemory.spring.Person$Hand">
<constructor-arg ref="person"></constructor-arg>
<property name="strength" value="90"/>
</bean>
</list>
</property>
</bean>
</beans>

App类代码如下:

package cn.outofmemory.spring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; /**
* Hello spring from OutOfMemory.CN
*
*/
public class App
{
public static void main( String[] args )
{
ApplicationContext appContext = new ClassPathXmlApplicationContext("/spring.xml");
Person person = appContext.getBean(Person.class);
for (Person.Hand hand : person.getHands()) {
System.out.println("hand strength is " + hand.getStrength());
}
}
}

App类的main方法获得spring中定义的person类,然后打印每一个hand的strength属性。输出如下:

hand strength is 90

内部类注入方式二:将内部类修改为static

对于内部类,如果没必要访问外部类,我们可以将其定义为static的,这样在spring配置文件中配置时,就不需要设置默认构造函数了。

如下修改后的Person类:

package cn.outofmemory.spring;

public class Person {
private Hand[] hands; public Hand[] getHands() {
return hands;
} public void setHands(Hand[] hands) {
this.hands = hands;
} public static class Hand {
private int strength; public int getStrength() {
return strength;
} public void setStrength(int strength) {
this.strength = strength;
} }
}

修改后的spring配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="cn.outofmemory.spring.Person" id="person">
<property name="hands">
<list>
<bean class="cn.outofmemory.spring.Person$Hand">
<property name="strength" value="90"/>
</bean>
</list>
</property>
</bean>
</beans>

App类保持不变,我们再次运行程序,依然会得到如下的输出结果:

hand strength is 90

总结:

对于内部类的注入,要注意非静态内部类,其默认构造函数有一个参数,是其外部类的实例,记住这一点在spring中定义内部类就没有问题了。

如果内部类不需要访问外部类的实例,可以将其定义为static的,这样也就不需要额外的构造函数参数设置了。

(转载)在spring的bean中注入内部类的更多相关文章

  1. 在Spring的bean中注入HttpServletRequest解密

    我们可以在Spring的bean中轻松的注入HttpServletRequest,使用@Autowired HttpServletRequest request;就可以了. 但是,为什么我们可以直接这 ...

  2. Spring在Bean中注入集合

    以下内容引用自http://wiki.jikexueyuan.com/project/spring/injecting-collection.html: 如果你想传递多个值,如Java Collect ...

  3. spring IOC bean中注入集合

    建立一个实体 package com.java.test4; import java.util.*; /** * @author nidegui * @create 2019-06-22 14:45 ...

  4. spring IOC bean中注入bean

    俩个实体 package com.java.test4; /** * @author nidegui * @create 2019-06-22 14:45 */ public class People ...

  5. 【转】spring 装配Bean中构造参数的注入

    转载自:http://www.bianceng.cn/Programming/Java/201307/37027.htm spring 装配Bean中构造参数的注入 spring装配bean中还有一种 ...

  6. Spring在Thread中注入Bean无效的解决方式

    在Spring项目中,有时需要新开线程完成一些复杂任务,而线程中可能需要注入一些服务.而通过Spring注入来管理和使用服务是较为合理的方式.但是若直接在Thread子类中通过注解方式注入Bean是无 ...

  7. Spring IOC容器中注入bean

    一.基于schema格式的注入 1.基本的注入方式 (属性注入方式) 根据setXxx()方法进行依赖注入,Spring只会检查是否有setter方法,是否有对应的属性不做要求 <bean id ...

  8. spring中如何向一个单例bean中注入非单例bean

    看到这个题目相信很多小伙伴都是懵懵的,平时我们的做法大都是下面的操作 @Component public class People{ @Autowired private Man man; } 这里如 ...

  9. spring给容器中注入组件的几种方式

    目录 环境搭建 spring给容器中注入组件 1.包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)适用于把自己写的类加入组件(默认ID类名 ...

随机推荐

  1. 第 15 章 可扩展性设计之 Cache 与 Search 的利用

    前言: 前面章节部分所分析的可扩展架构方案,基本上都是围绕在数据库自身来进行的,这样是否会使我们在寻求扩展性之路的思维受到“禁锢”,无法更为宽广的发散开来.这一章,我们就将跳出完全依靠数据库自身来改善 ...

  2. Python之日志处理(logging模块)

    本节内容 日志相关概念 logging模块简介 使用logging提供的模块级别的函数记录日志 logging模块日志流处理流程 使用logging四大组件记录日志 配置logging的几种方式 向日 ...

  3. CefSharp使用入门

    首先这是很重要的,环境搭建: 我用的是VS2017 步骤            方法 1.            打开VS的安装管理器 2.             进入修改界面,使用C++的桌面开发 ...

  4. C# DataTable转换成实体列表 与 实体列表转换成DataTable

    /// <summary> /// DataTable转换成实体列表 /// </summary> /// <typeparam name="T"&g ...

  5. 利刃 MVVMLight

    已经很久没有写系列文章了,上一次是2012年写的HTLM5系列,想想我们应该是较早一批使用HTML5做项目的人. 相比我当时动不动100+的粉丝增长和两天3000+的阅读量,MVVM Light只能算 ...

  6. SG函数和SG定理【详解】

    在介绍SG函数和SG定理之前我们先介绍介绍必胜点与必败点吧. 必胜点和必败点的概念:        P点:必败点,换而言之,就是谁处于此位置,则在双方操作正确的情况下必败.        N点:必胜点 ...

  7. 记一次利用AutoMapper优化项目中数据层到业务层的数据传递过程。

    目前项目中获取到DataSet数据后用下面这种方式复制数据. List<AgreementDoc> list = new List<AgreementDoc>(); ].Row ...

  8. 一天搞定HTML----标签语义化04

    根据页面里不同的内容,选择最适合它的标签,而不通篇只用一种标签 标签语义化作用: 代码演示 通过比较- - -H5布局和DIV+CSS 布局- - -体现标签语义化 注意: 标签语义化,不仅仅只是指使 ...

  9. linux升级openssh7.4sp1

    1.准备相关的包 openssh下载地址:http://mirror.internode.on.net/pub/OpenBSD/OpenSSH/portable/ openssl相关包下载:http: ...

  10. list与Set、Map区别

    1.List,Set都是继承自Collection接口,Map则不是 2.List特点:元素有放入顺序,元素可重复 ,Set特点:元素无放入顺序,元素不可重复,重复元素会覆盖掉,(注意:元素虽然无放入 ...