-
注解
- 概念
- 注释是用来干嘛的?或者说写给谁看的?当然是程序员啦,不然那堆屎山代码谁看得懂啊,哈哈
- 注解其实也类似,只不过是写给程序“看”的,程序“看”了就知道,哦,你要这样做呀
- 注意
- 注解仅仅只是修饰作用,与业务逻辑无关
- 程序运行的时候扫描到注解,根据不同的注解自动完成一些工作
- 注解不是程序本身,但是可以对程序作出解释
- 应用程序中的类、方法、变量、参数、包等程序元素都可以被注解
- 注解仅仅只是修饰作用,与业务逻辑无关
- 应用
- 编译时进行格式检查
- 减少配置
- 减少重复性工作
- 概念
-
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显示层对象
- 直接用于在网页上展示的数据对象,对象中包含的属性必须全部在页面中展示出来,不应该包含页面不需要的属性
- PO持久层对象
-
以上的这些只是些规范,了解含义即可
-
- 控制器类
02、SpringBoot 注解、Bean的注册与获取、依赖添加、命名规范
于 2024-08-02 23:24:45 首次发布