Code Ease Code Ease
  • 个人博客网站 (opens new window)
  • 好用的工具网站 (opens new window)
  • Java核心基础
  • 框架的艺术
  • 分布式与微服务
  • 开发经验大全
  • 设计模式
  • 版本新特性
数据库系列
大数据+AI
  • xxl-job
运维与Linux
  • 基于SpringBoot和BootStrap的论坛网址
  • 基于VuePress的个人博客网站
  • 基于SpringBoot开发的小功能
  • 做一个自己的IDEA插件
程序人生
关于我
  • 分类
  • 标签
  • 归档

神秘的鱼仔

你会累是因为你在走上坡路
  • 个人博客网站 (opens new window)
  • 好用的工具网站 (opens new window)
  • Java核心基础
  • 框架的艺术
  • 分布式与微服务
  • 开发经验大全
  • 设计模式
  • 版本新特性
数据库系列
大数据+AI
  • xxl-job
运维与Linux
  • 基于SpringBoot和BootStrap的论坛网址
  • 基于VuePress的个人博客网站
  • 基于SpringBoot开发的小功能
  • 做一个自己的IDEA插件
程序人生
关于我
  • 分类
  • 标签
  • 归档
服务器
  • Java核心基础

  • 框架的艺术

    • Spring

      • 重新带你走进Spring
      • 控制反转(IOC)和依赖注入(DI)的完美实现
      • 关于Spring中的Bean,一文搞定
      • Spring5竟然可以彻底抛弃xml配置
      • 通俗易懂的AOP切面详解
      • 一文搞定Spring整合Mybatis
      • 事务Transactional注解的参数与失效场景分析
      • 写了两年代码之后再来看看Spring中的Bean
        • (一)什么是Bean
        • (二)如何往Spring容器中添加Bean
        • (三)Bean的作用域
        • (四)Bean的常用注解
          • 4.1 Conditional
          • 4.2 ComponentScan
          • 4.3 @Import
        • (五)Bean的初始化和销毁
          • 1、自定义初始化方法和销毁方法
          • 2、通过 InitializingBean, DisposableBean 接口实现
          • 3、BeanPostProcessor
        • (六)总结
      • 这次终于把Spring的监听器讲明白了
      • 你真的了解Maven吗?
      • 正式发布的Spring AI,能让Java喝上AI赛道的汤吗
    • Mybatis

    • SpringBoot

    • MQ

    • Zookeeper

    • netty

  • 分布式与微服务

  • 开发经验大全

  • 版本新特性

  • Java
  • 框架的艺术
  • Spring
CodeEase
2023-09-20
目录

写了两年代码之后再来看看Spring中的Bean

作者:鱼仔
博客首页: codeease.top (opens new window)
公众号:Java鱼仔

# (一)什么是Bean

Spring中的Bean简单来讲就是一个个被Spring容器管理的Java对象,我们写了一个类之后,这个类只是一个单纯的Java类,可以通过new的方式去创建它。当我们把这个类添加到Spring的容器里之后,这个类就变成了Bean,由Spring容器管理,可以通过自动注入的方式去使用。

# (二)如何往Spring容器中添加Bean

这里列出四种常用的添加Bean的方式。

1、@Bean: 写一个普通的类时最常用的添加Bean的方式

2、@ComponentScan + @Controller @Service @Component @Repository:SpringBoot写多了之后一定会很熟悉这些。

3、@Import:通过导入的方式注入Bean

4、@ImportBeanDefinitionRegister:和Import类似,可以指定Bean的名称

# (三)Bean的作用域

首先介绍最基本的@Bean注解,@Bean注解声明这个类是一个Bean,在Spring5之前,大部分的声明都会放到配置文件里,Spring5之后通过两个注解就可以完成。以Teacher类为例

public class Teacher {
}

@Configuration
public class MainConfig {
    @Bean
    public Teacher teacher(){
        return new Teacher();
    }
}
1
2
3
4
5
6
7
8
9
10

在不指定@Scope的情况下,所有bean的实例都是单实例的bean,并且是饿汉式加载(容器启动时就创建好了)。可以通过注解@Lazy实现懒加载(在调用时被加载)。

@Bean
//@Lazy
public User user(){
    return new User();
}
1
2
3
4
5

指定@Scope为prototype表示为多实例,并且是懒汉式加载(使用时才会创建)

@Bean
@Scope(value = "prototype")
public User user(){
    return new User();
}
1
2
3
4
5

列出其他的几种Bean作用域:

singleton  单例(默认)
prototype  多实例
request  同一次请求
session  同一个会话级别
1
2
3
4

# (四)Bean的常用注解

有几个注解经常会和@Bean一起使用

# 4.1 Conditional

Conditional注解的意思是条件,即满足条件的情况下才会生效 比如我在Bean中配置了Conditional:

@Bean
@Conditional(value = TeacherCondition.class)
public Teacher teacher(){
    return new Teacher();
}
1
2
3
4
5

TeacherCondition 代码如下:如果Spring的Bean中有名字为student的,则返回true,否则返回false

public class TeacherCondition implements Condition {
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        if (conditionContext.getBeanFactory().containsBean("student")){
            return true;
        }
        return false;
    }
}
1
2
3
4
5
6
7
8

最后的结果就是,如果TeacherCondition返回的是true,则teacher这个bean会被注册到容器中,否则就不会注册到容器中。

# 4.2 ComponentScan

这个注解会和Controller、Service等同时出现,给一个类添加Controller、Service等注解后,需要在配置类中增加ComponentScan,ComponentScan扫描到的包下的Controller、Service等注解才会生效:

@Configuration
//最基本的扫描路径方式
//@ComponentScan(basePackages = {"com.javayz.testcompentscan"})
//增加了Filter的方式
@ComponentScan(basePackages = {"com.javayz.testcompentscan"},includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class, Service.class}),
        @ComponentScan.Filter(type = FilterType.CUSTOM,value = {TestFilterType.class})
},useDefaultFilters = false)
public class MainConfig {

    @Bean
    @Scope(value = "prototype")
    public User user(){
        return new User();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

Filter是在扫描时的过滤器,比如设置FilterType.ANNOTATION表示只有这里设置的注解才会被扫描到,FilterType.CUSTOM是自定义过滤器,TestFilterType 类进行了一层判断:包名为dao下的类会被注册到Bean容器中

public class TestFilterType implements TypeFilter {
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        //获取当前类的class源信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        if (classMetadata.getClassName().contains("dao")){
            return true;
        }
        return false;
    }
}
1
2
3
4
5
6
7
8
9
10

# 4.3 @Import

@Import可以用来往容器中导入第三方的组件,也可以起到和@Bean一样的作用:

@Configuration
//@Import(value = {Teacher.class, Student.class})
//@Import(value = {MyImportSelector.class})
@Import(value = {MyBeanDefinitionRegister.class})
public class MainConfig {
}
1
2
3
4
5
6

第一种方式直接导入对应的类,这里和直接写@Bean效果一致

@Import(value = {Teacher.class, Student.class})
1

第二种方式导入ImportSelector对象,通过selectImports方法返回要导入Bean的全限定名:

public class MyImportSelector implements ImportSelector {
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return new String[]{"com.javayz.testimport.compent.Teacher"};
    }
}
1
2
3
4
5

第三种方式通过BeanDefinitionRegister注入Bean(可以指定Bean的名称)

public class MyBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Student.class);
        registry.registerBeanDefinition("student",rootBeanDefinition);
    }
}
1
2
3
4
5
6

Import注解最常用的场景就是SpringBoot自动注入,在SpringBoot自动注入源码中导出可以看到@Import注解的身影。

# (五)Bean的初始化和销毁

当由容器管理Bean的生命周期时,我们可以通过自己指定Bean方法的初始化方法和销毁方法,使得一个Bean在初始化和销毁时能执行自己的方法。

# 1、自定义初始化方法和销毁方法

public class Teacher {
    public Teacher(){
        System.out.println("Teacher 构造方法");
    }
    public void init(){
        System.out.println("Teacher 初始化方法");
    }
    public void destory(){
        System.out.println("Teacher 销毁方法");
    }
}

@Configuration
public class MainConfig {
    @Bean(initMethod = "init",destroyMethod = "destory")
    public Teacher teacher(){
        return new Teacher();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

对于单例bean(singleton)容器启动的时候,bean对象就创建了,在容器销毁的时候,就会去调用Bean的销毁方法。

对于多实例的bean,容器启动的时候bean还未被创建,在获取Bean的时候才会被创建,并且bean的销毁不受IOC容器的管理。

# 2、通过 InitializingBean, DisposableBean 接口实现

Spring的这两个接口也可以实现初始化和销毁的功能。

public class Student implements InitializingBean, DisposableBean {
    public Student(){
        System.out.println("Student 构造方法");
    }
    @Override
    public void destroy() throws Exception {
        System.out.println("Student销毁");
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Student初始化");
    }
}
@Configuration
public class MainConfig {
    @Bean
    public Student student(){
        return new Student();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 3、BeanPostProcessor

BeanPostProcessor在所有Bean的初始化前和初始化后都会被调用

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Bean初始化前");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Bean初始化后");
        return bean;
    }
}

@ComponentScan
@Configuration
public class MainConfig {
    @Bean(initMethod = "init",destroyMethod = "destory")
    public Teacher teacher(){
        return new Teacher();
    }
    @Bean
    public Student student(){
        return new Student();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# (六)总结

别看Bean这个概念听起来简单,里面的内容还真不少。Spring的核心之一IOC也就是对Bean进行管理。我是鱼仔,我们下期再见!

上次更新: 2025/02/18, 11:30:08
事务Transactional注解的参数与失效场景分析
这次终于把Spring的监听器讲明白了

← 事务Transactional注解的参数与失效场景分析 这次终于把Spring的监听器讲明白了→

最近更新
01
AI大模型部署指南
02-18
02
半个月了,DeepSeek为什么还是服务不可用
02-13
03
Python3.9及3.10安装文档
01-23
更多文章>
Theme by Vdoing | Copyright © 2023-2025 备案图标 浙公网安备33021202002405 | 浙ICP备2023040452号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式