Spring源码解析(五)--Spring扩展点和扩展原理源码解析。

前文:通过Spring专题和Mybatis专题,我们学习到了Spring容器在初始化的时候有很多可以利用的机会。我们本篇主要讲解一下几个重要的接口和类,让我们能够在项目中Spring容器初始化的时候,更好的实现我们的需求开发。

一、本篇介绍的接口和类。

1、BeanPostProsessor Bean后置处理器。
2、BeanDefinitionRegistryPostProsessor 动态注册Bean到Spring容器。
3、BeanFactoryPostProsessor bean工厂后置处理器。
4、InitializingBean bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候都会执行该方法。
5、ApplicationListener 事件监听器。
6、ImportBeanDefinitionRegistrar ImportBeanDefinitionRegistrar类只能通过其他类@Import的方式来加载,通常是启动类或配置类。

二、对上面的接口和类仅以逐一解析。

1、BeanPostProsessor

public interface BeanPostProcessor {
	//在初始化之前调用
	Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
	//在初始化之后调用
	Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

如果这个接口的某个实现类被注册到某个容器,那么该容器的每个Bean在调用初始化方法之前,都会获得该接口实现类的一个回调。容器调用接口定义的方法时会将该受管Bean的实例和名字通过参数传入方法,进过处理后通过方法的返回值返回给容器。也就是回调了***postProcessBeforeInitialization*** 方法

要使用BeanPostProcessor回调,就必须先在容器中注册实现该接口的类,那么如何注册呢?BeanFactory和ApplicationContext容器的注册方式不大一样:若使用BeanFactory,则必须要显示的调用其addBeanPostProcessor()方法进行注册,参数为BeanPostProcessor实现类的实例;如果是使用ApplicationContext,那么容器会在配置文件在中自动寻找实现了BeanPostProcessor接口的Bean,然后自动注册,我们要做的只是配置一个BeanPostProcessor实现类的Bean就可以了。
我们来看下ApplicationContext容器是怎样注册BeanPostProcessor的。
AbstractApplicationContext中的refresh方法中有一个registerBeanPostProcessors方法。源代码如下

@Override
	public void refresh() throws BeansException, IllegalStateException {
	//省略....
		// Register bean processors that intercept bean creation.
		registerBeanPostProcessors(beanFactory);
	//省略....
		/**
		* 1.实例化剩余的所有非延迟加载单例对象
		* 2.为什么说是剩余的?因为在上面的registerBeanPostProcessors中已经把所有BeanPostProcessors所有对象都已经实例化过了;
		* 3.这加载的时候会判断bean是不是 FactoryBean类型的
		*   3.1如果是FactoryBean类型,则getBean(&beanName),这里是把FactoryBean本身的对象给实例化了,而没有调它的getObject方法;
		*      3.1.1 还要判断是不是SmartFactoryBean类型的,SmartFactoryBean继承了FactoryBean接口;但是它多了一个	boolean isEagerInit();方法;这个方法就是判断是否需要通过FactoryBean的getObject()生成实例;
		*   3.2如果不是FactoryBean类型,直接getBean就行了;
		* 其实我们在上一篇分享 FactoryBean的时候,有调用BeanPostProcessors的后置方法,但是很不理解这里为啥还要执行一次,因为讲道理在之前就应该执行过,TODO...看文章....
		* 4.还要判断是不是SmartInitializingSingleton接口,这个接口有个afterSingletonsInstantiated方法;
		* 循环所以bean判断是不是这个类型的,只要是这个类型就调用afterSingletonsInstantiated方法;
		*/
		finishBeanFactoryInitialization(beanFactory);
				//省略..
		}


委托给PostProcessorRegistrationDelegate调用其registerBeanPostProcessors方法。按照实现priorityOrdered、Ordered 和其他的顺讯进行回调方法的调用。

2、BeanDefinitionRegistryPostProcessor
调用时机是:invokeBeanFactoryPostProcessors。
invokeBeanFactoryPostProcessors(beanFactory)实际上是委托org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());方法处理的。
在这里插入图片描述
所有实现了BeanDefinitionRegistryPostProcessor接口的bean,其postProcessBeanDefinitionRegistry方法都会调用,然后再调用其postProcessBeanFactory方法,这样一来,我们如果自定义了BeanDefinitionRegistryPostProcessor接口的实现类,那么我们开发的postProcessBeanDefinitionRegistry和postProcessBeanFactory方法都会被执行一次;

BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor接口,BeanFactoryPostProcessor的实现类在其postProcessBeanFactory方法被调用时,可以对bean的定义进行控制,因此BeanDefinitionRegistryPostProcessor的实现类一共要实现以下两个方法:

void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException:
该方法的实现中,主要用来对bean定义做一些改变。

void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException:
该方法用来注册更多的bean到spring容器中,详细观察入参BeanDefinitionRegistry接口,这个参数可以更改我们bean定义的一些信息。

3、BeanFactoryPostProsessor
BeanFactoryPostProcessor接口与 BeanPostProcessor接口类似,可以对bean的定义(配置元数据)进行处理;也就是spring ioc运行BeanFactoryPostProcessor在容器实例化任何其他的bean之前读取配置元数据,并有可能修改它;如果业务需要,可以配置多个BeanFactoryPostProcessor的实现类,通过”order”控制执行次序(要实现Ordered接口)。
自定义一个实现类:实现bean的定义的信息修改。

/**
 * 和BeanPostProcessor原理一致,Spring提供了对BeanFactory进行操作的处理器BeanFactoryProcessor,简单来说就是获取容器BeanFactory,这样就可以在真正初始化bean之前对bean做一些处理操作。
 * 允许我们在工厂里所有的bean被加载进来后但是还没初始化前,对所有bean的属性进行修改也可以add属性值。
 * **/
@Component
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor{

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // TODO Auto-generated method stub
        System.out.println("postProcessBeanFactory");
        //获取BeanDefinition   
       /* TestService testService = (TestService) beanFactory.getBean("testServiceImpl");  
        //System.out.println("得到 testService ");
        testService.doMessage(); */

        BeanDefinition beanDefinition = beanFactory.getBeanDefinition("myTestBean");
        System.out.println("修改属性name值");
        beanDefinition.getPropertyValues().add("name", "liSi");


    }

}

执行时机是:refresh()==》invokeBeanFactoryPostProcessors(beanFactory);

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
				// 省略部分代码
				postProcessBeanFactory(beanFactory);
				invokeBeanFactoryPostProcessors(beanFactory);
				// 省略部分代码
				}
			}

4、InitializingBean
InitializingBean接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候都会执行该方法。

import org.springframework.beans.factory.InitializingBean;
@Component
public class TestInitializingBean implements InitializingBean{
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("ceshi InitializingBean");        
    }
    public void testInit(){
        System.out.println("ceshi init-method");        
    }
}

Spring为bean提供了两种初始化bean的方式,实现InitializingBean接口,实现afterPropertiesSet方法,或者在配置文件中通过init-method指定,两种方式可以同时使用。
这里调用时机:
AbstractAutowireCapableBeanFactory==》doCreateBean()==》initializeBean()=>invokeInitMethods()。
5、ApplicationListener
ApplicationListener是Spring事件机制的一部分,与抽象类ApplicationEvent类配合来完成ApplicationContext的事件机制。

如果容器中存在ApplicationListener的Bean,当ApplicationContext调用publishEvent方法时,对应的Bean会被触发。这一过程是典型的观察者模式的实现。

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

	/**
	 * Handle an application event.
	 * @param event the event to respond to
	 */
	void onApplicationEvent(E event);

}

6、ImportBeanDefinitionRegistrar
Spring官方通过ImportBeanDefinitionRegistrar实现了 Bean 的动态注入。
很多三方框架集成Spring的时候,都会通过该接口,实现扫描指定的类,然后注册到spring容器中。 比如Mybatis中的Mapper接口,springCloud中的FeignClient接口,都是通过该接口实现的自定义注册逻辑。

public interface ImportBeanDefinitionRegistrar {
	void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
}


自定义ImportBeanDefinitionRegistrar实现类手动注册bean。

  public class HelloImportBeanDefinitionRegistrar 
          implements ImportBeanDefinitionRegistrar {

      /**
       * @Description AnnotationMetadata:当前类的注解信息;
       * BeanDefinitionRegistry:注册类,其registerBeanDefinition()可以注册bean
       * @return void
       **/
      @Override
      public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
                                          BeanDefinitionRegistry registry) {
  
          //扫描注解
          Map<String, Object> annotationAttributes = importingClassMetadata
              .getAnnotationAttributes(ComponentScan.class.getName());
          String[] basePackages = (String[]) annotationAttributes.get("basePackages");
  
          //扫描类
          ClassPathBeanDefinitionScanner scanner =
                  new ClassPathBeanDefinitionScanner(registry, false);
          TypeFilter helloServiceFilter = new AssignableTypeFilter(HelloService.class);
          
          scanner.addIncludeFilter(helloServiceFilter);
          scanner.scan(basePackages);
      }
  
  }

  @Configuration
  @ComponentScan("com.haien.import2.domain")
  @Import(HelloImportBeanDefinitionRegistrar.class)
  public class HelloConfiguration {
  
  }

三、总结。

以上这些都是Spring常用的扩展类接口和底层运行逻辑,我们可以利用这些扩展接口来让我们参与Spring容器的初始化和bean的生命周期。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值