02、SpringBoot 注解、Bean的注册与获取、依赖添加、命名规范

  • 注解

    • 概念
      • 注释是用来干嘛的?或者说写给谁看的?当然是程序员啦,不然那堆屎山代码谁看得懂啊,哈哈
      • 注解其实也类似,只不过是写给程序“看”的,程序“看”了就知道,哦,你要这样做呀
    • 注意
      • 注解仅仅只是修饰作用,与业务逻辑无关
        • 程序运行的时候扫描到注解,根据不同的注解自动完成一些工作
      • 注解不是程序本身,但是可以对程序作出解释
      • 应用程序中的类、方法、变量、参数、包等程序元素都可以被注解
    • 应用
      • 编译时进行格式检查
      • 减少配置
      • 减少重复性工作
  • SpringBoot的常用注解及其标注位置

    • 常用注解太多了,用到了慢慢说
    • 标注位置
      • 一般来说,我们除了方法的形参标注在左边外,其他地方都喜欢标注在上方
    • @SpringBootApplication
      • 作用
        • 用于标注SpringBoot项目的启动类的
      • 概念
        • 这是一个组合注解,由多个强大的注解整合而成
        • @SpringBootConfiguration
          • 让项目基于Java注解的配置方式,而不是传统的XML文件配置(当然,如果你写了,SpringBoot也是可以识别的)
        • @EnableAutoConfiguration
          • 开启自动配置,这样SpringBoot在启动的时候就可以自动加载所有配置文件和配置类了
        • @ComponentScan
          • 启动注解扫描器,这样项目才能自动发现并创建各个组件的Bean
      • 注意
        • @SpringBootApplication有一个使用要求:智能扫描底层包及其子包中的代码。底层包就是启动类所在的包
  • Bean的注册和获取

    • Bean的概念

      • Bean指的是由SpringBoot容器管理的对象
      • Bean是根据SpringBoot配置文件中的数据信息予以创建的
    • 查看项目中的Bean

      • 打开控制台,点击Actuator选项卡,就可以看见了(还是有很多的)
    • Bean的注册

      • 概念

        • Spring容器想要获取Bean对象,肯定需要你对该对象的类进行一个“标记”,显然,注解就是很好的选择
      • @Componet

        • 将类注册为组件
        • 卧槽,什么是“组件”啊?不着急理解
      • @Bean

        • 用于注册Bean
      • 实操

        • 底层包下创建一个component子包,然后创建一个BeanComponent类

          package com.kaiven.springboothello.componet;
          
          import org.springframework.context.annotation.Bean;
          import org.springframework.stereotype.Component;
          
          @Component // 将类注册为组件
          public class BeanComponent {
              @Bean
              public String name(){
                  return "Kaiven"; // 将方法返回的对象注册成Bean
              }
          }
          
          
        • 然后呢,有什么用呢?别着急,我们先聊一下“依赖注入

    • 依赖注入

      • 简单来说,依赖关系就是一个对象中需要用到另外一个对象,即对象中存在一个属性,该属性是另外一个类对象
      • SpringBoot在创建一个对象的过程中,会根据“依赖关系”,把这个对象依赖的对象注入其中,这就是所谓的“依赖注入”
    • 依赖注入demo

      • controller包中创建BeanTestController类

        package com.kaiven.springboothello.controller;
        
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.web.bind.annotation.RequestMapping;
        import org.springframework.web.bind.annotation.RestController;
        
        @RestController
        public class BeanTestController {
            @Autowired  // 找到类型为String的bean,并将其注入name
            private String name;
        
            @RequestMapping("/bean")    // 方法处理/bean地址产生的请求
            public String test() {
                return name;    // 将name的值返回给请求
            }
        }
        
        

        现在,重启一下应用程序吧,访问:localhost:8080/bean

      • 过程解析

        • SpringBoot项目被启动时,扫描器发现了BeanComponent类,并在该类下发现了被@Bean标注的方法,于是把该方法会返回的对象注册Bean,在放在SpringBoot容器中。与此同时,扫描器也发现了BeanTestController类,发现这个类有一个name属性需要被注入值,SpringBoot便在SpringBoot容器中查找有没有类型相同、名称匹配的Bean,于是找到了name()方法返回的字符串“Kaiven”,便将“Kaiven”赋值给了name属性
    • 注册Bean

      • 概念
        • 注册Bean需要用到@Bean注解,该注解用于标注方法,表示方法的返回值是一个即将进入SpringBoot容器中的Bean
      • 让SpringBoot发现Bean
        • 概念
          • 如果要让@Bean注解生效,那么被标注的方法所在的类必须能够被SpringBoot的组件扫描器扫描到
        • 能够让@Bean生效的类注解
          • @Configuration:声明配置类
          • @Controller:声明控制器类
          • @Service:声明服务接口或类
          • @Repository:声明数据仓库
          • @Component:如果不知道类属于什么模块,就是这个注解将类声明成组件(推荐使用)
          • @Import:自行了解,用得不多
      • @Bean的使用方法
        • @Bean注解有很多属性
        • value和name
          • 作用就是给Bean起别名,让SpringBoot可以区分多个类型相同的Bean
          • 如果没有给Bean起别名的话,那么@Bean注解会默认将方法名作为别名
        • autowireCandidate
          • 是否采用默认的自动匹配机制,默认值是true,如果将其赋值为false,这个Bean就不会被默认的自动匹配机制匹配到,只能通过使用别名的方式匹配到
    • 获取Bean

      • 概念

        • 获取Bean就是在类中创建一个属性(可以是private属性),通过为属性添加注解,让SpringBoot为这个属性注入Bean
      • @Autowired、@Resource、@Value

        • 概念

          • 这三个注解可以获取Bean,且智能在可以被扫描到的类中使用
        • @Autowired

          • 该注解可以自动到Spring容器中寻找名称相同或类型相同的Bean

          • 值得注意的是,当SpringBoot容器中仅有一个该类型的Bean时,@Autowired才能匹配成功。如果存在多个该类型的Bean,Spring就不知道应该匹配哪个Bean了,项目就会抛出异常

          • 解决多个Bean同类型引起的报错

            • 将需要进行依赖注入的类属性名改成Bean的别名
            • 使用@Qualifier注解,该注解有一个value属性,用于指定要获取的Bean别名,可以与@Autowired配套使用
          • 代码示例

            我们将原来的name字段名改成了kaiven字段,然后保持BeanComponent类不变,我们会发现程序正常的运作:

            @RestController
            public class BeanTestController {
                @Autowired  // 找到类型为String的bean,并将其注入name
                private String kaiven;
            
                @RequestMapping("/bean")    // 方法处理/bean地址产生的请求
                public String test() {
                    return kaiven;    // 将name的值返回给请求
                }
            }
            
            

            现在我们在BeanComponent类中增加一个相同返回值类型的方法,并用@Bean进行注解:

            @Component
            public class BeanComponent {
                @Bean
                public String name(){
                    return "Kaiven";
                }
            
                @Bean
                public String name2(){
                    return "Kaiven2";
                }
            }
            
            

            重启了应用程序,我们发现,程序抛出异常后退出了:

            Field kaiven in com.kaiven.springboothello.controller.BeanTestController required a single bean, but 2 were found:
            	- name: defined by method 'name' in class path resource [com/kaiven/springboothello/componet/BeanComponent.class]
            	- name2: defined by method 'name2' in class path resource [com/kaiven/springboothello/componet/BeanComponent.class]
            
            This may be due to missing parameter name information
            
            

            现在我们尝试第一种解决方案 —— 更改被注入的字段名:

            @RestController
            public class BeanTestController {
                @Autowired  // 找到类型为String的bean,并将其注入name
                private String name2;
            
                @RequestMapping("/bean")    // 方法处理/bean地址产生的请求
                public String test() {
                    return name2;    // 将name的值返回给请求
                }
            }
            
            

            现在,启动程序,正常运行,方案一,得行。

            现在我们尝试第二种解决方法 —— @Qualifier注解:

            @RestController
            public class BeanTestController {
                @Autowired  // 找到类型为String的bean,并将其注入name
                @Qualifier(value = "name")
                private String kaiven;
            
                @RequestMapping("/bean")    // 方法处理/bean地址产生的请求
                public String test() {
                    return kaiven;    // 将name的值返回给请求
                }
            }
            
            

            重启程序,正常运行,方案二,得行

      • @Resource

        • 作用

          • 与@Autowired类似:@Resource注解自带name属性,可直接指定Bean的别名。其中name属性的默认值为空字符串,表示自动将被标注的属性名作为Bean的别名
        • 代码示例

          @RestController
          public class BeanTestController {
              @Resource(name = "name")
              private String kaiven;
          
              @RequestMapping("/bean")    // 方法处理/bean地址产生的请求
              public String test() {
                  return kaiven;    // 将name的值返回给请求
              }
          }
          
          

          or

          @RestController
          public class BeanTestController {
              @Resource
              private String name;
          
              @RequestMapping("/bean")    // 方法处理 /bean 地址产生的请求
              public String test() {
                  return name;    // 将name的值返回给请求
              }
          }
          
          
      • @Value

        • 作用

          • @Value注解可以动态地向属性注入值
        • 注入常量值

          @RestController
          public class BeanTestController {
              @Value("我真帅啊,哈哈哈!")
              private String name;
          
              @RequestMapping("/bean")    // 方法处理/bean地址产生的请求
              public String test() {
                  return name;    // 将name的值返回给请求
              }
          }
          
          

          重启应用,发送请求,返回@Value内的字符串

        • 注入Bean

          @RestController
          public class BeanTestController {
              @Value("#{name2}")
              private String name;
          
              @RequestMapping("/bean")    // 方法处理/bean地址产生的请求
              public String test() {
                  return name;    // 将name的值返回给请求
              }
          }
          
          

          重启应用,发送请求,返回“kaiven2”

        • 注入配置文件(application.properties)中的配置信息的值

          配置文件:

          spring.application.name=springboot-hello
          kaiven = "kaiven"
          
          

          BeanTestController:

          @RestController
          public class BeanTestController {
              @Value("${kaiven}")
              private String name;
          
              @RequestMapping("/bean")    // 方法处理/bean地址产生的请求
              public String test() {
                  return name;    // 将name的值返回给请求
              }
          }
          
          

          重启服务,发送请求,返回“kaiven”

  • 项目依赖添加

    • 直接在pom.xml添加即可,到指定的网站去copy即可
  • 项目结构规范

    • 配置包
      • 配置包用于存放配置类,所有被@Configuration标注的类都要放到配置包下。包名一般为config或者configuration
      • 不能存放其他配置文件
    • 公共类包
      • 公共类用于存放供其他模块使用的组件、工具、枚举等代码。包名一般为common
    • 控制器包
      • 控制器包用于存放控制器类。包名一般为control或者controller
    • 服务包
      • 服务包存放所有业务的服务接口或服务类。包名一般为service
      • 如果服务包下存放的是服务接口,那么这些接口的实现类都应该放在服务包的子包当中,子包名为impl
    • 数据库访问包
      • 数据库访问接口也就是持久层接口,专门执行读写数据库的操作。持久层接口的通常命名为dao,所以包名也叫dao
      • 如果使用mybatis作为持久层框架,Mybatis会把持久层接口命名为mapper(映射器),所以包名也可以叫做mapper
      • 如果数据库访问接口也有具体的实现类,这些实现类都应该放在数据库访问接口包的impl子包下
    • 数据实体包
      • 由于场景越来越复杂,需求越来越细化,虽然实体类的功能没有发生改变,单根据数据的来源和去处,对实体类进行了更详细的划分。这里我们暂时使用pojo充当包名吧
    • 过滤器包
      • 过滤器包用于存放过滤器类,通常命名为filter
    • 监听器包
      • 监听器包与过滤包类似,专门存放监听器实现类,通常都命名为listener
    • 无论是哪一种包,确保我们的spring应用可以扫描到,最好是都放在底层包下
  • Java文件的命名

    • 控制器类
      • Contrl或者Controller结尾
    • 服务接口/类
      • Service结尾
    • 接口的实现类
      • Impl结尾
    • 工具类
      • Util结尾
    • 配置类
      • Config或者Configuration结尾
    • 组件类
      • Component结尾
    • 异步消息处理类
      • Handler结尾
    • 实体类
      • 实体类是专门用于存放数据的类,类的属性用于保存具体的值。每一个实体类都要提供无参构造方法,每一个属性都要提供getter和setter方法

      • 实体名必须是名词

      • 实体名称可以直接作为类名,不同应用场景可以在类名后面拼接不同的后缀

        • PO持久层对象
          • PO实体类的属性与数据表中的字段一一对应,通常直接用表名为实体类命名
        • DO数据对象
          • 与PO用法类似,区别是PO用于封装持久保存的数据(例如Mysql中的数据),DO通常用于封装非持久数据(例如Redis中的数据)
        • DTO数据传输对象
          • 服务模块向外传输的业务数据对象,通常用业务名做前缀
          • 业务对象的属性不一定全来源于一张表,可能是由多张表的数据加工而成的
        • BO业务对象,与DTO类似
        • VO显示层对象
          • 直接用于在网页上展示的数据对象,对象中包含的属性必须全部在页面中展示出来,不应该包含页面不需要的属性
      • 以上的这些只是些规范,了解含义即可

  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值