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

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

听说微信搜索《Java鱼仔》会变更强哦!


本文收录于githubgitee ,里面有我完整的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类为例


publicclassTeacher {
}
@ConfigurationpublicclassMainConfig {
@BeanpublicTeacherteacher(){
returnnewTeacher();
    }
}

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

@Bean//@LazypublicUseruser(){
returnnewUser();
}

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

@Bean@Scope(value="prototype")
publicUseruser(){
returnnewUser();
}

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

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

(四)Bean的常用注解


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


4.1 Conditional


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

@Bean@Conditional(value=TeacherCondition.class)
publicTeacherteacher(){
returnnewTeacher();
}

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

publicclassTeacherConditionimplementsCondition {
publicbooleanmatches(ConditionContextconditionContext, AnnotatedTypeMetadataannotatedTypeMetadata) {
if (conditionContext.getBeanFactory().containsBean("student")){
returntrue;
        }
returnfalse;
    }
}

最后的结果就是,如果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)
publicclassMainConfig {
@Bean@Scope(value="prototype")
publicUseruser(){
returnnewUser();
    }
}

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



publicclassTestFilterTypeimplementsTypeFilter {
publicbooleanmatch(MetadataReadermetadataReader, MetadataReaderFactorymetadataReaderFactory) throwsIOException {
//获取当前类的class源信息ClassMetadataclassMetadata=metadataReader.getClassMetadata();
if (classMetadata.getClassName().contains("dao")){
returntrue;
        }
returnfalse;
    }
}

4.3 @Import


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

@Configuration//@Import(value = {Teacher.class, Student.class})//@Import(value = {MyImportSelector.class})@Import(value= {MyBeanDefinitionRegister.class})
publicclassMainConfig {
}

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

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

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

publicclassMyImportSelectorimplementsImportSelector {
publicString[] selectImports(AnnotationMetadataannotationMetadata) {
returnnewString[]{"com.javayz.testimport.compent.Teacher"};
    }
}

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

publicclassMyBeanDefinitionRegisterimplementsImportBeanDefinitionRegistrar {
publicvoidregisterBeanDefinitions(AnnotationMetadataimportingClassMetadata, BeanDefinitionRegistryregistry) {
RootBeanDefinitionrootBeanDefinition=newRootBeanDefinition(Student.class);
registry.registerBeanDefinition("student",rootBeanDefinition);
    }
}

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


(五)Bean的初始化和销毁


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


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


publicclassTeacher {
publicTeacher(){
System.out.println("Teacher 构造方法");
    }
publicvoidinit(){
System.out.println("Teacher 初始化方法");
    }
publicvoiddestory(){
System.out.println("Teacher 销毁方法");
    }
}
@ConfigurationpublicclassMainConfig {
@Bean(initMethod="init",destroyMethod="destory")
publicTeacherteacher(){
returnnewTeacher();
    }
}

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


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


2、通过 InitializingBean, DisposableBean 接口实现


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


publicclassStudentimplementsInitializingBean, DisposableBean {
publicStudent(){
System.out.println("Student 构造方法");
    }
@Overridepublicvoiddestroy() throwsException {
System.out.println("Student销毁");
    }
@OverridepublicvoidafterPropertiesSet() throwsException {
System.out.println("Student初始化");
    }
}
@ConfigurationpublicclassMainConfig {
@BeanpublicStudentstudent(){
returnnewStudent();
    }
}

3、BeanPostProcessor


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

@ComponentpublicclassMyBeanPostProcessorimplementsBeanPostProcessor {
@OverridepublicObjectpostProcessBeforeInitialization(Objectbean, StringbeanName) throwsBeansException {
System.out.println("Bean初始化前");
returnbean;
    }
@OverridepublicObjectpostProcessAfterInitialization(Objectbean, StringbeanName) throwsBeansException {
System.out.println("Bean初始化后");
returnbean;
    }
}
@ComponentScan@ConfigurationpublicclassMainConfig {
@Bean(initMethod="init",destroyMethod="destory")
publicTeacherteacher(){
returnnewTeacher();
    }
@BeanpublicStudentstudent(){
returnnewStudent();
    }
}

(六)总结


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

相关文章
|
3月前
|
安全 Java 应用服务中间件
Spring Boot + Java 21:内存减少 60%,启动速度提高 30% — 零代码
通过调整三个JVM和Spring Boot配置开关,无需重写代码即可显著优化Java应用性能:内存减少60%,启动速度提升30%。适用于所有在JVM上运行API的生产团队,低成本实现高效能。
310 3
|
2月前
|
人工智能 监控 Java
零代码改造 + 全链路追踪!Spring AI 最新可观测性详细解读
Spring AI Alibaba 通过集成 OpenTelemetry 实现可观测性,支持框架原生和无侵入探针两种方式。原生方案依赖 Micrometer 自动埋点,适用于快速接入;无侵入探针基于 LoongSuite 商业版,无需修改代码即可采集标准 OTLP 数据,解决了原生方案扩展性差、调用链易断链等问题。未来将开源无侵入探针方案,整合至 AgentScope Studio,并进一步增强多 Agent 场景下的观测能力。
1475 33
|
2月前
|
安全 Java 测试技术
《深入理解Spring》单元测试——高质量代码的守护神
Spring测试框架提供全面的单元与集成测试支持,通过`@SpringBootTest`、`@WebMvcTest`等注解实现分层测试,结合Mockito、Testcontainers和Jacoco,保障代码质量,提升开发效率与系统稳定性。
|
3月前
|
安全 IDE Java
Spring 的@FieldDefaults和@Data:Lombok 注解以实现更简洁的代码
本文介绍了如何在 Spring 应用程序中使用 Project Lombok 的 `@Data` 和 `@FieldDefaults` 注解来减少样板代码,提升代码可读性和可维护性,并探讨了其适用场景与限制。
145 0
Spring 的@FieldDefaults和@Data:Lombok 注解以实现更简洁的代码
|
10月前
|
XML Java 测试技术
Spring IOC—基于注解配置和管理Bean 万字详解(通俗易懂)
Spring 第三节 IOC——基于注解配置和管理Bean 万字详解!
684 26
|
6月前
|
Java 数据库连接 数据库
Spring boot 使用mybatis generator 自动生成代码插件
本文介绍了在Spring Boot项目中使用MyBatis Generator插件自动生成代码的详细步骤。首先创建一个新的Spring Boot项目,接着引入MyBatis Generator插件并配置`pom.xml`文件。然后删除默认的`application.properties`文件,创建`application.yml`进行相关配置,如设置Mapper路径和实体类包名。重点在于配置`generatorConfig.xml`文件,包括数据库驱动、连接信息、生成模型、映射文件及DAO的包名和位置。最后通过IDE配置运行插件生成代码,并在主类添加`@MapperScan`注解完成整合
1064 1
Spring boot 使用mybatis generator 自动生成代码插件
|
5月前
|
安全 Java Nacos
0代码改动实现Spring应用数据库帐密自动轮转
Nacos作为国内被广泛使用的配置中心,已经成为应用侧的基础设施产品,近年来安全问题被更多关注,这是中国国内软件行业逐渐迈向成熟的标志,也是必经之路,Nacos提供配置加密存储-运行时轮转的核心安全能力,将在应用安全领域承担更多职责。
|
6月前
|
Java 调度 流计算
基于Java 17 + Spring Boot 3.2 + Flink 1.18的智慧实验室管理系统核心代码
这是一套基于Java 17、Spring Boot 3.2和Flink 1.18开发的智慧实验室管理系统核心代码。系统涵盖多协议设备接入(支持OPC UA、MQTT等12种工业协议)、实时异常检测(Flink流处理引擎实现设备状态监控)、强化学习调度(Q-Learning算法优化资源分配)、三维可视化(JavaFX与WebGL渲染实验室空间)、微服务架构(Spring Cloud构建分布式体系)及数据湖建设(Spark构建实验室数据仓库)。实际应用中,该系统显著提升了设备调度效率(响应时间从46分钟降至9秒)、设备利用率(从41%提升至89%),并大幅减少实验准备时间和维护成本。
349 0