【Spring】@Autowired 和 @Resource 注解区别 & @Configuration 和 @Bean 的作用

报错:

启动项目,发现有一个报错:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.data.redis.core.RedisTemplate<java.lang.String, java.lang.Object>' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

发现过程:

Service服务中,该Bean被这样使用,

@Service
public class AServiceImpl implements AService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

}

应用1 和 应用2 都引用了 Service服务。

应用1可以启动成功,应用2启动就报如上错误。

为什么呢?

初步改动:

将上述的@Autowired 修改为@Resource  应用2启动即成功了。

@Service
public class AServiceImpl implements AService {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

}

提出问题:

问题1:@Autowired 和 @Resource 注解有什么区别?


问题2:使用@Autowired 为什么可以启动成功?

问题解答:

问题1:

  @Autowired  和  @Resource 注解有什么区别?

解答:

  

(1)@Resource和@Autowired注解都是用来实现依赖注入的。@Autowired只按照byType 注入;@Resource默认按byName自动注入,也提供按照byType 注入;
(2)@Autowired按类型装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它required属性为false。 【这一点很重要,即上面报错的原因】
    @Resource有两个中重要的属性:name和type。name属性指定byName,如果没有指定name属性,当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象,当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找依赖对象。需要注意的是,@Resource如果没有指定name属性,并且按照默认的名称仍然找不到依赖对象时, @Resource注解会回退到按类型装配。但一旦指定了name属性,就只能按名称装配了。

(3)那如果既想使用@Autowired,又想通过byName注入,可以搭配结合@Qualifier注解一起使用。【不仅这种情况,例如多个ServiceBean类型时候,定义的一个serviceBean1  一个是ServiceBean2,同种Type时候,也可以结合@Qualifier完成byName的注入】

(4)@Resource装配顺序
    1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常  
    2. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常  
    3. 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常  
    4. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;
    【这里注意,既没有指定name,又没有指定type,最终能匹配到则完成自动装配,如果最终name和type都没匹配到,就会出现使用@Resource注入一个Bean是null的情况】
    【这种情况下,@Resource和@Autowired(required = false)  就是一样的效果,也就是最开始的问题问什么使用 @Resource启动就成功了的原因】

问题2:

  使用@Autowired 为什么可以启动成功?

解答:

Service模块使用的地方

@Service
public class AServiceImpl implements AService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

}

应用1引用了Service模块,应用1使用@Autowired可以启动的原因是因为,应用1中对该Bean做了注入操作

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * redis 配置类
 */
@Configuration
public class RedisConfiguration {
    
    
    @Bean
    public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        return redisTemplate;
    }

}

这里就要说到 @Configuration  和 @Bean  的作用了

(1)@Configuration与@Bean结合使用。
(2)@Configuration可理解为用spring的时候xml里面的<beans>标签,@Bean可理解为用spring的时候xml里面的<bean>标签。
(3)Spring Boot不是spring的加强版,所以@Configuration和@Bean同样可以用在普通的spring项目中,而不是Spring Boot特有的,只是在spring用的时候,注意加上扫包配置。
(4)Bean注解的作用之一就是能够管理第三方jar包内的类到容器中。如上,我们将RedisTemplate通过使用@Bean的方式,把这个类交到Spring容器进行管理。
(5)在@Configuration中被@Bean标记的方法,会被Spring进行CGLIB代理,从而进行增强。
(6)原理参考:https://blog.csdn.net/sundacheng1989/article/details/92783515

总结:

所以,

之所以应用1使用@Autowired启动没问题,根本原因就是 应用1中对该Bean做了注入操作,已经将该Bean注入到Spring容器中进行管理,而@Autowired默认required=true,所以启动没问题。
应用2使用@Autowired启动会报错,因为没有对该Bean做注入操作,也没有设置@Autowired的required=false,所以启动失败了,而使用@Resource虽然启动成功了,但如果真正使用到该Bean,也是NULL的,也是有问题的。


所以应用2也需要对该Bean做注入操作。

===================================================================================================

原文地址:https://www.cnblogs.com/sxdcgaq8080/p/14657519.html