Spring Bean组件深入理解
一、Spring容器中Bean的常用属性
1-1、作用域
常用作用域有五种
在Spring2.0之前的是两种,分别是 singleton 和 prototype
在Spring2.0之后为支持web应用的ApplicationContext,添加了三种 request、session、global session
- singletion:单例:这种bean作用域是默认的,这种作用域确保不管接收到多少个请求,每个容器中只有一个bean实例,单例模式由bean factory自身来维护
- prototype:多例:prototype作用域与singleton作用域相反,为每一个bean请求提供一个实例
- request:请求:在请求bean作用域内,为每一个来自客户端的网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收
- session:响应会话:确保每个session中有一个bean实例,在session过期后,bean会随之失效
- global-session:全局session作用域:global-session和portlet应用相关。当应用部署在portlet容器中时,它包含很多portlet。如果想让所有的portlet共用全局存储变量,那么这个全局存储变量需要存储在global-session中。全局作用域与servlet中的session作用域效果相同
XML方式
<bean id="persion" class="com.helloworld.entity.Persion" scope="singleton" />
注解方式
@Scope("singleton")
1-2、延迟加载
默认情况下,当容器启动之后,会将所有作用域为单例的bean创建好,如果配置 lazy-init 值为 true ,表示延迟加载,即容器启动之后,不会立即创建该实例
XML方式
<bean id="persion" class="com.helloworld.entity.Persion" lazy-init="true" />
注解方式
@Lazy
二、@Component和@Bean区别
- @Component注解作用于类,@Bean注解作用域方法
- @Bean注解比@Component自定义更强,很多地方我们可以使用@Bean来注解,比如我们引入第三方库中需要用到@Bean
三、Bean的创建方式
创建 Bean 有三种方式,分别是:通过调用构造方法创建 Bean、调用实例工厂方法创建Bean、调用静态工厂方法创建 Bean、通过 setter 方式创建 Bean
3-1、通过调用构造方法创建 Bean
通过XML配置文件或者注解的方式配置 Bean, Spring 会通过调用 Bean 类的构造方法,来创建 Bean 的实例。通过 xml 文件配置,明确指定 Bean 的 class 属性,或者通过注解配置,Spring 容器知道 Bean 的完整类名,然后通过反射调用该类的构造方法即可
3-2、调用实例工厂方法创建Bean
Fruits.java
public interface Fruits {
void show();
}
Apple.java
public class Apple implements Fruits {
@Override
public void show() {
System.out.println("这是一个生产苹果的工厂");
}
}
Banana.java
public class Banana implements Fruits {
@Override
public void show() {
System.out.println("这是一个生产香蕉的工厂");
}
}
FruitsFactory.java
public class FruitsFactory {
public Fruits getFruits(String type){
if ("apple".equals(type)) {
return new Apple();
} else if ("banana".equals(type)){
return new Banana();
} else {
throw new IllegalArgumentException("fruits type is illegal!");
}
}
}
resources 文件夹下配置文件 factorybean.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="fruitsFactory" class="com.helloworld.test.FruitsFactory" />
<bean id="apple" factory-bean="fruitsFactory" factory-method="getFruits">
<constructor-arg value="apple" />
</bean>
<bean id="banana" factory-bean="fruitsFactory" factory-method="getFruits">
<constructor-arg value="banana" />
</bean>
</beans>
测试类,AppTest.java
public class AppTest {
public static void main(String[] args) {
Resource resource = new ClassPathResource("ApplicationContext.xml");
BeanFactory beanFactory = new DefaultListableBeanFactory();
BeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader((BeanDefinitionRegistry) beanFactory);
beanDefinitionReader.loadBeanDefinitions(resource);
Apple apple = (Apple) beanFactory.getBean("apple");
Banana banana = (Banana)beanFactory.getBean("banana");
apple.show();
banana.show();
}
}
结果
这是一个生产苹果的工厂
这是一个生产香蕉的工厂
3-3、调用静态工厂方法创建 Bean
在实例工厂方法的基础上作修改
FruitsFactory
public class FruitsFactory {
public static Fruits getFruits(String type){
if ("apple".equals(type)) {
return new Apple();
} else if ("banana".equals(type)){
return new Banana();
} else {
throw new IllegalArgumentException("fruits type is illegal!");
}
}
}
resources 文件夹下配置文件 factorybean.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="apple" class="com.helloworld.test.FruitsFactory" factory-method="getFruits">
<constructor-arg value="apple" />
</bean>
<bean id="banana" class="com.helloworld.test.FruitsFactory" factory-method="getFruits">
<constructor-arg value="banana" />
</bean>
</beans>
3-4、通过 setter 方式创建 Bean
UserInfo.java
/**
* @author q-linyu
* @className UserInfo
* @description 用户详情
* @date 2021/04/01 0:33
*/
public class UserInfo {
private long id;
private String nickname;
public UserInfo(){}
public UserInfo(long id, String nickname) {
this.id = id;
this.nickname = nickname;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
@Override
public String toString() {
return "UserInfo{" +
"id=" + id +
", nickname='" + nickname + '\'' +
'}';
}
}
resources 文件夹下配置文件 factorybean.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userInfo" class="com.helloworld.entity.UserInfo">
<constructor-arg name="id" value="1" />
<constructor-arg name="nickname" value="zhangsan" />
</bean>
</beans>
3-5、调用实例工厂方法和调用静态工厂方法创建 Bean 的区别
异同之处
- 配置实例工厂方法创建 Bean,必须将实例工厂配置成 Bean 实例;而配置静态工厂方法创建 Bean,则无需配置工厂 Bean;
- 配置实例工厂方法创建 Bean,必须使用 factory-bvean 属性确定工厂 Bean; 而配置静态工厂方法创建 Bean,则使用 class 属性确定静态工厂类。
相同之处
- 都需要使用 factory-method 指定生产 Bean 实例的工厂方法;
- 工厂方法如果需要参数,都使用 <constructor-arg.../> 元素指定参数值;
- 普通的设值注入,都使用 <property.../>元素确定参数值。
四、FactoryBean 和 BeanFactory
FactoryBean 和 BeanFactory 它们是两个极易混淆的概念,逐一分析和理解
4-1、FactoryBean
FactoryBean 见名知意就是 工厂Bean 的意思,它是 Spirng 提供的 工厂bean 的一个接口
其中从源码中我们就会发现它有三个方法
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
当自定义一个类实现了 FactoryBean 接口后,将该类部署在 Spring 容器里,再通过 Spring 容器调用 getBean 方法获取到的就不是该类的实例了,而是该类实现的 getObject 方法的返回值。这三个方法意义如下:
getObject()方法返回了该工厂Bean 生成的 java 实例getObjectType()该方法返回该工厂Bean 生成的 java 实例的类型isSingleton()该方法返回该工厂Bean 生成的 java 实例是否为单例
直接上代码:
/**
* @author q-linyu
* @className UserInfoFactoryBean
* @description 使用FactoryBean 管理 UserInfo 对象
* @date 2021/04/01 12:20
*/
public class UserInfoFactoryBean implements FactoryBean<UserInfo> {
/**
* 创建具体对象是由此getObject()方法来返回的
* @return
* @throws Exception
*/
@Override
public UserInfo getObject() throws Exception {
return new UserInfo();
}
/**
* 创建的具体bean对象的类型
* @return
*/
@Override
public Class<?> getObjectType() {
return UserInfo.class;
}
/**
* 是否是单例
* @return
*/
@Override
public boolean isSingleton() {
return true;
}
}
resources 文件夹下配置文件 factorybean.xml
<bean id="userInfoFactoryBean" class="com.helloworld.beans.UserInfoFactoryBean" />
测试类:AppTest.xml
public class AppTest {
public static void main(String[] args) throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext("factorybean.xml");
Object bean = context.getBean("userInfoFactoryBean");
System.out.println(bean.getClass().toString());
}
}
结果
class com.helloworld.entity.UserInfo
得出的结论是:FactoryBean是个bean,在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式,是一个可以生产对象和装饰对象的工厂bean,由Spring管理后,生产的对象是由getObject()方法决定的
4-2、BeanFactory
用一个最直观的方式去理解。打开IDEA,Ctrl + N 搜索 BeanFactory,再按 Ctrl + H 此时右侧显示 接口/类 的关系导航栏

在图中我们就可以看得出,BeanFactory 作为一个根接口,定义了IOC容器的最基本形式,并提供了IOC容器应遵守的的最基本的接口,也就是Spring IOC所遵守的最底层和最基本的编程规范。在Spring代码中,BeanFactory只是个接口,并不是IOC容器的具体实现,同时也是某种功能的扩展实现。比如我们最常用:ApplicationContext、AnnotationConfigApplicationContext、FileSystemXmlApplicationContext、ClassPathXmlApplicationContext
BeanFactory 包含如下几个基本方法:
public interface BeanFactory {
String FACTORY_BEAN_PREFIX = "&";
// 返回容器中 id 为 name 的 Bean 实例
Object getBean(String var1) throws BeansException;
// 返回容器中 id 为name,并且类型为 var1 的Bean
<T> T getBean(String var1, Class<T> var2) throws BeansException;
Object getBean(String var1, Object... var2) throws BeansException;
// 获取Spring容器中属于 var1 类型的、唯一的 Bean 实例
<T> T getBean(Class<T> var1) throws BeansException;
<T> T getBean(Class<T> var1, Object... var2) throws BeansException;
<T> ObjectProvider<T> getBeanProvider(Class<T> var1);
<T> ObjectProvider<T> getBeanProvider(ResolvableType var1);
// 判断Spring容器中是否包含 id 为 name 的 Bean 实例
boolean containsBean(String var1);
boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;
boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;
// 返回 id 为 name 的 Bean 实例的类型
@Nullable
Class<?> getType(String var1) throws NoSuchBeanDefinitionException;
String[] getAliases(String var1);
}
五、生命周期
5-1、执行流程

5-2、接口方法分类
- Bean标签级方法:这个包括了Bean本身调用的方法和通过配置文件中
的init-method和destroy-method指定的方法 - Bean级生命周期接口方法:BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean
- 容器级生命周期接口方法:InstantiationAwareBeanPostProcessor 和 BeanPostProcessor接口实现,通常叫为 "后置处理器"
- 后处理器工厂接口方法:AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer等等工厂接口的方法,工厂后处理器也是容器级的,可在应用上下文装配配置文件之后立即调用
5-3、示例
UserInfo.java
package com.helloworld.entity;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
/**
* @author q-linyu
* @className UserInfo
* @description 用户信息
* @date 2021/04/22 13:00
*/
public class UserInfo implements BeanNameAware,BeanFactoryAware, InitializingBean, DisposableBean {
private long id;
private String nickname;
private int age;
private String email;
private String address;
public UserInfo() {
System.out.println("[构造器] 调用[UserInfo]的构造器实例化");
}
public UserInfo(long id, String nickname, int age, String email, String address) {
this.id = id;
this.nickname = nickname;
this.age = age;
this.email = email;
this.address = address;
}
public long getId() {
return id;
}
public void setId(long id) {
System.out.println("[注入属性] 注入属性[id]");
this.id = id;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
System.out.println("[注入属性] 注入属性[nickname]");
this.nickname = nickname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
System.out.println("[注入属性] 注入属性[age]");
this.age = age;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
System.out.println("[注入属性] 注入属性[email]");
this.email = email;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
System.out.println("[注入属性] 注入属性[address]");
this.address = address;
}
@Override
public String toString() {
return "UserInfo{" +
"id=" + id +
", nickname='" + nickname + '\'' +
", age=" + age +
", email='" + email + '\'' +
", address='" + address + '\'' +
'}';
}
private BeanFactory beanFactory;
private String beanName;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("[BeanFactoryAware接口] 调用BeanFactoryAware.setBeanFactory()");
this.beanFactory = beanFactory;
}
@Override
public void setBeanName(String beanName) {
System.out.println("[BeanNameAware接口] BeanNameAware接口.setBeanName()");
this.beanName = beanName;
}
@Override
public void destroy() throws Exception {
System.out.println("[DiposibleBean接口] 调用DiposibleBean.destory()");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("[InitializingBean接口] 调用InitializingBean.afterPropertiesSet()");
}
public void myinit(){
System.out.println("[init-method] 调用<bean>的init-method属性指定的初始化方法");
}
public void myDestory(){
System.out.println("[destroy-method] 调用<bean>的destroy-method属性指定的初始化方法");
}
}
MyBeanPostProcessor.java
package com.helloworld.processors;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* @author q-linyu
* @className MyBeanPostProcessor
* @description 自定义后置处理器
* @date 2021/04/22 13:15
*/
public class MyBeanPostProcessor implements BeanPostProcessor {
public MyBeanPostProcessor() {
super();
System.out.println("这是BeanPostProcessor实现类构造器");
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor接口方法postProcessBeforeInitialization对属性进行更改");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor接口方法postProcessAfterInitialization对属性进行更改");
return bean;
}
}
MyInstantiationAwareBeanPostProcessor.java
package com.helloworld.processors;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
/**
* @author q-linyu
* @className MyInstantiationAwareBeanPostProcessor
* @description
* @date 2021/04/22 13:24
*/
public class MyInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
public MyInstantiationAwareBeanPostProcessor(){
super();
System.out.println("这是InstantiationAwareBeanPostProcessorAdapter实现类构造器");
}
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
System.out.println("InstantiationAwareBeanPostProcessor调用postProcessBeforeInstantiation方法");
return null;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("InstantiationAwareBeanPostProcessor调用postProcessAfterInitialization方法");
return bean;
}
}
MyBeanFactoryPostProcessor.java
package com.helloworld.processors;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
/**
* @author q-linyu
* @className MyBeanFactoryPostProcessor
* @description
* @date 2021/04/22 13:42
*/
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public MyBeanFactoryPostProcessor() {
super();
System.out.println("这是BeanFactoryPostProcessor实现类构造器");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
System.out.println("BeanFactoryPostProcessor调用postProcessBeanFactory方法");
BeanDefinition beanDefinition = configurableListableBeanFactory.getBeanDefinition("userInfo");
beanDefinition.getPropertyValues().addPropertyValue("nickname","zhangsan");
}
}
MyBeanFactoryPostProcessor.java
package com.helloworld.processors;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
/**
* @author q-linyu
* @className MyBeanFactoryPostProcessor
* @description
* @date 2021/04/22 13:42
*/
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public MyBeanFactoryPostProcessor() {
super();
System.out.println("这是BeanFactoryPostProcessor实现类构造器");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
System.out.println("BeanFactoryPostProcessor调用postProcessBeanFactory方法");
BeanDefinition beanDefinition = configurableListableBeanFactory.getBeanDefinition("userInfo");
beanDefinition.getPropertyValues().addPropertyValue("id",1L);
beanDefinition.getPropertyValues().addPropertyValue("nickname","刘备");
}
}
编写 ApplicationContext.xml 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="beanPostProcessor" class="com.helloworld.processors.MyBeanPostProcessor" />
<bean id="instantiationAwareBeanPostProcessor" class="com.helloworld.processors.MyInstantiationAwareBeanPostProcessor" />
<bean id="beanFactoryPostProcessor" class="com.helloworld.processors.MyBeanFactoryPostProcessor" />
<bean id="userInfo" class="com.helloworld.entity.UserInfo" init-method="myinit" destroy-method="destroy">
<property name="id" value="1" />
<property name="nickname" value="刘备" />
<property name="age" value="25" />
<property name="email" value="123456789@qq.com" />
<property name="address" value="成都市蜀汉王朝辅助大臣李严代收" />
</bean>
</beans>
测试用例
package com.helloworld.test;
import com.helloworld.entity.UserInfo;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author q-linyu
* @className AppTest
* @description 测试用例
* @date 2021/04/01 12:25
*/
public class AppTest {
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
System.out.println("容器初始化成功");
UserInfo userInfo = context.getBean("userInfo",UserInfo.class);
System.out.println("现在开始关闭容器!");
System.out.println(userInfo.toString());
context.registerShutdownHook();
}
}
结果
这是BeanFactoryPostProcessor实现类构造器
BeanFactoryPostProcessor调用postProcessBeanFactory方法
这是BeanPostProcessor实现类构造器
这是InstantiationAwareBeanPostProcessorAdapter实现类构造器
InstantiationAwareBeanPostProcessor调用postProcessBeforeInstantiation方法
[构造器] 调用[UserInfo]的构造器实例化
[注入属性] 注入属性[id]
[注入属性] 注入属性[nickname]
[注入属性] 注入属性[age]
[注入属性] 注入属性[email]
[注入属性] 注入属性[address]
[BeanNameAware接口] BeanNameAware接口.setBeanName()
[BeanFactoryAware接口] 调用BeanFactoryAware.setBeanFactory()
BeanPostProcessor接口方法postProcessBeforeInitialization对属性进行更改
[InitializingBean接口] 调用InitializingBean.afterPropertiesSet()
[init-method] 调用<bean>的init-method属性指定的初始化方法
BeanPostProcessor接口方法postProcessAfterInitialization对属性进行更改
InstantiationAwareBeanPostProcessor调用postProcessAfterInitialization方法
容器初始化成功
现在开始关闭容器!
UserInfo{id=1, nickname='zhangsan', age=25, email='123456789@qq.com', address='成都市蜀汉王朝刘备代收'}
[DiposibleBean接口] 调用DiposibleBean.destory()

浙公网安备 33010602011771号