Spring容器扩展机制及实现原理

一、利用后置处理器扩展Spring容器

Bean后置处理器(BeanPostProcessor 接口)

如果希望在Spring容器完成实例化、配置和初始化bean之后实现某些自定义逻辑, 则可以实现一个或多个 BeanPostProcessor 接口。BeanPostProcessor中有两个抽象方法:

  • postProcessBeforeInitialization方法:在初始化方法(InitializingBean的afterPropertiesSet、init-method指定的方法等)之前调用
  • postProcessAfterInitialization方法:在初始化方法(InitializingBean的afterPropertiesSet、init-method指定的方法等)之后调用
/**
 * 后置处理器:初始化前后进行处理工作
 */
@Component //将后置处理器加入容器中
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization"+beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization"+beanName);
        return bean;
    }
}

BeanPostProcessor中的方法何时别执行?在refresh()方法中调用finishBeanFactoryInitialization(beanFactory), 直到org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory
类的doCreateBean方法,该方法中有以下代码:

//给bean属性赋值
populateBean(beanName, mbd, instanceWrapper);
initializeBean(beanName, exposedObject, mbd);

initializeBean方法瞟一眼,内容大致如下:

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
	if (System.getSecurityManager() != null) {
		AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
			invokeAwareMethods(beanName, bean);
			return null;
		}, getAccessControlContext());
	}
	else {
		invokeAwareMethods(beanName, bean);
	}

	...
	//遍历容器中所有的BeanPostProcessor,依次执行postProcessBeforeInitialization,一旦返回null,
//就跳出for循环,不会执行后面的BeanPostProcessor.postProcessBeforeInitialization方法
	applyBeanPostProcessorsBeforeInitialization(bean, beanName);
	//执行初始化
	invokeInitMethods(beanName, wrappedBean, mbd);
	// 与applyBeanPostProcessorsBeforeInitialization方法类似
	applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
	...
	return wrappedBean;
}

/**
 * 在调用invokeInitMethods方法前调用,处理给中Aware接口
 */
private void invokeAwareMethods(final String beanName, final Object bean) {
	if (bean instanceof Aware) {
		if (bean instanceof BeanNameAware) {
			((BeanNameAware) bean).setBeanName(beanName);
		}
		if (bean instanceof BeanClassLoaderAware) {
			ClassLoader bcl = getBeanClassLoader();
			if (bcl != null) {
				((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
			}
		}
		if (bean instanceof BeanFactoryAware) {
			((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
		}
	}
}

invokeInitMethods方法

protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd) throws Throwable {
	...
	((InitializingBean)bean).afterPropertiesSet();
	...
	invokeCustomInitMethod(beanName, bean, mbd); //通过反射执行
	...
}

InitializingBean和init-method可以一起使用,Spring总是先执行InitializingBean的.afterPropertiesSet方法,然后才处理init-method。如果在Spirng处理InitializingBean时出错,那么Spring将直接抛出异常,不会再继续处理init-method。

Ordered 接口与@Order 注解

此接口只有一个方法 int getOrder() 用来设置执行顺序。如果实现多个 BeanPostProcessor 接口, 我们就可以实现 Ordered 接口来设置执行顺序.

@Component
public class Test implements BeanPostProcessor, Ordered {
 
  @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    return bean;
  }
 
  @Override
  public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    return bean;
  }
 
  @Override
  public int getOrder() {
    return 1;
  }
}

也可以使用 @Order 注解进行排序·

@Configuration
@Order(2)
public class Demo1Config {
  @Bean
  public Demo1Service demo1Service(){
    System.out.println("demo1config 加载了");
    return new Demo1Service();
  }
 
}

设置数值越小优先级越高.

容器后处理器(BeanFactoryPostProcessor 接口)

BeanPostProcessor是bean后置处理器,bean创建对象初始化前后进行拦截工作。
BeanFactoryPostProcessor是beanFactory的后置处理器;在BeanFactory标准初始化之后调用,也就是所有的bean定义已经保存加载到beanFactory,但是bean的实例还未创建。

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor{

    //这个方法会在bean实例创建之前调用
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("postProcessBeanFactory...");
        String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
        int beanDefinitionCount = beanFactory.getBeanDefinitionCount();
        System.out.println("当前beanFactory中有"+ beanDefinitionCount +"个bean,这些bean的名字是"+Arrays.toString(beanDefinitionNames));   
    }
}

BeanFactoryPostProcessor原理:

1)容器创建时调用refresh()方法
2) invokeBeanFactoryPostProcessor(beanFactory),直接在beanFactory中找到所有类型是BeanFactoryPostProcessor的组件,并执行它们的方法,这是在初始化创建其他组件之前执行的。

BeanFactoryPostProcessor 子接口 BeanDefinitionRegistryPostProcessor

BeanDefinitionRegistryPostProcessor是一个接口继承BeanFactoryPostProcessor
BeanDefinitionRegistryPostProcessorpostProcessBeanDefinitionRegistry();这个方法是在所有bean定义信息将要被加载,bean实例还未创建是执行;

  • 优先于BeanFactoryPostProcessor执行;
  • 利用BeanDefinitionRegistryPostProcessor给容器中再额外添加一些组件
@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor{

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        int beanDefinitionCount = beanFactory.getBeanDefinitionCount();
        System.out.println("当前beanFactory中有"+ beanDefinitionCount +"个bean");
        
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        System.out.println("当前beanFactory中有"+ registry.getBeanDefinitionCount() +"个bean");
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Dog.class).getBeanDefinition();
        registry.registerBeanDefinition("newAddBean", beanDefinition);   
    }
}

原理:

  1. ioc容器创建执行refresh()方法
  2. refresh()方法中调用invokeBeanFactoryPostProcessors(beanFactory)
  3. 从容器中获取到所有的BeanDefinitionRegisryPostProcessor组件,依次触发所有的postProcessBeanDefinitionRegistry()方法,
  4. 再从容器中找到BeanFactoryPostProcessor组件,然后依次触发postProcessBeanFactory()方法

二、ApplicationListener

监听容器发布的事件,实现一个监听器的步骤:

  1. 编写一个监听器(实现ApplicationListener类)来监听某个事件(ApplicationEvent极其子类)
  2. 把监听器加入到容器中
  3. 只要容器中有相关事件发布,就能监听到这个事件
    ContextRefreshedEvent : 容器刷新完成(所有bean都完成创建)会发布这个事件
    ContextClosedEvent : 关闭容器会发布这个事件
  4. 手动发布一个事件:applicationContext.publishEvent()
@Component
public class MyApplicationListener implements ApplicationListener<ApplicationEvent>{

    //当容器中发布此事件,方法会得到触发
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println("收到事件:"+event);   
    }
}

事件发布流程:

在refresh()方法中执行publishEvent(new ContextRefreshedEvent(this));

  1. 获取事件的多播器(派发器):getApplicationEventMulticaster(), 容器创建refresh()方法initAppicationEventMulticaster()初始化ApplicationEventMulticaster。
  2. multicastEvent派发事件
  3. 获取到所有的ApplicationListenr,如果有Executor,可以支持Executor进行异步派发;同步方式直接执行listener()方法,依次调用onApplicationEvent方法

@Listener注解
这个注解标在方法上spring在启动的时候就会将这个方法创建成一个监听器

@Service
public class ListenerService {

    @EventListener(classes= {ApplicationEvent.class})
    public void Listener(ApplicationEvent event) {
        System.out.println("@EventListener收到事件:"+event);
    }
}

@Listener的原理

  1. @EventListener 使用EventListenerMethodProcessor处理器来解析方法上的@EventListener注解

  2. EventListenerMethodProcessor实现了SmartInitializingSingleton

  3. SmartInitializingSingleton 原理:
    1 、ioc容器创建对象并refresh()
    2 、finishBeanFactoryInitialization(beanFactory);初始化剩下的单实例bean;
    先创建所有的单实例bean;再获取所有创建好的单实例bean,判断是否是SmartInitializingSingleton类型的,如果是调用afterSingletonSInstantiated();

三、获取容器底层组件(各种Aware)

自定义组件想要使用Spring容器底层的一些组件(ApplicationContext, Environment,BeanFactory等),自定义组件需要实现XXXAware接口(继承Aware接口),在创建对象的时候,Spring会调用接口规定的方法注解相关组件,把Spring底层的一些组件注入到自定义的Bean中。

@Component
public class Boss implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware {

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("bean名称:"+name);
    }

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        String stringValue = resolver.resolveStringValue("你好${os.name},我是#{18*20}");
        System.out.println(stringValue);
    }
}

ApplicationContextAware 的处理器就是 ApplicationContextAwareProcessor,ApplicationContextAwareProcessor是一种BeanPostProcessor。前文提到BeanPostProcessor发生在bean初始化前后,在bean初始化之前将调用postProcessBeforeInitialization方法,ApplicationContextAwareProcessor的postProcessBeforeInitialization如下:

public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
        AccessControlContext acc = null;

        if (System.getSecurityManager() != null &&
                (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
                        bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
                        bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
            acc = this.applicationContext.getBeanFactory().getAccessControlContext();
        }

        if (acc != null) {
            AccessController.doPrivileged(new PrivilegedAction<Object>() {
                public Object run() {
                    invokeAwareInterfaces(bean);
                    return null;
                }
            }, acc);
        }
        else {
            invokeAwareInterfaces(bean);
        }

        return bean;
    }

    private void invokeAwareInterfaces(Object bean) {
        if (bean instanceof Aware) {
            if (bean instanceof EnvironmentAware) {
                ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
            }
            if (bean instanceof EmbeddedValueResolverAware) {
                ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(
                        new EmbeddedValueResolver(this.applicationContext.getBeanFactory()));
            }
            if (bean instanceof ResourceLoaderAware) {
                ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
            }
            if (bean instanceof ApplicationEventPublisherAware) {
                ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
            }
            if (bean instanceof MessageSourceAware) {
                ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
            }
            if (bean instanceof ApplicationContextAware) {
                ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
            }
        }
    }

可以看出ApplicationContextAwareProcessor完成了容器中特有的一些Aware的调用,发生的时机在初bean始化之前。那么ApplicationContextAwareProcesso是何时被加入容器的?

  1. 容器创建时调用refresh()方法
  2. refresh()方法调用prepareBeanFactory(beanFactory)方法
public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
            //第一步,预创建bean对象
            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {
                
                //第二步,调用invokeBeanFactoryPostProcessors(beanFactory)方法
                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);
                ...
                //初始化bean对象实例
                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);
                ...
                }
                ...
    }
  1. prepareBeanFactory(beanFactory)方法向容器中添加ApplicationContextAwareProcessor。
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

你可能感兴趣的:(Spring)