Spring factory-method踩坑实录,Bean类型异常一次讲透

文章目录


P.S. 目前国内还是很缺AI人才的,希望更多人能真正加入到AI行业,共同促进行业进步,增强我国的AI竞争力。想要系统学习AI知识的朋友可以看看我精心打磨的教程 传送门http://blog.csdn.net/jiangjunshow,教程通俗易懂,高中生都能看懂,还有各种段子风趣幽默,从深度学习基础原理到各领域实战应用都有讲解,我22年的AI积累全在里面了。注意,教程仅限真正想入门AI的朋友,否则看看零散的博文就够了。

前言

先别急,今天要聊的事特别简单:Spring 怎么通过 factory-method 造 Bean。对,就是字面意义上的"造星星",不是让你当造物主,是让 Spring 当。这坑我踩过,你大概率也踩过------不然你也不会点进来,对吧?

一、先看这行配置:一行 XML 引发的"血案"

配置长这样:

xml 复制代码
<bean id="starBean" class="com.xie.spring.StarFactory" factory-method="get" />

翻译成人话:Spring 拿到这行配置,会找到 com.xie.spring.StarFactory 这个类,敲敲门喊一嗓子:"老哥,把 get() 的返回值给我。"

然后,get() 返回啥,Spring 就把啥当成 starBean 塞进容器。

注意,重点来了:容器里 starBean 是啥类型,取决于 get() 返回啥,跟 StarFactory 这个类本身没有半毛钱关系。

这就好比你去食堂打饭,跟师傅说"来份番茄炒蛋",师傅给你打的是番茄炒蛋,而不是"师傅"本人。你要是想打一份食堂阿姨,那得换窗口,别在一棵树上吊死。

简单总结:Spring 自己不生产星星,它只是星星的搬运工。

二、想让这套跑起来,得满足仨条件

1. get() 必须是 static,这是硬性规定

java 复制代码
public class StarFactory {
    public static Star get() {
        Star star = new Star();
        star.setName("太阳");
        return star;
    }
}

看到 static 没?没它,Spring 当场甩脸子。

为啥?因为 Spring 压根没实例化 StarFactory,它连工厂的门都没进,就想隔空调用方法。让一个还没出生的对象去干活,这不光违反物理学,还违反 Spring 的脾气。我当年第一次忘了写 static,一个报错糊脸上,一度怀疑是自己 Java 没学明白。

2. get() 的返回类型,必须和你 getBean 时想要的类型对得上

java 复制代码
Star star = context.getBean("starBean", Star.class);

你声明要 Starget() 也老老实实返回 Star,大家相安无事。

但凡 get() 叛逆一点,返回个 StarFactory,Spring 当场给你表演一个 BeanNotOfRequiredTypeException

那感觉就像你点了一杯奶茶,店员端上来一杯茶叶渣泡水,还安慰你:"都是茶,凑合喝吧。"凑合?我凑合你个大头鬼。

3. get() 要带参数,记住用 <constructor-arg>,别用 <property>

xml 复制代码
<bean id="starBean" class="com.xie.spring.StarFactory" factory-method="get">
    <constructor-arg name="name" value="太阳" />
</bean>

这里有个坑中坑:标签名虽然叫 constructor-arg(构造函数参数),实际传的是工厂方法的参数,跟构造方法一毛钱关系都没有。

名字像构造参数,干的却是传参的活,属于典型的"名字诈骗"。你要是在这写 <property>,Spring 会用沉默让你知道什么叫"无视你的配置"。

三、静态工厂 vs 实例工厂,别把俩兄弟搞混

刚才说了,get() 必须是静态的。那万一你手一抖,static 没写呢?

那就得换剧本:让 Spring 先把工厂实例化出来,再通过实例去调方法:

xml 复制代码
<!-- 先定义工厂 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),又是一个响亮的类型不匹配。

我愿称之为"买椟还珠"的 Spring 版:你要的是珍珠(Star),他给你个盒子(StarFactory),还觉得自己挺周到。

对比维度 静态工厂方法 实例工厂方法
工厂方法类型 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'

翻译一下:你要 Star,容器里躺着 StarFactory。

容器的内心 OS:"你要的我没有,我有的你不要,要不咱俩都冷静冷静?"说真的,这报错信息长得像法院传票,我当年盯着看了半天才看懂:哦,原来你不是我要的那个人。

这错一般咋来的?常见四种情况:

1. 忘记写 factory-method

xml 复制代码
<bean id="starBean" class="com.xie.spring.StarFactory" />

Spring 一看:哦,没让我调方法,那我直接把 StarFactory 实例化了吧。你想要的星星没了,容器里多了个工厂。这锅怪谁?怪你自己忘了传话。

2. get() 返回了工厂自己

java 复制代码
public static StarFactory get() {
    return new StarFactory(); // 返回的是工厂,不是产品
}

这就好比你去蛋糕店买蛋糕,店员把整个后厨(烤箱、面粉、围裙)打包给你了。是挺值,但不是你要的东西啊。

3. 实例工厂配错了

xml 复制代码
<bean id="starBean" class="com.xie.spring.StarFactory" />

该写 factory-bean 引用工厂,结果写成了 class,Spring 直接给你实例化一个裸工厂。经典"抄错作业"现场。

4. 用了 FactoryBean,还搞错获取姿势

如果 StarFactory 实现了 FactoryBean<Star>

  • getBean("starBean") → 返回 Star(产品)
  • getBean("&starBean") → 返回 StarFactory(工厂本身)

& 一写错,C 语言老玩家直接狂喜:这不是取地址符吗?没错,& 就是让你"取工厂的地址",把藏在后面的工厂本体捞出来。这俩要是写反了,类型不匹配就是你的宿命。

五、来一套标准操作,照着抄就行

Java 类:

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 复制代码
<?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>

测试代码:

java 复制代码
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='太阳'}
    }
}

输出 Star{name='太阳'},完美。这颗星星,终于被正儿八经地从工厂里"生产"出来了。

顺便说一句,太阳是星星吗?天文学家说了,太阳就是一颗恒星。程序员表示:叫 Star 就行,别抬杠,能跑就行。

六、再报错?按这个顺序查,别乱开枪

  1. 打开 XML 配置文件,定位 id="starBean" 那行。
  2. 看有没有 factory-method,没有?补上。
  3. 静态工厂,看 class 是不是指向工厂类。
  4. 实例工厂,看是不是 factory-bean + factory-method,同时确认没写 class
  5. 用了 FactoryBean,看是不是用 &amp;starBean 取工厂本体。
  6. 确认 get() 返回类型是 Star,不是 StarFactory
  7. 实在不行,先不指定类型,把 Bean 捞出来打印真实类型:
java 复制代码
Object bean = context.getBean("starBean");
System.out.println(bean.getClass().getName());

输出 com.xie.spring.Star,恭喜,配置正确。输出 com.xie.spring.StarFactory,说明你的工厂方法把工厂自己"打包出售"了,回去改 get() 吧。

七、最后总结一张表,面试前突击用

维度 核心要点
配置含义 调用静态工厂方法 get(),用返回值当 Bean
前提条件 get() 得是 static,返回类型得是目标类型
参数传递 <constructor-arg>,不是 <property>
实例工厂 factory-bean + factory-method,不能再写 class
常见错误 BeanNotOfRequiredTypeException,容器里躺着工厂不是产品
排查方法 检查 factory-method、返回类型、获取姿势
正确获取 getBean("starBean", Star.class) 拿产品;getBean("&amp;starBean") 拿工厂

说白了,静态工厂、实例工厂、FactoryBean 这三兄弟,你就记住一句话:**Spring 要的是产品,不是生产产品的那个车间。**只要容器里躺的是你 get() 造出来的星星,而不是 StarFactory 本体,这个报错就跟你彻底说再见了。

P.S. 目前国内还是很缺AI人才的,希望更多人能真正加入到AI行业,共同促进行业进步,增强我国的AI竞争力。想要系统学习AI知识的朋友可以看看我精心打磨的教程 传送门http://blog.csdn.net/jiangjunshow,教程通俗易懂,高中生都能看懂,还有各种段子风趣幽默,从深度学习基础原理到各领域实战应用都有讲解,我22年的AI积累全在里面了。注意,教程仅限真正想入门AI的朋友,否则看看零散的博文就够了。

相关推荐
米小虾1 小时前
多智能体还在"说话":C2C 把 KV-Cache 直接传给另一个模型,2.5× 加速背后的五个死结
人工智能·agent
AI职业加油站1 小时前
数据要素价值释放年:大数据治理工程师,站上职业新风口
人工智能·学习·职场和发展·数据分析·职场发展
小眼睛和小僵尸1 小时前
【全宇宙恒等系统云端部署和跑起来】
人工智能·全球发展·全宇宙发展
倍利福猎头公司官方账号1 小时前
2026具身智能赛道还火热吗?机器人人选该如何思考下半年的工作机会?
人工智能·面试·职场和发展·机器人·求职招聘
Dawson Zhu1 小时前
大模型记忆系统设计:分层架构与关键技术解析
人工智能·语言模型·架构·aigc·agi
嘻嘻的AI日记1 小时前
智能知识库系统,重构智能知识库的可信底色
人工智能
天远API1 小时前
零信任架构实战:基于天远车信盟出险构建自动化车险评估网关
人工智能·ai·工具分享
打工仔折腾 AI1 小时前
用 Docker 部署 Excalidraw 手绘白板并配置固定公网访问的完整实践
人工智能·后端·python
宝贝儿好1 小时前
【LLM】第六章:LangChain框架中的大模型的创建与调用
人工智能·自然语言处理·nlp·aigc·ai编程