美文网首页Java 核心技术
Spring Boot常用注解(二) - 注入Bean的注解

Spring Boot常用注解(二) - 注入Bean的注解

作者: cbw100 | 来源:发表于2020-02-11 14:37 被阅读0次

    1. 概述

    Spring Boot常用注解(一) - 声明Bean的注解 中学习了Spring Boot中声明Bean的注解
    那Spring容器中的Bean是怎么实现自动装配(依赖)的呢?
    这就是接下来学习的注入注解咯

    注入Bean的注解:

    • @Autowired
    • @Inject
    • @Resource

    2. @Autowired注解

    @Autowired注解源码:

    package org.springframework.beans.factory.annotation;
    
    /**
     1. @since 2.5
     2. @see AutowiredAnnotationBeanPostProcessor
     3. @see Qualifier
     4. @see Value
     */
    @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Autowired {
    
        boolean required() default true;
    }
    
    1. @Autowired注解作用在构造函数、方法、方法参数、类字段以及注解上
    2. @Autowired注解可以实现Bean的自动注入

    2.1 @Autowired注解原理

    在Spring Boot应用启动时,Spring容器会自动装载一个org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor处理器,当容器扫扫描到@Autowired注解时,就会在IoC容器就会找相应类型的Bean,并且实现注入。

    2.2 @Autowired注解使用

    在Web MVC中控制层(Controller)访问的是业务层(Service),而业务层(Service)访问的是数据层(Dao),使用@Autowired注解实现注入

    数据层:

    package com.example.demo.chapter1.useannotation.autowired.dao;
    
    /**
     * 数据层接口,用于访问数据库,返回数据给业务层
     * */
    public interface IDao {
        public String get();
    }
    
    /**
     * 数据层接口实现类
     * 
     * 1.数据层Bean用@Repository标注
     * 2.当前Bean的名称是"autowiredUserDaoImpl"
     * 3.设置当前Bean的为原型模式,即每次获取Bean时都创建一个新实例
     * */
    @Repository("autowiredUserDaoImpl")
    @Scope("prototype")
    public class UserDaoImpl implements IDao {
    
        public String get() {
            return "@Autowired注解实现自动装配";
        }
    }
    

    业务层:

    package com.example.demo.chapter1.useannotation.autowired.service;
    
    /**
     * 业务层接口
     * 从数据层获取数据,处理结果返回给控制层
     * */
    public interface IService {
        public String get();
    }
    
    /**
     * 业务层接口实现
     * 
     * 1.数据层Bean用@Service标注
     * 2.当前Bean的名称是"autowiredUserServiceImpl"
     * 3.设置当前Bean的为原型模式,即每次获取Bean时都创建一个新实例
     * 4.业务层有一个数据层接口IDao,使用@Autowired注解标注
     * */
    
    @Service("autowiredUserServiceImpl")
    @Scope("prototype")
    public class UserServiceImpl implements IService {
        /**
         * @Autowired实现自动装配
         * Spring IoC容器扫描到@Autowired注解会去查询IDao的实现类,并自动注入
         * */
        @Autowired
        private IDao dao;
    
        @Override
        public String get() {
            return dao.get();
        }
    }
    
    1. Bean通过注解@Service声明为一个Spring容器管理的Bean,Spring容器会扫描classpath路径下的所有类,找到带有@Service注解的UserServiceImpl类,并根据Spring注解对其进行初始化和增强,命名为autowiredUserServiceImpl
    2. Spring容器如果发现此类属性dao也有注解@Autowired,则会从Spring容器中查找一个已经初始化好的IDao的实现类,如果没有找到,则先初始化一个IDao实现类

    控制层:

    package com.example.demo.chapter1.useannotation.autowired.controller;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import com.example.demo.chapter1.useannotation.autowired.service.IService;
    
    /**
     1. 控制层
     2. 
     3. 1.控制层使用@RestController注解标注,返回json格式的字符串
     4. 2.获取业务层返回的数据,输出到客户端
     5. 3.请求:http:localhost:8080/autowiredController
     6. */
    @RestController
    public class AutowiredController {
        @Autowired
        private IService service;
    
        @RequestMapping("/autowiredController")
        public String get () {
            return service.get();
        }
    }
    

    测试结果:

    1. 启动Spring Boot应用
    2. 浏览器输入:http:localhost:8080/autowiredController
    3. 返回结果:


      2019102606.png

    2.3 @Qualifier注解

    @Qualifier注解源码:

    package org.springframework.beans.factory.annotation;
    
    /**
     * @since 2.5
     * @see Autowired
     */
    @Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @Documented
    public @interface Qualifier {
    
        String value() default "";
    
    }
    
    1. 如果Spring 容器中有两个数据层接口IDao的实现类
    2. 而业务层通过@Autowired注解标注的是IDao接口
    3. 这时就需要@Qualifier注解来指定需要自动装配的Bean的名称
    4. 否则会报如下的错:
    Description:
    
    Field dao in com.example.demo.chapter1.useannotation.autowired.service.UserServiceImpl required a single bean, but 2 were found:
        - autowiredAdminDaoImpl: defined in file [D:\eclipse\workspace\boot\demo\target\classes\com\example\demo\chapter1\useannotation\autowired\dao\AdminDaoImpl.class]
        - autowiredUserDaoImpl: defined in file [D:\eclipse\workspace\boot\demo\target\classes\com\example\demo\chapter1\useannotation\autowired\dao\UserDaoImpl.class]
    
    
    Action:
    
    Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
    

    2.4 @Qualifier注解使用

    数据层接口IDao:

    public interface IDao {
        public String get();
    }
    

    IDao实现类 - UserDaoImpl

    @Repository("autowiredUserDaoImpl")
    @Scope("prototype")
    public class UserDaoImpl implements IDao {
    
        public String get() {
            return "@Autowired注解实现自动装配 - UserDaoImpl";
        }
    }
    

    IDao实现类 - AdminDaoImpl

    @Repository("autowiredAdminDaoImpl")
    @Scope("prorotype")
    public class AdminDaoImpl implements IDao {
    
        @Override
        public String get() {
            return "@Autowired注解实现自动装配 - AdminDaoImpl";
        }
    }
    

    @Qualifier注解使用:

    @Service("autowiredUserServiceImpl")
    @Scope("prototype")
    public class UserServiceImpl implements IService {
        /**
         * @Autowired实现自动装配
         * Spring IoC容器扫描到@Autowired注解会去查询IDao的实现类,并自动注入
         * */
        @Autowired
        @Qualifier("autowiredUserDaoImpl")
        private IDao dao;
    
        @Override
        public String get() {
            return dao.get();
        }
    }
    

    测试结果:


    2019102607.png

    2.5 @Autowired注解的requird属性

    在使用@Autowired注解时,首先在容器中查询对应类型的bean

    1. 如果查询结果Bean刚好为一个,自动注入
    2. 如果查询结果Bean不止一个,通过@Qualifier注解指定自动装配Bean的名称
    3. 如果没有查询到对应类型的Bean,由于默认@Autowired(required=true),会抛出异常,解决方法是使用@Autoiwired(quired=false)
    4. @Autowired(quired=true)意味着依赖是必须的
    5. @Autowired(quired=false)等于告诉 Spring:在找不到匹配 Bean 时也不报错

    数据层接口:

    package com.example.demo.chapter1.useannotation.autowired.dao;
    
    /**
     * 数据层接口
     * */
    public interface ITask {
        public String get();
    }
    

    业务层接口:

    package com.example.demo.chapter1.useannotation.autowired.service;
    
    @Service("taskServiceImpl")
    @Scope("prototype")
    public class TaskServiceImpl implements IService {
    
        @Autowired
        private ITask task;
    
        @Override
        public String get() {
            return task.get();
        }
    }
    

    如果没有接口ITask的实现类,启动Spring Boot应用会报如下错:
    没有找到ITask的实现类

    Description:
    
    Field task in com.example.demo.chapter1.useannotation.autowired.service.TaskServiceImpl required a bean of type 'com.example.demo.chapter1.useannotation.autowired.dao.ITask' that could not be found.
    
    
    Action:
    
    Consider defining a bean of type 'com.example.demo.chapter1.useannotation.autowired.dao.ITask' in your configuration.
    

    解决方法 - 添加required=false

    @Service("autowiredTaskServiceImpl")
    @Scope("prototype")
    public class TaskServiceImpl implements IService {
    
        /**
         * 接口ITask没有实现类
         * 添加required=false不报错
         * */
        @Autowired(required=false)
        private ITask task;
    
        @Override
        public String get() {
            return task.get();
        }
    }
    

    >推荐一下我的公众号: 【geekjc】,一起学习交流编程知识,分享经验,各种有趣的事,更多精彩内容,扫码进入小程序。

    tuiguang.png

    相关文章

      网友评论

        本文标题:Spring Boot常用注解(二) - 注入Bean的注解

        本文链接:https://www.haomeiwen.com/subject/csrxfhtx.html