架构师必须掌握的知识——spring容器扩展点

架构师必须掌握的知识——spring容器扩展点

写作意图

spring作为目前最为主流的框架,能掌握它的各个知识点是必不可少的技能,有些知识在业务代码中不经常使用,但在框架开发时会经常用到。这篇文章的知识就是如此,希望这篇文章能起到夯实基础的作用。本人能力有限,理解不当的地方在所难免,希望各位看官指正。

文章阅读建议

文章遵循带着问题阅读的方式,这样能深刻掌握知识。文章会先抛出要解决的问题,引导思考,一步步阐明如何解决问题。
【同时也更新到了头条上https://www.toutiao.com/i6641387847611859464/

本次主题

本次总结的主题是spring core部分的1.8节内容——容器扩展点

本节要解决的问题_什么时候需要用到容器扩展点

  1. 先想一想容器解决什么问题?
    答:管理beans,实例化beans,获取beans,依据是beans的定义(比如xml,@Bean会解析成Bean的定义对象)
    【注意这里我用的是复数beans,因为对于单个bean有生命周期的扩展点,这会在以后文章中介绍。不要搞混了】

知道了容器能做什么,下面我们就能回答以下问题了

  1. 扩展容器能扩展什么?
    答:自定义bean、自定义bean的定义、自定义bean的实例化逻辑。特别是需要在运行时才能确定属性的赋值,需要哪些依赖的问题。比如通过xml可以配置依赖,但是如果我的依赖需要根据引用的jar包不同,依赖不同怎么办。下面是一些其他的例子
    【举个例子】:
    a. 自定义bean:我希望bean在初始化之前根据一些条件改变bean的属性值,比如有的属性值在某些条件下从环境变量中取值。
    b.自定义bean的定义:比如我希望根据一些条件给bean新增一些属性,修改依赖的bean,这些条件在运行时才能判断,比如引入的jar包。
    c.自定义bean的实例化逻辑:我希望根据一定条件判断实例化的bean类型

如何扩展

估计你首先会想到继承容器对象,这是很自然的想法,但是遗憾的是官方并不推荐
能想到的思路
通过可插拔的接口可以更优雅的实现扩展,我们看看有哪些接口吧
在这里插入图片描述
我们再进一步看看他们提供了什么方法
在这里插入图片描述

1. BeanPostProcessor
  1. 为什么叫PostProcessor?
    答:bean已经完成了属性赋值的后处理
  2. postProcessBefore/AfterInitializing方法名透露了什么信息?
    答:在bean属性赋值后,初始化之前/后调用(比如init-method,这属于bean的生命周期扩展点,我们会在下一篇文章介绍)
    在这里插入图片描述

特别注意,由于是容器的扩展点,方法会对所有的bean进行回调,我们需要判断是否是我们需要处理的bean对象,比如:
if (bean instanceof MybatisProperties) { }

【举个例子】

@Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof MybatisProperties) {
            MybatisProperties mybatisProperties = (MybatisProperties) bean;
            // 根据条件修改mybatisProperties的属性值
            if(xxx){
            	mybatisPropertiess.setXXX(xxx);
            }
        }
        return bean;
    }
@Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof MybatisProperties) {
           MybatisProperties mybatisProperties = (MybatisProperties) bean;
            // 包装,或者代理
           MybatisProperties mybatisPropertiesProxy = Wrap(mybatisProperties);
           return mybatisPropertiesProxy;
        }
        return bean;
    }
2. BeanFactoryPostProcessor
  1. 也叫做PostProcessor,它是什么时候的后处理?
    答:容器被初始化以后,所有的bean的定义被加载到容器后,所有的bean没有被初始化

    【举个例子】
    transactionManager根据不同的数据源类型,动态定义依赖。这个时候你无法用xml或者@Bean去定义依赖,因为只有运行环境你才能知道引入了哪些数据源
@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
			throws BeansException {
		String[] transactionManagers = beanFactory
				.getBeanNamesForType(TransactionManager.class, true, false);
		for (String transactionManager : transactionManagers) {
			addTransactionManagerDependencies(beanFactory, transactionManager);
		}
	}

	private void addTransactionManagerDependencies(
			ConfigurableListableBeanFactory beanFactory, String transactionManager) {
		for (String dependentBeanName : getBeanNamesForType(beanFactory,
				"javax.jms.ConnectionFactory")) {
			beanFactory.registerDependentBean(transactionManager, dependentBeanName);
		}
		for (String dependentBeanName : getBeanNamesForType(beanFactory,
				"javax.sql.DataSource")) {
			beanFactory.registerDependentBean(transactionManager, dependentBeanName);
		}
	}
3. FactoryBean
  1. 从名字中能看出什么含义?
    答:从factory能看出是负责对象创建的,bean说明它是一个bean(注意不要和BeanFactory弄混了)

  2. 创建对象的时机是什么?
    答:既然是spring,时机是获取相应bean的时候
    在这里插入图片描述
    【举个例子】
    通过FactoryBean,可以通过ProxyFactory(后面的文章会介绍到)返回一个代理对象,这个对象会产生一个实现了接口的空实现对象,接口可以注入,比如@Autowired。具体的业务逻辑通过MethodInterceptor接口拦截实现

@Override
    public synchronized Object getObject() throws Exception {
        if (this.proxy == null) {
            ProxyFactory factory = new ProxyFactory(MyInterceptor.class, myMethodInterceptor);
            this.proxy = factory.getProxy();
        }
        return this.proxy;
    }
@Autowired
private MyInterceptor myInterceptor;

这个时候调用myInterceptor的方法,会被myMethodInterceptor进行拦截,在其中实现业务逻辑

4. 其他特性

本主题的问题已经解决,我们还需要关注这些扩展点的其他一些特性,比如BeanPostProcessor和BeanFactoryPostProcessor他们是由applicationContext自动检测生效的,他们的有效范围只针对某个容器,他们可以用Ordered接口设置执行顺序,延迟初始化设置对其无效等。这些特性总结如下:
在这里插入图片描述

扫描二维码关注公众号,回复: 4735974 查看本文章

猜你喜欢

转载自blog.csdn.net/guduyishuai/article/details/85013860