zoukankan      html  css  js  c++  java
  • 【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做注入操作。

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

  • 相关阅读:
    分享一些曾经设计的ASP.NET自定义服务端控件(附源程序下载)
    使用SuperSocket实现TLV自定义协议网络通信的Demo
    让Silverlight支持GB2312中文编码
    在Sqlite中通过Replace来实现插入和更新
    在VS2010项目中引用Lib静态库(以Openssl为例)
    金融系统中PBOC/EMV的TLV的算法实现(含C++/C#)
    在Windows下C++实现UNIX中的GZ格式的解压缩(附工具)
    Opensuse网络配置备忘
    项目管理理论与实践系列文章索引
    让Windows远程访问Opensuse桌面的解决办法
  • 原文地址:https://www.cnblogs.com/sxdcgaq8080/p/14657519.html
Copyright © 2011-2022 走看看