Spring 学习之扩展点总结之后置处理器(二)

Spring 源码系列

1、Spring 学习之扩展点总结之后置处理器(一)
2、Spring 学习之扩展点总结之后置处理器(二)
3、Spring 学习之扩展点总结之自定义事件(三)
4、Spring 学习之扩展点总结之内置事件(四)
5、Spring 学习之扩展点总结之@Import(五)
6、Spring 学习之AOP总结之基础介绍(六)
7、Spring 学习之AOP总结之实现代理(七)
8、SpringBoot 学习之自动配置基本原理(八)
9、SpringBoot 学习之启动原理(九)
10、ElasticSearch学习随笔之SpringBoot Starter 操作
11、图数据库 Neo4j 学习之SpringBoot整合
12、SpringBoot 学习之常用 Filter / Advice 总结
13、SpringBoot+FastJson 优雅的过滤 Response Body
14、Spring Security + Oauth2 认证授权

前言

在 Spring学习之扩展点总结(一)介绍了什么是 BeanDefinition 以及BeanFactoryPostProcessor、BeanPostProcessor 和 Aware 通知的扩展点,但是还没有完,本文继续介绍其他扩展点。

Bean实例化扩展点

1、InitializingBean

InitializingBean 是Spring提供的扩展性接口,当一个 Bean 实现了此扩展接口,那么这个 Bean 在实例化完成之后,就会调用到 afterPropertiesSet() 方法,而我们自己的 Bean 里面肯定会 复写这个方法,那么就会执行到我们自己的代码了。

1、首先创建一个 UserServiceImpl 业务类,并且实现了 InitializingBean 接口,代码如下:

UserServiceImpl 类实现了 InitializingBean 接口,并且复写了 afterPropertiesSet() 方法,可以发现,这个方法是无参的,那是因为这个扩展点只对当前的这个Bean起作用。

@Service
public class UserServiceImpl implements UserService, InitializingBean {

	private String name;

	@Override
	public void sayHi() {
		System.out.println(String.format("被注入的 name: %s", name));
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("初始化 UserServiceImpl Bean 完成!");
	}
}

2、main测试

@ComponentScan("com.self.test")
public class MainStartApp {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainStartApp.class);
		UserServiceImpl bean = applicationContext.getBean(UserServiceImpl.class);
		bean.sayHi();
	}

}

测试结果:
测试结果
从测试结果中可以看出,在 UserServiceImpl 初始化完成之后调用了 afterPropertiesSet() 方法,打印了 “初始化 UserServiceImpl Bean 完成!”。

注意:在之前 Spring 学习之扩展点总结(一)(见文章开头处) 篇中,介绍另一个扩展点,也是对 Bean 的一个增强,那就是 BeanPostProcessor ,都是对 Bean 的一个操作,那么有什么异同点呢?
看下面 1.2 InitializingBean 和 BeanPostProcessor 各负其责。

2、DisposableBean

InitializingBean 是Spring提供的扩展性接口,当一个 Bean 实现了此扩展接口,那么这个 Bean 在销毁之际,就会调用到 destroy() 方法,而我们自己的 Bean 里面肯定会 复写这个方法,那么就会执行到我们自己的代码了。
在一些业务逻辑中,比如在容器注销时,需要把缓存中的数据持久化,就可以用此方法。

1、创建一个 UserServiceImpl 类并且实现接口 DisposableBean 接口,代码如下:

DisposableBean 扩展接口和上面的 InitializingBean 可以说是相辅相成的,InitializingBean 是在一个 Bean 初始化时进行扩展添加功能,而 DisposableBean 是在一个 Bean 销毁之前做一些收尾工作。

@Service
public class UserServiceImpl implements UserService, DisposableBean {

	@Override
	public void destroy() throws Exception {
		System.out.println("UserServiceImpl 已注销!");
	}
}

2、main方法测试

在 main 方法中,实例化容器,需要定义为 AnnotationConfigApplicationContext 类型,并且调用 close() 方法则会调用到 destroy() 注销方法。

@ComponentScan("com.self.test.service")
public class MainStartApp {

	public static void main(String[] args) throws Exception {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainStartApp.class);
		UserService userService = applicationContext.getBean(UserServiceImpl.class);
		applicationContext.close();
	}
}

测试结果:
在这里插入图片描述

从测试结果中可以看到,UserServiceImpl 中的 destroy 方法调用了,但是这个扩展点也有缺点,我们在工作中,有时候停止服务并不是按照正常关闭应用的,有时候运维人员也是比较暴力,直接 kill 的,那么内存里面的数据如果要持久化到数据库,没来得及持久化,就会丢失了。

3、InitializingBean 和 BeanPostProcessor 各负其责

InitializingBean 可以说是对当前的 Bean 的一个增强,主要是 afterPropertiesSet() 方法,就是那个 Bean 实现了 InitializingBean 接口,才会被执行操作,就像 Spring 工厂里面的主心骨 Bean 工人,有权利,需要承担很多业务。
BeanPostProcessor 呢,是多很多 Bean 进行增强,就像一个管家,管理着 Spring 工厂里面的很多 Bean 工人,给他们进行定制化操作。

那么,如果 一个 Bean 既想加入到 BeanPostProcessor 的管理组里面,又想让 InitializingBean 为他特殊服务,这是老总的待遇啊,那该怎么办呢?
他们的服务顺序是怎么样呢?

1、首先创建一个 Car 类,他自身是被 InitializingBean 服务着,如下:

Car 类实现了 InitializingBean 接口。

@Component
public class Car implements InitializingBean {

	public Car() {}

	public Car(int id, String name) {
		this.id = id;
		this.name = name;
	}

	private int id;
	private String name = "奥迪";

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("InitializingBean: 实例化 Car 完成 !");
	}
}

2、然后还想加入 BeanPostProcessor 的管理组,对他进行辅助工作。

新建一个 ValueBeanPostProcessor 服务类并且实现了 BeanPostProcessor 接口,复写 postProcessBeforeInitializationpostProcessAfterInitialization 方法,具体的事情就有这两个方法去做了。
这两个方法都是才参数的,如果是 Car 类的话,就对他进行辅助增强。

@Component
public class ValueBeanPostProcessor implements BeanPostProcessor {

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		if(bean.getClass() == Car.class){
			System.out.println("ValueBeanPostProcessor:实例化 Car Bean 之前");
			Car car = (Car) bean;
			car.setName("奥迪A6");
			return car;
		}
		return null;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		if(bean.getClass() == Car.class){
			System.out.println("ValueBeanPostProcessor:实例化 Car Bean 之后");
			Car car = (Car) bean;
			car.setId(100);
		}
		return null;
	}
}

3、main测试
测试结果
在每个方法里面打印了语句,看打印顺序就知道,先是 BeanPostProcessor 服务者的 postProcessBeforeInitialization 方法对他开始辅助增强,然后就是由他的独有的服务者 InitializingBean 为他服务,最后再由 BeanPostProcessor 的 postProcessAfterInitialization 方法对他进行辅助增强。

所以说,InitializingBean 和 BeanPostProcessor 各负其责。

4、FactoryBean

一句话来概括, FactoryBean 就是用来 生成 Bean 的 一个 Bean。
FactroyBean 提供了具体的行为方法来生产 Bean,看源码便知分晓。
以下就是 FactoryBean 的源码,我们可以看到有三个方法,第一个是 getObject() 返回一个泛型类型,说明我们可以返回任意的类型对象;第二个方法是 getObjectType() 返回 Class,我们可以通过此方法获取到具体类型;第三个是 isSingleton() 是规定是否为单例的。

public interface FactoryBean<T> {

	@Nullable
	T getObject() throws Exception;

	@Nullable
	Class<?> getObjectType();

	default boolean isSingleton() {
		return true;
	}
}

1、创建一个普通的 User 类,这个是我们最终需要的一个对象,在com.self.test.bean 包下。

在构造方法中打印一句话,便于测试。

package com.self.test.bean;
public class User {

	private String name;

	public User() {
		System.out.println("初始化 User 对象!");
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

2、构建一个用来创建 User 对象的一个类 UserFactoryBean,并且复写 getObject() 和 getObjectType() 方法。

实例化 User 对象,并且 设置 name 属性值是 “VIP 用户 张三”。

@Component
public class UserFactoryBean implements FactoryBean<User> {
	@Override
	public User getObject() throws Exception {
		User user = new User();
		user.setName("VIP 用户 张三");
		return user;
	}

	@Override
	public Class<?> getObjectType() {
		return User.class;
	}
}

3、main 测试

下面是通过 main 方法来构建 AnnotationConfigApplicationContext 容器,并且最终获取到 User 实体。

@ComponentScan("com.self.test.iocTest")
public class MainStartApp {

	public static void main(String[] args) throws Exception {

		ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainStartApp.class);
		System.out.println("容器启动完成!");
		User userBean = applicationContext.getBean(User.class);
		System.out.println("从容器中获取到 User:" + userBean);
		Object userFactoryBean = applicationContext.getBean("userFactoryBean");
		System.out.println("从容器中获取到 UserFactoryBean:" + userFactoryBean);
	}

}

测试结果:
打印结果

从打印结果里面可以看出来,容器启动完成之后,我们可以获取到 User 实体,但是在MainStartApp 类上面配置的@ComponentScan并没有配置扫描 User 类所在的包,而且从容器中获取到的 UserFactoryBean 实体居然和 User 对象是同一个对象。

4、如何获取到 UserFactoryBean 实体呢?

在获取 UserFactoryBean 的时候,通过getBean 方法获取,参数是 对象名称,前面必须要加上一个 “&”。

Object userFactoryBean = applicationContext.getBean("&userFactoryBean");

测试结果:
测试结果

从测试结果中可以看出,用& + BeanName作为Bean名称获取到的 UserFactoryBean 就是它自己的实例了,在 User 构造方法中打印的那句话 “初始化 User 对象!” 是在 “获取 User 对象!” 这句话之后的,可以看出来容器是首先创建出 UserFactoryBean 的实例,在调用 getObject 方法的时候才创建出 User 对象的。

5、FactoryBean 和 BeanFactory 形似魂不似

FactoryBean 和 BeanFactory 看上去是两个很像的类名,但是他们的内在和功能缺完全不同。

BeanFactory 就是 Spring Bean工厂的顶级接口,看下面类图就知道,我一直在 main 方法里面测试 new 的 AnnotationConfigurationApplication 向上实现和继承了 ApplicationContext 上下文接口,ApplicationContext 再向上继承的是 ListableBeanFactory 接口;而 DefaultListableBeanFactory 实现了接口 ConfigurableListableBeanFactory,接口 ConfigurableListableBeanFactory 继承了接口 ListableBeanFactory,那么凭什么说 BeanFactory 就是 Spring Bean 工厂的顶级接口呢,继续往下看。

BeanFactory部分类图

接下来我们看看 GenericApplicationContext 的源码,如下:

public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {

	private final DefaultListableBeanFactory beanFactory;

	== 部分代码省略 ==

	/**
	 * Create a new GenericApplicationContext.
	 * @see #registerBeanDefinition
	 * @see #refresh
	 */
	public GenericApplicationContext() {
		this.beanFactory = new DefaultListableBeanFactory();
	}

可以看到在 GenericApplicationContext 类里面 定义了 DefaultListableBeanFactory 类型的 beanFactroy 属性,我们再看看 DefaultListableBeanFactory 类里面是什么样的(只保留了关键代码):

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
		implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {

	
	/** Map from serialized id to factory instance. */
	private static final Map<String, Reference<DefaultListableBeanFactory>> serializableFactories =
			new ConcurrentHashMap<>(8);

	/** Resolver to use for checking if a bean definition is an autowire candidate. */
	private AutowireCandidateResolver autowireCandidateResolver = SimpleAutowireCandidateResolver.INSTANCE;

	/** Map from dependency type to corresponding autowired value. */
	private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16);

	/** Map of bean definition objects, keyed by bean name. */
	private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

可以看到,在 DefaultListableBeanFactory 里面定义了很多 Map 和 List 等集合,则是 Spring 用来存放 Bean 定义和 Bean 的地方了。
整体看下来,一句话总结,BeanFactory 就是 Spring Bean工厂的顶级接口。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值