大白话讲解:

从广义上 Spring 注解可以分为两类:

  • 一类注解是用于注册 Bean

假如 IoC 容器是一间空屋子,首先这间空屋子啥都没有,我们要吃大餐,我们就要从外部搬运食材和餐具进来。这里把某一样食材或者某一样餐具搬进空屋子的操作就相当于每个注册 Bean 的注解作用类似。注册 Bean 的注解作用就是往 IoC容器中放(注册)东西!

用于注册 Bean 的注解:比如 @Component、@Repository、@Controller、@Service、@Configuration 这些注解就是用于注册 Bean,放进 IoC 容器中,一来交给 Spring 管理方便解耦,二来还可以进行二次使用,啥是二次使用呢?这里的二次使用可以理解为:在你开始从外部搬运食材和餐具进空屋子的时候,一次性搬运了猪肉、羊肉、铁勺、筷子四样东西,这个时候你要开始吃大餐,首先你吃东西的时候肯定要用筷子或者铁勺,别说你手抓,只要你需要,你就会去找,这个时候发现你已经把筷子或者铁勺放进了屋子,你就不同再去外部拿筷子进屋子了,意思就是 IoC 容器中已经存在,就可以直接拿去用,而不必再去注册!而拿屋子里已有的东西的操作就是下面要讲的关于使用 Bean 的注解!

  • 一类注解是用于使用 Bean

用于使用 Bean 的注解:比如 @Autowired、@Resource 注解,这些注解就是把屋子里的东西自己拿来用,如果你要拿,前提一定是屋子(IoC)里有的,不然就会报错。比如你要做一道牛肉拼盘需要五头牛做原材料才行,你现在锅里只有四头牛,这个时候你知道,自己往屋子里搬过五头牛,这个时候就直接把屋子里的那头牛直接放进锅里,完成牛肉拼盘的组装。是的这些注解就是需要啥,只要容器中有就往容器中拿,就是这么豪横!而这些注解又有各自的区别,比如 @Autowired 用在筷子上,这筷子你可能想用木质的,或许只想用铁质的,@Autowired 作用在什么属性的筷子就那什么筷子,而 @Resource 如果用在安格斯牛肉上面,就指定要名字就是安格斯牛肉的牛肉。

一、定义

Bean 是 Spring 框架中最核心的两个概念之一(另一个是面向切面编程 AOP)

Spring 官方文档对 bean 的解释是:

In Spring, the objects that form the backbone of your application and that are managed by the Spring IoC container are called beans. A bean is an object that is instantiated, assembled, and otherwise managed by a Spring IoC container.

翻译过来就是:

在 Spring 中,构成应用程序主干并由 Spring IoC 容器管理的对象称为 bean。bean 是由Spring IoC 容器实例化、组装和管理的对象。

从上面翻译过来意思来看:

  • bean 是对象,一个或者多个不限定
  • bean 由 Spring 中一个叫 IoC 的东西管理的
  • 我们的应用程序由一个个 bean 构成

那么问题来了,IoC 是什么呢?

二、控制反转(IoC)

控制反转英文全称:Inversion of Control,简称就是 IoC。控制反转通过依赖注入(DI)方式实现对象之间的松耦合关系。程序运行时,依赖对象由辅助程序动态生成并注入到被依赖对象中,动态绑定两者的使用关系。Spring IoC 容器就是这样的辅助程序,它负责对象的生成和依赖的注入,然后再交由我们使用。

1、什么是依赖注入与控制反转呢?先通过一个例子来理解一下

首先有一个类叫做 Student,里面有两个成员变量分别是 id 和 name,并提供 set、get方法。

public class Student {private Integer id;private String name;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}

另外一个类叫做 StudentManager

public class StudentManager {private Student student;public void setStudent(Student student) {this.student = student;}public void show() {System.out.println(student.getId());System.out.println(student.getName());}
}

这个 StudentManager 类有个成员是 Student 的一个对象,然后它的 show 方法能够打印这个 student 的 id 以及 name,并提供了 setStudent 方法初始化 Student 对象。我们可以说,StudentManager(被依赖对象) 是依赖于 Student(依赖对象)的。

有一个问题,StudentManager 与 Student 之间的耦合非常紧密,假如我们还没有来的及对 StudentManager 的 student 绑定对象,却调用了 show 方法的话,那么程序将会抛出空指针异常。所以 Spring 提供了一套叫做控制反转与依赖注入这套机制,目的就是为了解耦。

在 Spring 中,你不需要自己创建对象,你只需要告诉 Spring,哪些类我需要创建出对象,然后在启动项目的时候 Spring 就会自动帮你创建出该对象,并且只存在一个类的实例。这个类的实例在 Spring 中被称为 Bean。而这种模式,我们称之为“单例模式”。也就是一个类只有一个实例的意思。

那么 Spring 是靠什么来了解究竟哪些类需要帮我们创建呢,这里介绍最常用的两种方式------Java 注解配置,Java 代码配置。之前还有 XML 配置等,但是之前的现在已经不推荐使用了。

首先介绍的是 Java 注解配置,这是最简单也是最常用的一种方式。

声明 含义
@Component 当前类是组件,没有明确的意思
@Service 当前类在业务逻辑层使用
@Repository 当前类在数据访问层
@Controller 当前类在展示层(MVC)使用

以上四种声明方式效果完全一致,使用不同的关键词是为了给阅读的人能够快速了解该类属于哪一层。

使用方法为:在定义的实体类前使用该注解。让我们看下面一段代码

@Component
public class Student {private Integer id;private String name;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}

我们在刚才的 Student 类前面,加上了 @Component 注解,成功告诉 Spring:你要在项目创建运行时帮我创建 Student 类的 Bean (对象)

好了,这时候添加“依赖”就已经做完了,但是还没完,我们虽然让 Spring 帮我们创建了对象,但是 StudentManager 怎么知道这个对象在哪呢?所以接下来,我们要告诉 StudentManager 刚才 Spring 帮我们创建的 Bean (对象)到底在哪,也就是使用(“注入”)这个 Bean。

我们来看看注入注解的语法:

声明 含义
@Autowired 根据 Bean 的 Class 类型来自动装配
@Inject 翻译为“注入”最易懂得注入注解
@Resource 翻译为“资源”,根据 Bean 得属性名称(id 或 name)自动装配

使用方法:在我们需要注入依赖的成员变量前使用该注解,看一下下面一段代码

@Component
public class StudentManager {@Autowiredprivate Student student;public void show() {System.out.println(student.getId());System.out.println(student.getName());}
}

可以看到,在声明成员变量 Student 的前面我们使用了 @Autowired,所以 Spring 会自动帮我们使用(注入)一个 Bean,我们就再也不用担心忘记绑定对象而出现空指针了。但是可以发现,虽然我们告诉了 Spring 哪些类是需要添加依赖,哪些类是需要注入 Bean,但是 Spring 还需要我们做一次配置,来真正完成这样一个操作。

2、让 Spring 控制类构建过程

不用 new,让 Spring 控制 new 过程。在 Spring 中,我们基本不需要 new 一个类,这些都是让 Spring 去做的。Spring 启动时会把所需的类实例化对象,如果需要依赖,则先实例化依赖,然后实例化当前类。因为依赖必须通过构建函数传入,所以实例化时,当前类就会接收并保存所有依赖的对象。这一步也就是所谓的依赖注入。

3、这就是 IOC

在 Spring 中,类的实例化、依赖的实例化、依赖的传入都交由 Spring Bean 容器控制,而不是用 new 方式实例化对象、通过非构造函数方法传入依赖等常规方式。实质的控制权已经交由程序管理,而不是程序员管理,所以叫控制反转。

三、 @Bean 注解的使用

1、使用说明

  • @Bean 注解作用在方法上,产生一个 Bean 对象,然后这个 Bean 对象交给 Spring 管理,剩下的你就不用管了。产生这个 Bean 对象的方法 Spring 只会调用一次,随后这个 Spring 将会将这个 Bean 对象放在自己的 IOC 容器中。
  • @Bean 方法名与返回类名一致,首字母小写。
  • @Component、@Repository、@Controller、@Service 这些注解只局限于自己编写的类,而 @Bean 注解能把第三方库中的类实例加入 IOC 容器中并交给 Spring 管理。
  • @Bean 一般和 @Component 或者 @Configuration 一起使用

2、Bean 名称

2.1、默认情况下 Bean 名称就是方法名(首字母小写),比如下面 Bean 名称便是 myBean

@Bean
public MyBean myBean() {return new MyBean();
}

2.2、@Bean 注解支持设置别名。比如下面除了主名称 myBean 外,还有个别名 myBean1(两个都可以使用)

@Bean("myBean1")
public MyBean myBean() {return new MyBean();
}

2.3、@Bean 注解可以接受一个 String 数组设置多个别名。比如下面除了主名称 myBean 外,还有别名 myBean1、myBean2(三个都可以使用)

@Bean({"myBean1","myBean2"})
public MyBean myBean() {return new MyBean();
}

3、@Bean 与其他注解产生的火花

@Bean 注解常常与 @Scope、@Lazy、@DependsOn 和 @link Primary 注解一起使用

3.1、@Profile 注解

为在不同环境下使用不同的配置提供了支持,如开发环境和生产环境的数据库配置是不同的

@Bean
@Profile("!dev")  // 不是dev环境的能使用这个bean
public MyBean myBean() {MyBean myBean = new MyBean();myBean.setPort("8080");return myBean;
}

3.2、@Scope 注解

在 Spring 中对于 bean 的默认处理都是单例的,我们通过上下文容器.getBean方法拿到 bean 容器,并对其进行实例化,这个实例化的过程其实只进行一次,即多次 getBean 获取的对象都是同一个对象,也就相当于这个 bean 的实例在 IOC 容器中是 public 的,对于所有的 bean 请求来讲都可以共享此 bean。@Scope 注解将其改成 prototype 原型模式(每次获取 Bean 的时候会有一个新的实例)

@Bean
@Scope("prototype")
public MyBean myBean() {MyBean myBean = new MyBean();myBean.setPort("8080");return myBean;
}
@SpringBootApplication
@MapperScan("com.example.quartzdemo.dao")//使用MapperScan批量扫描所有的Mapper接口;
public class QuartzDemoApplication {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(QuartzDemoApplication.class, args);MyBean myBean = (MyBean) context.getBean("myBean");System.out.println(myBean);MyBean myBean2 = (MyBean) context.getBean("myBean");System.out.println(myBean2);}
}

打印输出结果:

com.example.quartzdemo.config.MyBean@49601f82
com.example.quartzdemo.config.MyBean@23e44287

将 @Scope("prototype") 删除掉,再运行启动类,打印结果如下:

com.example.quartzdemo.config.MyBean@4cdd2c73
com.example.quartzdemo.config.MyBean@4cdd2c73

3.3、@Lazy 注解:

在 Spring 框架中,默认会在启动时会创建所有的 Bean 对象,但有些 bean 对象假如长时间不用,启动时就创建对象,会占用其内存资源,从而造成一定的资源浪费,此时我们可以基于懒加载策略延迟对象的创建。

    @Bean@Lazypublic MyBean myBean() {MyBean myBean = new MyBean();myBean.setPort("8080");return myBean;}

3.4、@DependsOn注解:

表示在当前 Bean 创建之前需要先创建特定的其他 Bean

四、Bean 规范

  • 所有属性为 private
  • 提供默认构造方法
  • 提供 getter 和 setter
  • 实现 Serializable (比如可以实现Serializable 接口,用于实现bean的持久性)
  • 属性类型使用包装类

五、参考文档

  • spring bean是什么
  • 大白话讲解Spring的@bean注解
  • Java bean 是个什么概念?

【Java基础】Spring 中 Bean 的理解与使用相关推荐

  1. Spring中Bean的理解以及@Bean的作用

    Bean在Spring和SpringMVC中无所不在,将这个概念内化很重要,下面分享一下我的想法: 一.Bean是啥 1.Java面向对象,对象有方法和属性,那么就需要对象实例来调用方法和属性(即实例 ...

  2. 如果你每次面试前都要去背一篇Spring中Bean的生命周期,请看完这篇文章

    前言 当你准备去复习Spring中Bean的生命周期的时候,这个时候你开始上网找资料,很大概率会看到下面这张图: 先不论这张图上是否全面,但是就说这张图吧,你是不是背了又忘,忘了又背? 究其原因在于, ...

  3. Spring 中 Bean 的生命周期

    本文作者: 伯乐在线 - yemengying 智商捉鸡?,实在没办法一下子理解Spring IoC和AOP的实现原理,看的闹心也不太懂,所以...决定拆成小的不能在小的一个个问题,一点点啃.今天先来 ...

  4. 深究Spring中Bean的生命周期

    前言 这其实是一道面试题,是我在面试百度的时候被问到的,当时没有答出来(因为自己真的很菜),后来在网上寻找答案,看到也是一头雾水,直到看到了<Spring in action>这本书,书上 ...

  5. (转)Spring中Bean的命名问题(id和name区别)及ref和idref之间的区别

    Spring中Bean的命名 1.每个Bean可以有一个id属性,并可以根据该id在IoC容器中查找该Bean,该id属性值必须在IoC容器中唯一: 2.可以不指定id属性,只指定全限定类名,如: & ...

  6. Spring中Bean的生命周期是怎样的?

    对于普通的Java对象,当new的时候创建对象,当它没有任何引用的时候被垃圾回收机制回收.而由Spring IoC容器托管的对象,它们的生命周期完全由容器控制.Spring中每个Bean的生命周期如下 ...

  7. 厉害了,Spring中bean的12种定义方法!

    前言 在庞大的java体系中,spring有着举足轻重的地位,它给每位开发者带来了极大的便利和惊喜.我们都知道spring是创建和管理bean的工厂,它提供了多种定义bean的方式,能够满足我们日常工 ...

  8. 面试问题:Spring中Bean 的生命周期

    Spring Bean生命周期执行流程 在传统的 Java 应用中,Bean 的生命周期很简单,使用关键字 new 实例化 Bean,当不需要该 Bean 时,由 Java 自动进行垃圾回收. Spr ...

  9. Spring中Bean管理操作基于XML配置文件方法实现

    Spring中Bean管理操作基于XML配置文件方法实现 基于XML配置文件方式实现 1.基于`xml`方式创建对象 2.基于`xml`方式注入属性 1.创建类,定义属性和对应的set方法 2.在Sp ...

最新文章

  1. [BZOJ 2839] 集合计数
  2. opencv converTO()函数 转换图像的数据类型不改变通道数,注意与cvtColor()改变颜色空间/彩色空间/色彩空间函数区分
  3. 性能提升2.58倍!阿里最快KV存储引擎揭秘
  4. Prufer序列相关
  5. Google发布Objectron数据集
  6. 【iVX 初级工程师培训教程 10篇文拿证】02 数值绑定及自适应网站制作
  7. CSDN专訪:大数据时代下的商业存储
  8. python xgboost实战_史上最详细的XGBoost实战
  9. 小游戏开发--Cocos引擎
  10. shift and算法
  11. 谁在使用我的网站——用户分类
  12. 编程基本功:找出BUG的特殊性,再确认BUG是否系统导致的
  13. 我的世界服务器修改世界难度,我的世界服务器空岛生存调难度指令 | 手游网游页游攻略大全...
  14. 校友全剧透CMU :ME + 转CS + 其他主要项
  15. 灵遁者:真正热爱生活的人,都知道这点
  16. “视”不可挡:征兵招警,近视手术成“通关法宝”
  17. 如何解决merge conflict的方法
  18. 【数据分析】基于RFM模型的线上零售中的客户细分(二):RFM模型实战
  19. 文保数据-历史文化名城、名街、重点保护单位名单+空间分布数据
  20. 八、基于多源数据建成区提取——Landsat数据大气校正

热门文章

  1. Java 中 UTC 如何转换 CST(北京时间)
  2. python使用Pyinstaller打包整个项目
  3. 数据库的逻辑结构设计步骤
  4. java理发店会员预约管理系统springboot+vue
  5. ARCGIS安装及卸载中遇见的一些问题
  6. 1002 写出这个数 (20 分) 读入一个正整数 n,计算其各位数字之和,用汉语拼音写出和的每一位数字。
  7. windows 10 下微信突然不能输入中文:已禁用输入法,排查键盘问题无果……
  8. Flutter 自绘制 Widget
  9. nc 命令临时启动一个端口便于进行端口测试
  10. 响应式布局的常用解决方案(媒体查询、百分比、rem和vw/vh)