包阅导读总结
1. `Spring Bean`、`注入不生效`、`@Resource`、`@Autowired`、`配置类`
2. 本文主要探讨了在项目开发中遇到的 bean 注入不生效问题,对比了@Resource 和@Autowired 注解的区别,介绍了多种配置 bean 的方式及可能出现的问题,并给出了相应的解决建议。
3.
– 项目开发中出现 bean 注入不生效问题,A 应用正常,B 应用异常。
– 最初通过 Java 配置类配置 tair 的 bean,A 应用没问题,B 应用查不出数据。
– 尝试修改配置,如写死 username 值,问题未解决。
– 将 Java 配置改为 XML 配置,问题解决。
– 对比@Resource 和@Autowired 注解
– @Autowired 按类型自动装配,可结合@Qualifier 按名称装配。
– @Resource 按名称装配,不支持 required 属性。
– 给出解决建议
– 使用配置类配置 bean 时,@Bean 方法参数或@Autowired 配置 bean 最好用@Qualifier 指定注入的 bean。
– 使用 XML 配置时,通过 ref 元素按 bean 的 id 引用和注入。
思维导图:
文章地址:https://mp.weixin.qq.com/s/rWorrPuxZaneGsjoGMe-Pw
文章来源:mp.weixin.qq.com
作者:遇舟
发布时间:2024/7/24 11:01
语言:中文
总字数:3795字
预计阅读时间:16分钟
评分:88分
标签:Spring Boot,Spring Bean配置,依赖注入,JavaConfig,XML配置
以下为原文内容
本内容来源于用户推荐转载,旨在分享知识与观点,如有侵权请联系删除 联系邮箱 media@ilingban.com
@Resource和@Autowired
行为和特性:
-
按类型装配:默认情况下,@Autowired按类型自动装配Bean。
-
可选依赖:如果你的依赖是可选的,可以使用required=false设置:
-
构造器、方法或字段:可以用在构造器,属性字段或Setter方法上。
-
结合@Qualifier:可以和@Qualifier结合使用以实现按名称装配。
-
作为Spring特有的注解,它更深度地集成在Spring的生态系统中,更适合与其他Spring注解一起使用。
-
按名称装配:默认情况下,@Resource按名称装配。如果没有匹配到名称,再按类型装配。
-
不支持required属性:与@Autowired不同,@Resource不支持required属性。
-
可以用于字段和Setter方法:虽然也可以用于构造器,但不常见。通常用在字段或Setter方法上。
-
由于是Java EE规范的一部分,它可以与其他Java EE注解(如@PostConstruct和@PreDestroy)更好地配合使用。
-
@Component:标注一个类为Spring管理的组件。类似的注解还有:
-
@Service:表示服务层组件。
-
@Repository:表示DAO(数据访问层)组件。
-
@Controller:表示Spring MVC控制器组件。
-
@Primary:当一个类型有多个Bean时,在不使用@Qualifier的情况下,Spring会优先选择标注了@Primary的Bean。
-
@Scope:用于指定Bean的作用域,如singleton、prototype。
@Configuration
@Slf4j(topic = "config")
public class XxxTairConfig {
@Value("${spring.tmg.xxx.tair.username:默认值}")
private String username;
@Value("${spring.tmg.xxx.tair.namespace:默认值}")
private Integer namespace;
@Bean(initMethod = "init")
public TairManager tmgXxxTairManager() {
MultiClusterTairManager tairManager = new MultiClusterTairManager();
tairManager.setUserName(username);
tairManager.setDynamicConfig(true);
return tairManager;
}
@Bean
public TairAccessor tmgXxxTairAccessor(@Qualifier("tmgXxxTairManager") TairManager tmgXXXTairManager)
{
TairAccessorImpl tairAccessor = new TairAccessorImpl();
tairAccessor.setTairManager(tmgXxxTairManager);
tairAccessor.setNamespace(namespace);
return tairAccessor;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="tmgXxxTairManager" class="com.taobao.tair.impl.mc.MultiClusterTairManager" init-method="init">
<property name="userName">
<value>tair用户名参数</value>
</property>
<property name="timeout">
<value>50</value>
</property>
</bean>
<bean id="tmgXxxTairAccessor" class="com.alibaba.tmallg.gcommon.tair.TairAccessorImpl">
<property name="tairManager" ref="tmgXxxTairManager"/>
<property name="namespace" value="tair namespace参数"/>
</bean>
</beans>
@Configuration
@Slf4j(topic = "config")
public class XxxTairConfig {
@Value("${spring.tmg.xxx.tair.username:默认值}")
private String username;
@Value("${spring.tmg.xxx.tair.namespace:默认值}")
private Integer namespace;
@Bean(initMethod = "init")
public TairManager tmgXxxTairManager() {
MultiClusterTairManager tairManager = new MultiClusterTairManager();
tairManager.setUserName(username);
tairManager.setDynamicConfig(true);
return tairManager;
}
@Bean
public TairAccessor tmgXxxTairAccessor(TairManager tmgXxxTairManager)
{
TairAccessorImpl tairAccessor = new TairAccessorImpl();
tairAccessor.setTairManager(tmgXxxTairManager);
tairAccessor.setNamespace(namespace);
return tairAccessor;
}
}
在应用A中,该配置没有问题,tair也可以正常查询。
但是部署到应用B后,奇怪的问题出现了:同样的key,应用A可以查到,tair控制台也可以查到,但是应用B死活查不出来。
难道是因为username的@Value默认值没生效?因为debug可以看到namespace属性,符合预期,但是username属性看不到,我最早怀疑是username没配置成功。但namespace是生效的,理论上不应该部分不生效呀?抱着试试看的态度,遂尝试将username直接写死成目标值。重新部署后,依然不行,看来不是@Value的锅。
中间我尝试将java配置bean的方式,改成用xml配置,这样是生效的,可以解决问题。
但是为什么java配置bean的方式不生效呢?
还原后,继续debug,感觉依旧有些摸不着头脑。后来请团队同学帮忙看了下,一开始也觉得奇怪,tair各个单元都是有数据的,和单元化也没关系,后来点开tairManager属性值看到mdbcomm,问了句,我们的tair用的是mdb吗?最后打开控制台一看,是ldb……
明确指定名称:
按字段或属性名称匹配:
按类型匹配:
按类型匹配:
-
Spring 首先通过类型匹配找到所有符合要求的候选 Bean。如果只有一个候选 Bean,那么该 Bean 会被注入。
按名称匹配结合@Qualifier:
使用@Primary:
-
如果仍存在多个符合要求的 Bean,并且其中一个 Bean 标记了@Primary,Spring 会优先选择标记了@Primary 的 Bean 进行注入。
按名称匹配字段或属性名称:
NoUniqueBeanDefinitionException:
@Bean
public TairAccessor tmgXxxTairAccessor(TairManager tmgXxxTairManager) {
TairAccessorImpl tairAccessor = new TairAccessorImpl();
tairAccessor.setTairManager(tmgXxxTairManager);
tairAccessor.setNamespace(namespace);
return tairAccessor;
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="tmgXxxTairManager" class="com.taobao.tair.impl.mc.MultiClusterTairManager" init-method="init">
<property name="userName">
<value>tair用户名参数</value>
</property>
<property name="timeout">
<value>50</value>
</property>
</bean>
<bean id="tmgXxxTairAccessor" class="com.alibaba.tmallg.gcommon.tair.TairAccessorImpl">
<property name="tairManager" ref="tmgXxxTairManager"/>
<property name="namespace" value="tair namespace参数"/>
</bean>
</beans>
通过@Qualifier指定bean,避免受@Primary等因素的影响。
@Configuration
@Slf4j(topic = "config")
public class XxxTairConfig {
@Value("${spring.tmg.xxx.tair.username:默认值}")
private String username;
@Value("${spring.tmg.xxx.tair.namespace:默认值}")
private Integer namespace;
@Bean(initMethod = "init")
public TairManager tmgXxxTairManager() {
MultiClusterTairManager tairManager = new MultiClusterTairManager();
tairManager.setUserName(username);
tairManager.setDynamicConfig(true);
return tairManager;
}
@Bean
public TairAccessor tmgXxxTairAccessor(@Qualifier("tmgXxxTairManager") TairManager tmgXxxTairManager) {
TairAccessorImpl tairAccessor = new TairAccessorImpl();
tairAccessor.setTairManager(tmgXxxTairManager);
tairAccessor.setNamespace(namespace);
return tairAccessor;
}
}