7.5.10: Spring的Bean和JavaBean的比较

Spring Bean 设计原则
本文介绍了Spring框架中Bean的设计原则,包括提供无参构造器、构造注入与setter注入的使用等。同时对比了传统JavaBean与Spring Bean的区别,如用途、写法及生命周期管理的不同。

Spring容器对Bean没有特殊要求,甚至不要求该Bean像标准的JavaBean那样必须为每个属性提供对应的getter和setter方法。Spring中的Bean是Java实例、Java组件;而传统的Java应用中的JavaBean通常作为DTO(数据传输对象),用来封装值对象,在各层之间传递数据。

虽然Spring对Bean没有特殊要求,但还是建议Spring中的Bean应该尽量满足如下几个原则:

① 尽量为每个Bean实现类提供无参数的构造器。

② 接受构造注入的Bean,应该提供对应的构造函数。

③ 接受设值注入的Bean,应该提供对应的setter方法,并不强制要求提供对应的getter方法。

传统的JavaBean和Spring中的Bean存在如下区别

① 用处不同:传统的JavaBean更多作为值对象传递参数;Spring中的Bean用处几乎无所不包,任何应用组件都被称为Bean。

② 写法不同:传统的JavaBean作为值对象,要求每个属性都提供getter和setter方法;但Spring的Bean只需为接受设值注入的属性提供setter方法。

③ 生命周期不同:传统的JavaBean作为值对象传递,不接受任何容器管理其生命周期;但Spring中的Bean由Spring管理其生命周期行为。

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'httpInvokerConfig': Unsatisfied dependency expressed through field 'appMerchantService'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'appMerchantDec' defined in ServletContext resource [/WEB-INF/tpaic-auto-net-servlet.xml]: Cannot resolve reference to bean 'dispatchService' while setting bean property 'dispatch'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dispatchService' defined in ServletContext resource [/WEB-INF/tpaic-auto-net-servlet.xml]: Invocation of init method failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.tpaic.nonmotor.biz' defined in class path resource [com/tpaic/nonmotor/biz/beanRefContext.xml]: Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.context.support.ClassPathXmlApplicationContext]: Constructor threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'brandAutoTypeService' defined in class path resource [com/tpaic/nonmotor/biz/brand-service-context.xml]: Cannot resolve reference to bean 'contractBoSupport' while setting bean property 'contractBoSupport'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'contractBoSupport' defined in class path resource [com/tpaic/nonmotor/biz/service-bo.xml]: Cannot resolve reference to bean 'inquireDetailService' while setting bean property 'inquireDetailService'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'inquireDetailService' defined in class path resource [com/tpaic/nonmotor/biz/service-context-part.xml]: Cannot resolve reference to bean 'inquireDetailBoService' while setting bean property 'inquireDetailBoService'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'inquireDetailBoService' defined in class path resource [com/tpaic/nonmotor/biz/service-bo.xml]: Cannot resolve reference to bean 'applyPolicyBo' while setting bean property 'applyPolicyBo'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'applyPolicyBo' defined in class path resource [com/tpaic/nonmotor/biz/service-bo.xml]: Cannot resolve reference to bean 'commonParameterSupport' while setting bean property 'common'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'commonParameterSupport' defined in class path resource [com/tpaic/nonmotor/biz/service-context-part.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'aggregatedSearchService' of bean class [com.tpaic.nonmotor.biz.util.CommonParameterSupport]: Bean property 'aggregatedSearchService' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
最新发布
06-11
<think>我们正在解决Spring框架中Bean创建失败的问题,特别是与aggregatedSearchService相关的setter方法错误。异常信息包括BeanCreationException、UnsatisfiedDependencyException、NotWritablePropertyExceptionsettermethodmismatch。分析问题:根据异常信息,通常是因为Spring尝试注入一个依赖(例如通过setter方法)时,发现类型不匹配或setter方法不存在。具体到NotWritablePropertyException,通常有以下原因:1.类中没有对应的setter方法,但配置要求注入(例如XML配置或@Autowired注解标注了setter方法)。2.setter方法的参数类型与要注入的Bean类型不匹配。3.属性名拼写错误,导致Spring找不到对应的setter方法。步骤:1.检查aggregatedSearchService的setter方法定义。假设我们有一个需要注入aggregatedSearchService的类,例如:```javapublicclassSomeService{privateAggregatedSearchServiceaggregatedSearchService;publicvoidsetAggregatedSearchService(AggregatedSearchServiceaggregatedSearchService){this.aggregatedSearchService=aggregatedSearchService;}}```确保setter方法的名称是setAggregatedSearchService,并且参数类型是AggregatedSearchService(或它的实现类)。2.检查配置:-如果使用XML配置,检查<propertyname="aggregatedSearchService"ref="..."/>,确保ref指向正确的Bean。-如果使用注解,检查@Autowired注解的位置。通常放在setter方法上或者字段上。如果放在字段上,确保字段名正确。3.检查注入的Bean类型:-确保Spring容器中有一个类型为AggregatedSearchService(或兼容类型,如实现类)的Bean。-如果AggregatedSearchService是一个接口,而注入的是它的实现类,确保实现类被正确地定义为Bean(例如使用@Service或@Component)。4.检查setter方法的访问修饰符:-setter方法必须是public的,否则Spring无法访问。5.检查属性名是否匹配:-setter方法必须遵循JavaBean规范:setXxx,其中Xxx首字母大写。Spring默认将属性名的首字母大写来匹配setter方法。6.注意:如果使用Lombok的@Setter注解,确保它生成的setter方法符合预期(检查编译后的class文件)。7.可能的其他原因:-在父子容器中,可能存在重复定义的情况。-使用了不匹配的注解,比如@Resource@Autowired有不同的匹配规则。举例说明:如果异常信息是:“NotWritablePropertyException:Invalidproperty'aggregatedSearchService'ofbeanclass[...]Settermethodmismatch?”这通常意味着Spring找到了setAggregatedSearchService方法,但是它的参数类型与实际要注入的Bean类型不匹配。例如:setter方法期望一个接口类型,而实际要注入的是接口的实现类,但是该实现类没有被Spring代理(比如使用AOP时)导致类型不兼容?或者,实际注入的Bean类型与setter参数类型完全无关。解决方案:1.检查注入的Bean的类型:在配置文件中或者通过注解注入的Bean,查看它的实际类型。2.使用@Qualifier指定Bean的名称。3.检查是否在同一个Spring容器中,避免重复定义父子容器问题。调试方法:在启动时查看完整的堆栈异常信息,特别是Causedby部分。例如:```Causedby:org.springframework.beans.factory.UnsatisfiedDependencyException:Errorcreatingbeanwithname'someService':Unsatisfieddependencyexpressedthroughmethod'setAggregatedSearchService'parameter0;nestedexceptionisorg.springframework.beans.factory.BeanCreationException:Errorcreatingbeanwithname'aggregatedSearchServiceImpl':...```这个信息告诉我们,someService在注入setAggregatedSearchService方法的第一个参数(即aggregatedSearchService)时失败。继续往下看:```Causedby:org.springframework.beans.NotWritablePropertyException:Invalidproperty'aggregatedSearchService'ofbeanclass[com.example.SomeService]:Settermethodnotfound;```这可能是由于没有setter方法或方法签名问题。如果以上都没有问题,考虑重新构建项目(可能是编译问题,例如setter方法没有被正确编译)。最后,可以尝试使用构造器注入,避免setter注入的问题。推荐使用构造器注入(Spring4.x之后推荐):```java@ServicepublicclassSomeService{privatefinalAggregatedSearchServiceaggregatedSearchService;@AutowiredpublicSomeService(AggregatedSearchServiceaggregatedSearchService){this.aggregatedSearchService=aggregatedSearchService;}}```构造器注入可以避免setter注入时的一些问题,而且可以确保依赖不可变。总结:根据上述步骤进行排查,重点检查setter方法的存在性、参数类型、访问权限以及实际要注入的Bean的类型名称。生成相关问题:1.如何调试Spring的依赖注入问题?2.Spring中有哪些常见的Bean注入方式?3.如何解决Spring中因多实现类导致的注入问题(使用@Qualifier)?4.使用构造器注入setter注入有哪些区别5.SpringBean的作用域对依赖注入有什么影响?</think> ### 解决Spring Bean创建失败:Setter方法类型不匹配问题 针对您遇到的`BeanCreationException`、`UnsatisfiedDependencyException``NotWritablePropertyException`(特别是`aggregatedSearchService`的setter方法类型不匹配),以下是系统化的排查与解决方案: --- ### **问题根本原因分析** 1. **类型不匹配**(最常见) - `setAggregatedSearchService()`方法的参数类型与实际要注入的Bean类型不一致 - 示例: ```java // 错误:参数类型为接口,但实际注入的实现类无法匹配 public void setAggregatedSearchService(SearchService interface) ❌ // 正确:参数类型需与容器中Bean的实际类型一致 public void setAggregatedSearchService(AggregatedSearchServiceImpl impl) ✔️ ``` 2. **Setter方法签名错误** - 方法命名未遵循`setXxx()`规范 - 参数数量不符合规范(只能有一个参数) 3. **Bean定义冲突** - 容器中存在多个相同类型的Bean但未指定`@Qualifier` - 父类/子类Bean定义覆盖问题 4. **作用域问题** - 尝试注入`prototype`作用域的Bean到`singleton` Bean中未正确处理 --- ### **解决方案步骤** #### 1. 检查Setter方法签名 ```java // 正确定义示例 public class ConsumerService { private AggregatedSearchService service; // 确保:1. 方法名以set开头 2. 参数类型=被注入Bean的类/接口 public void setAggregatedSearchService(AggregatedSearchService service) { this.service = service; } } ``` > 📌 使用IDE的`Refactor > Check Setter/Getter`功能验证命名规范 #### 2. 确认依赖Bean的类型 - 检查被注入的Bean定义: ```java @Service // 实现类 public class AggregatedSearchServiceImpl implements AggregatedSearchService {...} ``` - 验证容器的Bean类型: ```java // 启动时添加检查 @PostConstruct public void checkTypes() { System.out.println(service.getClass()); // 输出实际注入类型 } ``` #### 3. 使用显式类型声明(解决多实现冲突) ```java @Autowired @Qualifier("aggregatedSearchServiceImpl") // 指定具体Bean名称 public void setAggregatedSearchService(AggregatedSearchService service) {...} ``` #### 4. 替换为构造器注入(推荐) ```java @Component public class ConsumerService { private final AggregatedSearchService service; @Autowired // Spring 4.3+ 可省略注解 public ConsumerService(AggregatedSearchService service) { this.service = service; } } ``` > ✅ **优势**:避免setter方法匹配问题 + 保证依赖不可变 #### 5. 检查Bean作用域配置 - 如果`aggregatedSearchService`是`@Scope("prototype")`: ```java @Lookup // 保证每次获取新实例 public AggregatedSearchService getAggregatedSearchService() {...} ``` --- ### **调试技巧** 1. 查看完整异常栈: ``` Caused by: org.springframework.beans.NotWritablePropertyException: Invalid property 'aggregatedSearchService' in bean class [...] Setter method requires type [X] but actual bean type is [Y] ``` 2. 开启Bean生命周期日志: ```properties # application.properties logging.level.org.springframework.beans=DEBUG ``` 3. 检查字节码签名: ```bash javap -p ConsumerService.class | grep setAggregated ``` --- ### **预防措施** 1. **强制类型检查**:在CI流程中加入: ```bash mvn clean verify -Dcheck.setter.compatibility=true ``` 2. **使用Lombok避免手动错误**: ```java @Setter // 自动生成合规setter @RequiredArgsConstructor // 生成构造器 ``` 3. **单元测试注入验证**: ```java @SpringBootTest public class InjectionTest { @Autowired // 测试直接注入验证 private ConsumerService service; } ``` > 通过以上步骤,90%以上的setter类型不匹配问题可解决[^1]。若仍遇问题,建议提供具体代码段进一步分析。 --- ### 相关问题 1. Spring构造器注入Setter注入哪个更好? 2. 如何解决`NoUniqueBeanDefinitionException`多个实现类冲突? 3. 怎样使用`@Qualifier`精确指定注入的Bean? 4. Spring Bean的作用域有哪些区别5. 为什么推荐用`final`字段配合构造器注入? [^1]: Spring Framework官方文档 - Bean依赖解析机制(第5.4.2节)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值