5、扩展知识之spring一些重要接口和类的使用

  • 前面知道BeanPostProcessor是bean后置处理器,bean创建对象初始化前后进行拦截工作的,下面将介绍几种重要的类和接口。

1、BeanFactoryPostProcessor

  • beanFactory的后置处理器,在BeanFactory标准初始化之后调用,来定制和修改BeanFactory的内容;此时所有的bean定义已经保存加载到beanFactory,但是bean的实例还未创建。
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("MyBeanFactoryPostProcessor...postProcessBeanFactory...");
//当前容器中定义的bean个数
        int count = beanFactory.getBeanDefinitionCount();
        String[] names = beanFactory.getBeanDefinitionNames();
        System.out.println("当前BeanFactory中有"+count+" 个Bean");
        System.out.println(Arrays.asList(names));
    }

}
  • 原理
    查看AbstractApplicationContext.refresh方法中的有这么一段代码,
    invokeBeanFactoryPostProcessors(beanFactory),这里面主要做了找到所有的BeanFactoryPostProcessor,并执行他们的方法。特点:
    1)、直接在BeanFactory中找到所有类型是BeanFactoryPostProcessor的组件,并执行他们的方法
    2)、在初始化创建其他组件前面执行
  • invokeBeanFactoryPostProcessors(beanFactory)中
// Finally, invoke all other BeanFactoryPostProcessors.
        List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
        for (String postProcessorName : nonOrderedPostProcessorNames) {
            nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
        }
    invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
  • invokeBeanFactoryPostProcessors中
private static void invokeBeanFactoryPostProcessors(
            Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {

        for (BeanFactoryPostProcessor postProcessor : postProcessors) {
            postProcessor.postProcessBeanFactory(beanFactory);
        }
    }

2、BeanDefinitionRegistryPostProcessor

  • 继承于BeanFactoryPostProcessor,优先于BeanFactoryPostProcessor执行,利用BeanDefinitionRegistryPostProcessor给容器中再额外添加一些组件;
@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor{
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("MyBeanDefinitionRegistryPostProcessor...bean的数量:"+beanFactory.getBeanDefinitionCount());
    }
    //BeanDefinitionRegistry Bean定义信息的保存中心,以后BeanFactory就是按照BeanDefinitionRegistry里面保存的每一个bean定义信息创建bean实例;
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        System.out.println("postProcessBeanDefinitionRegistry...bean的数量:"+registry.getBeanDefinitionCount());
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Blue.class).getBeanDefinition();
        registry.registerBeanDefinition("hello", beanDefinition);
    }
}
  • 原理:

原理:
1)、ioc创建对象
2)、refresh()-》invokeBeanFactoryPostProcessors(beanFactory);
3)、从容器中获取到所有的BeanDefinitionRegistryPostProcessor组件。
1、依次触发所有的postProcessBeanDefinitionRegistry()方法
2、再来触发postProcessBeanFactory()方法BeanFactoryPostProcessor;
4)、再来从容器中找到BeanFactoryPostProcessor组件;然后依次触发postProcessBeanFactory()方法

  • invokeBeanFactoryPostProcessors(beanFactory)方法中
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
            boolean reiterate = true;
            while (reiterate) {
                reiterate = false;
                postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
                for (String ppName : postProcessorNames) {
                    if (!processedBeans.contains(ppName)) {
                        BeanDefinitionRegistryPostProcessor pp = beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class);
                        registryPostProcessors.add(pp);
                        processedBeans.add(ppName);
    //触发postProcessBeanDefinitionRegistry方法     
    pp.postProcessBeanDefinitionRegistry(registry);
                        reiterate = true;
                    }
                }
            }

// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
//然后触发postProcessBeanFactory方法          invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory);

3、ApplicationListener

  • spring监听容器中发布的事件。事件驱动模型开发
  • 源码:
//是一个函数式接口
//用于监听 ApplicationEvent 及其下面的子事件
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends 
EventListener {
    void onApplicationEvent(E event);
}
  • 使用案例:
步骤:
1)、写一个监听器(ApplicationListener实现类)来监听某个事件(ApplicationEvent及其子类)
@EventListener;原理:使用EventListenerMethodProcessor处理器来解析方法上的@EventListener
2)、把监听器加入到容器;
3)、只要容器中有相关事件的发布,我们就能监听到这个事件;
ContextRefreshedEvent:容器刷新完成(所有bean都完全创建)会发布这个事件;
ContextClosedEvent:关闭容器会发布这个事件;
4)、发布一个事件:
applicationContext.publishEvent();
实例:
1、自定义事件监听器
@Component
public class MyApplicationListener implements ApplicationListener<ApplicationEvent> {
    //当容器中发布此事件以后,方法触发
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println("收到事件:"+event);
    }
}

--》测试:
    public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext  = new 
AnnotationConfigApplicationContext(ExtConfig.class);
//关闭容器
        applicationContext.close();
    }
/*
在容器中注册后测试,结果是:
收到事件:org.springframework.context.event.ContextRefreshedEvent...
收到事件:org.springframework.context.event.ContextClosedEvent...
其中:
ContextRefreshedEvent:容器刷新完成(所有bean都完全创建)会发布这个事件;
ContextClosedEvent:关闭容器会发布这个事件;
*/
2、在测试中自己发布事件或自定义一个事件发布器
    //发布事件;
applicationContext.publishEvent(new ApplicationEvent(new String("我发布的时间")) {});
//测试结果:
收到事件:com.huya.qiu.ext.IOCTest_Ext$1[source=我发布的时间]
  • spring监听器原理:
    (1)事件的执行顺序:

事件的执行顺序:
1)、ContextRefreshedEvent事件:
  1)、容器创建对象:refresh();
  2)、finishRefresh();容器刷新完成会发布ContextRefreshedEvent事件
2)、自己发布事件;
3)、容器关闭会发布ContextClosedEvent;

(2)事件发布的流程源码解读:

事件发布的流程源码解读:
1、AnnotationConfigApplicationContext构造器里面的refresh方法
2、AbstractApplicationContext.refresh方法里面的finishRefresh();方法
3、AbstractApplicationContext.finishRefresh方法里面的publishEvent方法
4、在publishEvent中获取ApplicationEventMulticaster事件多发器,并执行事件多发器的
multicastEvent方法,也就是将给定的应用程序事件广播到适当的监听器,该方法如下:
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
//遍历容器中定义的事件监听器
        for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
//如果有异步的事件监听器就调用异步的事件监听器
            Executor executor = getTaskExecutor();
            if (executor != null) {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        invokeListener(listener, event);
                    }
                });
            }
            else {
  //调用事件监听器
                invokeListener(listener, event);
            }
        }
    }
5、调用invokeListener(ApplicationListener listener, ApplicationEvent event)方法
protected void invokeListener(ApplicationListener listener, ApplicationEvent event) {
        ErrorHandler errorHandler = getErrorHandler();
        if (errorHandler != null) {
            try {
                listener.onApplicationEvent(event);
            }
            catch (Throwable err) {
                errorHandler.handleError(err);
            }
        }
        else {
            try {
      //处理监听器监听到的事件
                listener.onApplicationEvent(event);
            }
            catch (ClassCastException ex) {
                // Possibly a lambda-defined listener which we could not resolve the generic event type for
                LogFactory.getLog(getClass()).debug("Non-matching event type for listener: " + listener, ex);
            }
        }
    }

(3)事件多播器(派发器)的创建

1、AnnotationConfigApplicationContext构造器里面的refresh方法
2、里面的initApplicationEventMulticaster();为容器初始化事件多发器
protected void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//先去容器中找有没有id=“applicationEventMulticaster”的组件;
        if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
            this.applicationEventMulticaster =
                    beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
            if (logger.isDebugEnabled()) {
                logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
            }
        }
        else {
//如果没有this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
//并且加入到容器中,我们就可以在其他组件要派发事件,自动注入这个applicationEventMulticaster;
            this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
            beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
            if (logger.isDebugEnabled()) {
                logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
                        APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
                        "': using default [" + this.applicationEventMulticaster + "]");
            }
        }
    }

(4)容器中注册相应的事件监听器

1、AnnotationConfigApplicationContext构造器里面的refresh方法
2、里面的registerListeners();效验监听器并把他们注册到容器中
protected void registerListeners() {
//从容器中拿到所有的监听器,把他们注册到applicationEventMulticaster中;
        for (ApplicationListener<?> listener : getApplicationListeners()) {
            getApplicationEventMulticaster().addApplicationListener(listener);
        }

//根据类型获取容易中多有注册的监听器,并注册到容器中
        String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
        for (String listenerBeanName : listenerBeanNames) {
            getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
        }

        // Publish early application events now that we finally have a multicaster...
        Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
        this.earlyApplicationEvents = null;
        if (earlyEventsToProcess != null) {
            for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
                getApplicationEventMulticaster().multicastEvent(earlyEvent);
            }
        }
    }
  • 采用注解的形式来扩展监听器的使用(也就说更加方便而不需实现接口了)
1、@EventListener原理:使用EventListenerMethodProcessor处理器来解析方法上的@EventListener
2、案例
@Service
public class UserService {
    @EventListener(classes={ApplicationEvent.class})
    public void listen(ApplicationEvent event){
        System.out.println("UserService。。监听到的事件:"+event);
    }
}
3、解析原理源码解读
(1)EventListenerMethodProcessor处理器
//实现了SmartInitializingSingleton接口和ApplicationContextAware接口
public class EventListenerMethodProcessor implements SmartInitializingSingleton
, ApplicationContextAware
(2)SmartInitializingSingleton 接口
public interface SmartInitializingSingleton {
//在所有的单实例都完成初始化后触发
    void afterSingletonsInstantiated();
}
(3)出发原理
1)ioc容器创建对象并refresh();
2)finishBeanFactoryInitialization(beanFactory)方法,初始化剩下的单实例bean;
3)beanFactory.preInstantiateSingletons();初始化剩下的单实例bean;
*先创建所有的单实例bean;getBean()
*获取所有创建好的单实例bean,判断是否是SmartInitializingSingleton类型的;如果是就调用afterSingletonsInstantiated();
4)smartSingleton.afterSingletonsInstantiated()
public void afterSingletonsInstantiated() {
        List<EventListenerFactory> factories = getEventListenerFactories();
        String[] beanNames = this.applicationContext.getBeanNamesForType(Object.class);
        for (String beanName : beanNames) {
            if (!ScopedProxyUtils.isScopedTarget(beanName)) {
                Class<?> type = null;
                try {
                    type = AutoProxyUtils.determineTargetClass(this.applicationContext.getBeanFactory(), beanName);
                }
                catch (Throwable ex) {
                    // An unresolvable bean type, probably from a lazy bean - let's ignore it.
                    if (logger.isDebugEnabled()) {
                        logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
                    }
                }
                if (type != null) {
                    if (ScopedObject.class.isAssignableFrom(type)) {
                        try {
                            type = AutoProxyUtils.determineTargetClass(this.applicationContext.getBeanFactory(),
                                    ScopedProxyUtils.getTargetBeanName(beanName));
                        }
                        catch (Throwable ex) {
                            // An invalid scoped proxy arrangement - let's ignore it.
                            if (logger.isDebugEnabled()) {
                                logger.debug("Could not resolve target bean for scoped proxy '" + beanName + "'", ex);
                            }
                        }
                    }
                    try {
//获取实例bean的@EventListener并注册并在容器中注册该监听器
                        processBean(factories, beanName, type);
                    }
                    catch (Throwable ex) {
                        throw new BeanInitializationException("Failed to process @EventListener " +
                                "annotation on bean with name '" + beanName + "'", ex);
                    }
                }
            }
        }
    }
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容

  • “又回到最初的起点,静静的站在井字前……”这首歌是高中时候喜欢的,叫《北京东路的日子》,很多人都听过,但不知道有多...
    Fo念及他名阅读 370评论 0 0