浅析Spring 中 Bean 的理解与使用

目录
  • 一、定义
  • 二、控制反转(IoC)
    • 1、什么是依赖注入与控制反转呢?先通过一个例子来理解一下
    • 2、让 Spring 控制类构建过程
    • 3、这就是 IOC
  • 三、 @Bean 注解的使用
    • 1、使用说明
    • 2、Bean 名称
      • 2.1、默认情况下 Bean 名称就是方法名(首字母小写),比如下面 Bean 名称便是 myBean
      • 2.2、@Bean 注解支持设置别名。比如下面除了主名称 myBean 外,还有个别名 myBean1(两个都可以使用)
      • 2.3、@Bean 注解可以接受一个 String 数组设置多个别名。
    • 3、@Bean 与其他注解产生的火花
      • 3.1、@Profile 注解
      • 3.2、@Scope 注解
      • 3.3、@Lazy 注解:
      • 3.4、@DependsOn注解:
  • 四、Bean 规范
  • 五、参考文档

大白话讲解:

从广义上 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 {
    @Autowired
    private 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
    @Lazy
    public 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 是个什么概念?

到此这篇关于Spring 中 Bean 的理解与使用的文章就介绍到这了,更多相关Spring Bean 使用内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解Spring中Bean后置处理器(BeanPostProcessor)的使用

    目录 一.BeanPostProcessor接口 二.案例 三.总结 一.BeanPostProcessor接口 Bean后置处理:对Spring 工厂创建的对象进行二次加工处理,即预初始化和后初始化. PostProcessor中文意思就是后置处理器. BeanPostProcessor 接口也被称为Bean后置处理器,通过该接口可以自定义调用初始化前后执行的操作方法. 该接口中包含了两个方法:before方法(预初始化)和after方法(后厨是化) postProcessBeforeInit

  • 使用Spring初始化加载InitializingBean()方法

    目录 Spring初始化加载InitializingBean() 1.spring初始化bean有两种方式 2.相同点 3.不同点 4.InitializingBean接口定义的源码如下所示 5.由于代码在项目启动的时候会执行afterPropertiesSet()方法 6.这个方法将在所有的属性被初始化后调用 关于InitializingBean简单使用 这是一个Spring组件Filer 实现了afterPropertiesSet方法 debug启动项目 Spring初始化加载Initial

  • Spring中Bean的单例和多例使用说明

    目录 Bean的单例和多例使用 实战演示 Spring单例bean与原型bean区别和创建过程 singletonScope与prototypeScope Bean的单例和多例使用 在Spring中,bean可以被定义为两种模式:prototype(多例)和singleton(单例) singleton(单例):只有一个共享的实例存在,所有对这个bean的请求都会返回这个唯一的实例. prototype(多例):对这个bean的每次请求都会创建一个新的bean实例,类似于new. Spring

  • Spring详细讲解FactoryBean接口的使用

    目录 一.基本使用 二.高级使用 FactoryBean是一个接口,创建对象的过程使用了工厂模式. 一.基本使用 让Spring容器通过FactoryBean来实现对象的创建. 创建FactoryBean案例 public class SimpleFactoryBean implements FactoryBean<Cat> { @Override public Cat getObject() throws Exception { // 创建Cat对象并且返回 return new Cat(&

  • SpringBoot如何使用ApplicationContext获取bean对象

    目录 使用ApplicationContext获取bean对象 SpringBoot Bean注入的深入研究 下面代码可正常运行 下面代码不能正常运行 比较 解决方案 应用 使用ApplicationContext获取bean对象 编写一个ApplicationContextFactory工厂类 public class ApplicationContextFactory{ private static ApplicationContext applicationContext = null;

  • Bean Searcher配合SpringBoot的使用详解

    先吐槽一下,现在的Bean Searcher操作手册的指引弱的可怜…对我这样的小白及其不友好 话不多说直入主题 1.首先肯定是得引入依赖 <dependency> <groupId>com.ejlchina</groupId> <artifactId>bean-searcher-boot-starter</artifactId> <version>${searcher.version}</version> </dep

  • 浅析Spring 中 Bean 的理解与使用

    目录 一.定义 二.控制反转(IoC) 1.什么是依赖注入与控制反转呢?先通过一个例子来理解一下 2.让 Spring 控制类构建过程 3.这就是 IOC 三. @Bean 注解的使用 1.使用说明 2.Bean 名称 2.1.默认情况下 Bean 名称就是方法名(首字母小写),比如下面 Bean 名称便是 myBean 2.2.@Bean 注解支持设置别名.比如下面除了主名称 myBean 外,还有个别名 myBean1(两个都可以使用) 2.3.@Bean 注解可以接受一个 String 数

  • 详解Spring 中 Bean 的生命周期

    前言 这其实是一道面试题,是我在面试百度的时候被问到的,当时没有答出来(因为自己真的很菜),后来在网上寻找答案,看到也是一头雾水,直到看到了<Spring in action>这本书,书上有对Bean声明周期的大致解释,但是没有代码分析,所以就自己上网寻找资料,一定要把这个Bean生命周期弄明白! ​ 网上大部分都是验证的Bean 在面试问的生命周期,其实查阅JDK还有一个完整的Bean生命周期,这同时也验证了书是具有片面性的,最fresh 的资料还是查阅原始JDK!!! 一.Bean 的完整

  • Spring中Bean的加载与SpringBoot的初始化流程详解

    目录 前言 第一章 Spring中Bean的一些简单概念 1.1 SpingIOC简介 1.2 BeanFactory 1.2.1 BeanDefinition 1.2.2 BeanDefinitionRegistry 1.2.3 BeanFactory结构图 1.3 ApplicationContext 第二章 SpringBoot的初始化流程 2.1 准备阶段 2.2 运行阶段 2.2.1 监听器分析 2.2.2 refreshContext 2.3 总结 前言 一直对它们之间的关系感到好奇

  • Spring中bean集合注入的方法详解

    目录 Map注入 List注入 Set注入 数组注入 应用 哈喽大家好啊,我是Hydra. Spring作为项目中不可缺少的底层框架,提供的最基础的功能就是bean的管理了.bean的注入相信大家都比较熟悉了,但是有几种不太常用到的集合注入方式,可能有的同学会不太了解,今天我们就通过实例看看它的使用. 首先,声明一个接口: public interface UserDao { String getName(); } 然后定义两个类来分别实现这个接口,并通过@Component注解把bean放入s

  • Java Spring中Bean的作用域及生命周期

    目录 1.Bean的作用域 1.1 被修改的Bean案例 1.2 为什么使用单例模式作为默认作用域 1.3 作用域 1.4 Bean的6种作用域 1.5 设置作用域 2.Spring执行流程和Bean的生命周期 2.1 Bean的生命周期 2.1.1生命周期演示 2.1.2 为什么要先设置属性,在进行初始化 1.Bean的作用域 1.1 被修改的Bean案例 原因:Bean的作用域默认是单例模式的,也就是说所有⼈的使⽤的都是同⼀个对象!之前我们学单例模式的时候都知道,使⽤单例可以很⼤程度上提⾼性

  • Spring中bean的继承与抽象代码示例

    我们在应用Spring时,在一般的设计时,肯定要用的抽象类.那在Spring中怎么样配置这些抽象Bean呢.请看下面: 如果两个bean 之间的配置信息非常相似,可利用继承来减少重复配置工作. 继承是指子bean 定义可从父bean 定义继承部分配置信息,也可覆盖特定的配置信息,或者添加一些配置.使用继承配置可以节省很多的配置工作.在实际应用中,通用配置会被配置成模板,可供子bean 继承. 使用abstract 属性 正如前面所介绍的,通用的配置会被配置成模板,而模板不需要实例化,仅仅作为子b

  • java JSP开发之Spring中Bean的使用

    java JSP开发之Spring中Bean的使用 在传统的Java应用中,bean的生命周期很简单.使用Java关键字new进行bean实例化,然后bean就可以被使用了,一旦该bean不再使用,Java就自动进行垃圾回收.然而,在Spring中,bean的生命周期就比较复杂了.下面是一个bean装载到Spring应用上下文的过程: 如图所示:在你准备调用bean之前,bean工厂执行了若干启动步骤: 1.Spring对bean进行实例化: 2.Spring将值和bean的引用注入到bean对

  • 浅谈Spring中Bean的作用域、生命周期

    本文主要探究的是关于Bean的作用域.生命周期的相关内容,具体如下. Bean的作用域 Spring 3中为Bean定义了5中作用域,分别为singleton(单例).prototype(原型).request.session和global session,5种作用域说明如下: 1.singleton:单例模式,Spring IoC容器中只会存在一个共享的Bean实例,无论有多少个Bean引用它,始终指向同一对象.Singleton作用域是Spring中的缺省作用域,也可以显示的将Bean定义为

  • 关于Spring中Bean的创建进行更多方面的控制

    我们知道Spring Boot 中一个@Controller修饰的Bean是在什么时间被创建的,那么这个Bean创建时间能不能由我们管控?答案是肯定的 关于Spring中Bean的创建,除了配置装配属性外,我们还可以进行更多方面的控制. 1,首先,我们可以控制Bean是单例还是可以生成多个对象的. 在Spring中,Bean默认是单例的,如果想每次请求都生成一个新的Bean对象,可以在定义Bean时,在<bean>标签中配置scope属性为prototype,那么,就会允许该Bean可以被多次

  • Spring中Bean的命名方式代码详解

    本文主要描述的是关于spring中bean的命名方式,通过简单实例向大家介绍了六种方式,具体如下. 一般情况下,在配置一个Bean时需要为其指定一个id属性作为bean的名称.id在IoC容器中必须是唯一的,此外id的命名需要满足xml对id的命名规范. 在实际情况中,id命名约束并不会给我们带来影响.但是如果用户确实希望用到一些特殊字符来对bean进行命名,那么可以使用bean的name属性来进行命名,name属性没有字符上的限制,几乎可以使用任何字符. 每个Bean可以有一个或多个id,我们

随机推荐