一、配置解读
你给出的配置片段是:
<bean id="starbean" class="com.xie.spring.starfactory" factory-method="get"> </bean>
这段配置的含义是:spring 会调用 com.xie.spring.starfactory 类中的静态方法 get(),用它的返回值作为容器中 starbean 这个 bean 的实例。
也就是说,容器里 starbean 的类型取决于 get() 方法的返回类型,而不是 starfactory 这个类本身。
二、静态工厂方法实例化的前提条件
要让这段配置正常工作,必须满足以下条件:
1. get() 必须是静态方法
public class starfactory {
public static star get() {
star star = new star();
star.setname("太阳");
return star;
}
}
如果 get() 不是 static 的,spring 启动时会报错,因为它无法在没有工厂实例的情况下调用实例方法。
2. get() 的返回类型必须与 getbean() 时的期望类型一致
star star = context.getbean("starbean", star.class);
如果 get() 返回的是 star,注入成功。如果返回的是 starfactory 或其他类型,就会抛出 beannotofrequiredtypeexception。
3. 如果 get() 有参数,必须用 <constructor-arg> 传递
<bean id="starbean" class="com.xie.spring.starfactory" factory-method="get">
<constructor-arg name="name" value="太阳"/>
</bean>
注意:这里虽然标签名是 constructor-arg,但实际是传给工厂方法的参数,不是构造方法参数。不能用 <property>。
三、与实例工厂方法的对比
如果 get() 不是静态方法,就必须改用实例工厂写法:
<!-- 先定义工厂 bean --> <bean id="starfactory" class="com.xie.spring.starfactory"/> <!-- 再通过工厂实例调用方法 --> <bean id="starbean" factory-bean="starfactory" factory-method="get"/>
此时第二个 <bean> 不能再写 class 属性。否则容器里存放的将是 starfactory 实例,而不是 get() 返回的产品,调用 getbean("starbean", star.class) 时就会报类型不匹配。
| 对比维度 | 静态工厂方法 | 实例工厂方法 |
|---|---|---|
| 工厂方法类型 | static | 非静态 |
| xml 配置 | class + factory-method | factory-bean + factory-method |
| 工厂是否需要实例化 | 不需要 | 需要,且由 spring 管理 |
| 工厂能否注入依赖 | 不能 | 可以 |
四、常见错误:beannotofrequiredtypeexception
你之前遇到的报错是:
bean named 'starbean' is expected to be of type 'com.xie.spring.star' but was actually of type 'com.xie.spring.starfactory'
这个异常表示:你试图从容器中获取名为 starbean 的 bean,期望类型是 star,但容器中实际存放的却是 starfactory 类型的实例。
根本原因
出现这个错误,通常是因为配置或代码中,starbean 被定义成了 starfactory 本身,而不是通过工厂方法创建出的 star 对象。常见情况有:
忘记写 factory-method
<bean id="starbean" class="com.xie.spring.starfactory"/>
spring 直接实例化 starfactory,自然类型不匹配。
factory-method 方法返回了工厂自身
public static starfactory get() {
return new starfactory(); // 返回的是工厂,不是产品
}
实例工厂方法配置错误
<bean id="starbean" class="com.xie.spring.starfactory"/>
应该写成 factory-bean 引用,而不是直接写 class。
使用 factorybean 接口时获取方式错误 如果 starfactory 实现了 factorybean<star>,那么:
getbean("starbean")返回stargetbean("&starbean")返回starfactory写反了就会类型不匹配。
五、完整正确示例
java 类:
public class star {
private string name;
// getter/setter/tostring
}
public class starfactory {
public static star get() {
star star = new star();
star.setname("太阳");
return star;
}
}
beans.xml:
<?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 id="starbean" class="com.xie.spring.starfactory" factory-method="get"/>
</beans>测试代码:
public class testfirstbean {
@test
public void test() {
applicationcontext context = new classpathxmlapplicationcontext("beans.xml");
star star = context.getbean("starbean", star.class);
system.out.println(star); // star{name='太阳'}
}
}
六、排查步骤
- 打开 spring 的 xml 配置文件。
- 找到
id="starbean"的 bean 定义。 - 检查:
- 是否使用了
factory-method? - 如果是静态工厂,
class是否指向工厂类? - 如果是实例工厂,是否配置了
factory-bean和factory-method? - 如果实现了
factorybean,是否通过&starbean获取工厂?
- 是否使用了
- 确认工厂方法的返回类型是
star,而不是starfactory。 - 先不指定类型获取 bean,打印实际类型:
object bean = context.getbean("starbean");
system.out.println(bean.getclass().getname());
如果输出 com.xie.spring.star,说明配置正确;如果输出 com.xie.spring.starfactory,说明工厂方法返回了工厂自身。
七、总结
| 维度 | 核心要点 |
|---|---|
| 配置含义 | 调用静态工厂方法 get(),用返回值作为 bean |
| 前提条件 | get() 必须是 static,返回类型必须是目标类型 |
| 参数传递 | 用 <constructor-arg>,不是 <property> |
| 实例工厂 | 用 factory-bean + factory-method,不能再写 class |
| 常见错误 | beannotofrequiredtypeexception,容器中存放的是工厂而非产品 |
| 排查方法 | 检查 factory-method、返回类型、获取方式 |
| 正确获取 | getbean("starbean", star.class) 获取产品;getbean("&starbean") 获取工厂(仅 factorybean 场景) |
理解静态工厂、实例工厂和 factorybean 的区别,确保容器中存放的是工厂方法返回的产品,而不是工厂本身,就能避免这类错误。
以上就是spring通过factory-method实例化bean详解与常见错误排查的详细内容,更多关于spring factory-method实例化bean的资料请关注代码网其它相关文章!
发表评论