一、什么是Spring Bean?
Spring Bean是Spring中最基本的组成单元,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 managed by a Spring IoC container.
翻译过来就是:
在 Spring 中,构成应用程序主干并由Spring IoC容器管理的对象称为Bean。Bean是一个由Spring IoC容器实例化、组装和管理的对象。
Spring是通过声明式配置的方式来定义Bean的,所有创建Bean需要的前置依赖或者参数都是通过配置文件先声明,Spring启动以后会解析这些声明好的配置内容。那么,我们该如何去定义Spring中的Bean呢?
二、定义Spring Bean的方式
一般来说,Spring Bean的定义配置有三种方式:基于XML的方式配置、基于注解扫描的方式配置、基于Java类的配置。
2.1 基于XML的方式配置
这种配置方式主要适用于以下两类场景:
- Bean实现类来自第三方类库、比如DataSource等;
- 需要定义命名空间的配置,如:context、aop、mvc等。
举例:
<beans>
<import resource=“resource1.xml” />//导入其他配置文件Bean的定义
<import resource=“resource2.xml” />
<bean id="userService" class="com.gupaoedu.vip.UserService" init-method="init" destory-method="destory"> </bean>
<bean id="message" class="java.lang.String">
<constructor-arg index="0" value="test"></constructor-arg>
</bean>
</beans>
这段代码是标准的Spring配置内容,咱们从上往下来看,首先导入一个叫做resource1.xml的标准配置文件,然后,导入了第二个标准的配置文件resource2.xml,接着,定义了一个叫做userService的Bean,对应的类是com.gupaoedu.vip.UserService,并且声明了在userService实例化之后要调用init()方法,在userService销毁之后调用destory()方法。
2.2 基于注解扫描的方式配置
这种配置方式主要适用于:在开发中需要引用的类,如Controller、Service、Dao等。
两种配置方法:
<context:component-scan base-package="com.gupaoedu.vip">
<context:include-filter type="regex" expression="com.gupaoedu.vip.mall.*"/>//包含的目标类
<context:exclude-filter type="aspectj" expression="com.gupaoedu.vip.mall..*Controller+"/>//排除的目标类
</context:component-scan>
在这段配置中,context:component-scan相当于使用了Spring内置的扫描注解的组件 @ComponentScan ,声明了需要扫描的基础包路径com.gupaoedu.vip,把所有com.gupaoedu.vip.mall下面的子包全部纳入扫描范围。并且排除了com.gupaoedu.vip.mall 包下面所有以Controller结尾或者包含Controller结尾的类。
使用Spring容器管理组件的beanName规则,默认是类名首字母变小写,可以自己修改。Spring主要提供了4种内置的注解用来声明Bean。它们分别是@Controller,声明为控制层组件的Bean,@Service,声明为业务逻辑层组件的Bean,@Repository,声明为数据访问层组件的Bean,当对组件的层次难以定位的时候使用@Component注解来声明。
2.3 基于Java类的配置
这种配置方式主要适用于以下两类场景:
- 需要通过代码控制对象创建逻辑的场景;
- 实现零配置,消除XML配置文件的场景。
@Configuration
public class BeansConfiguration {
@Bean
public Student student(){
Student student = new Student();
student.setName("张三");
student.setTeacher(teacher());
return student;
}
@Bean
public Teacher teacher(){
Teacher teacher = new Teacher();
teacher.setName("Tom");
return teacher;
}
}
通过分析这段代码,我可以了解到使用基于类的配置需要以下步骤:
- 首先,在BeansConfiguration类上配置@Configuration注解,表示将BeansConfiguration类将定义Bean的元数据;
- 在方法上使用@Bean注解,方法名默认就是Bean的名称,方法返回值就是Bean的实例;
- 通过AnnotationConfigApplicationContext或子类来启动Spring容器,从而加载这些已经声明好的注解配置。
三、Spring容器如何加载Bean?
Spring解析这些声明好的配置内容,将这些配置内容都转化为BeanDefinition对象,BeanDefinition中几乎保存了配置文件中声明的所有内容,再将BeanDefinition存到一个叫做beanDefinitionMap中。以beanName作为Key,以BeanDefinition对象作为Value。之后Spring容器,根据beanName找到对应的BeanDefinition,再去选择具体的创建策略。
Spring Bean的生命周期
- Spring 启动,查找并加载需要被 Spring 管理的 Bean,进行 Bean 的实例化;
- Bean 实例化后,对 Bean 的引入和值注入到 Bean 的属性中;
- 如果 Bean 实现了 BeanNameAware 接口的话,Spring 将 Bean 的 Id 传递给 setBeanName() 方法;
- 如果 Bean 实现了 BeanFactoryAware 接口的话,Spring 将调用 setBeanFactory() 方法,将 BeanFactory 容器实例传入;
- 如果 Bean 实现了 ApplicationContextAware 接口的话,Spring 将调用 Bean 的 setApplicationContext() 方法,将 Bean 所在应用上下文引用传入进来;
- 如果 Bean 实现了 BeanPostProcessor 接口,Spring 就将调用它们的postProcessBeforeInitialization() 方法;
- 如果 Bean 实现了 InitializingBean 接口,Spring 将调用它们的 afterPropertiesSet() 方法。类似地,如果 Bean 使用 init-method 声明了初始化方法,该方法也会被调用;
- 如果 Bean 实现了 BeanPostProcessor 接口,Spring 就将调用它们的postProcessAfterInitialization() 方法;
- 此时,Bean 已经准备就绪,可以被应用程序使用了。它们将一直驻留在应用上下文中,直到应用上下文被销毁;
- 如果 Bean 实现了 DisposableBean 接口,Spring 将调用它的 destory() 接口方法,同样,如果 Bean 使用了 destory-method 声明销毁方法,该方法也会被调用。
参考文章:
https://baijiahao.baidu.com/s?id=1730064966023804126
https://blog.csdn.net/weixin_44129618/article/details/121989474