zoukankan      html  css  js  c++  java
  • Spring注解开发(六)扩展原理

    在解析SpringIOC容器创建之前,我们先来看以下扩展原理:

    1.BeanFactoryPostProcessor

    2.BeanDefinitionRegistryPostProcessor

    3.ApplicationListener/@EventListener与SmartInitializingSingleton

    一、BeanFactoryPostProcessor  BeanFactory的后置处理器

    先看一下BeanFactoryPostProcessor源码:

    @FunctionalInterface
    public interface BeanFactoryPostProcessor {
    
    	/**
    	 * Modify the application context's internal bean factory after its standard
    	 * initialization. All bean definitions will have been loaded, but no beans
    	 * will have been instantiated yet. This allows for overriding or adding
    	 * properties even to eager-initializing beans.
    	 * @param beanFactory the bean factory used by the application context
    	 * @throws org.springframework.beans.BeansException in case of errors
    	 */
    	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
    
    }
    

    该接口中只有一个方法为postProcessBeanFactory,可以看到他的执行时机是在BeanFactoy标准初始化之后,此时所有的Bean定义信息已被加载,但是没有Bean被实例化。

    下面简单看个例子:

    配置类代码如下:

    @ComponentScan("com.practice.bean")
    @Configuration
    public class ExtConfig {
        @Bean
        public Person person(){
            return  new Person();
        }
    }

    自定义BeanFactoryPostProcessor实现类如下:

    @Component
    public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            int count = beanFactory.getBeanDefinitionCount();
            String[] names = beanFactory.getBeanDefinitionNames();
            System.out.println("bean 定义数量为:" + count);
            for (String name : names) {
                System.out.println(name);
            }
            System.out.println("打印bean定义信息完毕");
        }
    }

    测试类如下:

      @Test
        public void test01() {
            AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ExtConfig.class);
            applicationContext.close();
        }

    结果如下:

    bean 定义数量为:8
    org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    org.springframework.context.annotation.internalCommonAnnotationProcessor
    org.springframework.context.event.internalEventListenerProcessor
    org.springframework.context.event.internalEventListenerFactory
    extConfig
    myBeanFactoryPostProcessor
    person
    Person 无参构造函数被执行

    可以看出Peron的实例化在postProcessBeanFactory方法执行之后。

    那么该方法是在什么时候执行的呢?

    断点截图如下:

    可以看到执行路径如下:

    AnnotationConfigApplicationContext---refresh();
                   ——————>AbstractApplicationContext.refresh();
                             ————————>
                    // Invoke factory processors registered as beans in the context.
    				invokeBeanFactoryPostProcessors(beanFactory);

    进入invokeBeanFactoryPostProcessors(beanFactory);方法,可以大致看到执行顺序为

    1,先找到所有的BeanFactoryPostProcessor

    String[] postProcessorNames =
    				beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

    2.按照是否实现优先排序及排序接口分别放置到对应的List中,然后再去分别按序执行方法。

    二、BeanDefinitionRegistryPostProcessor Bean定义注册后置处理器

    BeanDefinitionRegistryPostProcessor 也是继承自BeanFactoryPostProcessor,但它定义了另外一个方法:

    public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
    	/**
    	 * Modify the application context's internal bean definition registry after its
    	 * standard initialization. All regular bean definitions will have been loaded,
    	 * but no beans will have been instantiated yet. This allows for adding further
    	 * bean definitions before the next post-processing phase kicks in.
    	 * @param registry the bean definition registry used by the application context
    	 * @throws org.springframework.beans.BeansException in case of errors
    	 */
    	void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
    }

    postProcessBeanDefinitionRegistry根据注释来看,它的执行时机为所有符合规则的Bean定义将要被加载,但是没有bean被实例化,简单看一个例子,我们自己实现该接口,查看它的执行流程:

    自定义实现类如下:

    @Component
    public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
        @Override
        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
            int count = registry.getBeanDefinitionCount();
            System.out.println("bean 定义数量为"+count);
            String[] beanDefinitionNames = registry.getBeanDefinitionNames();
            for (String name:beanDefinitionNames) {
                System.out.println(name);
            }
            RootBeanDefinition beanDefinition = new RootBeanDefinition();
            beanDefinition.setBeanClass(PersonDao.class);
            registry.registerBeanDefinition("PersonDao",beanDefinition);
    
        }
    
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            System.out.println("MyBeanDefinitionRegistryPostProcessor.postProcessBeanFactory被执行");
        }
    }

    配置类和测试类上一致

    测试结果如下:

    bean 定义数量为9
    org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    org.springframework.context.annotation.internalCommonAnnotationProcessor
    org.springframework.context.event.internalEventListenerProcessor
    org.springframework.context.event.internalEventListenerFactory
    extConfig
    myBeanDefinitionRegistryPostProcessor
    myBeanFactoryPostProcessor
    person
    MyBeanDefinitionRegistryPostProcessor.postProcessBeanFactory被执行
    bean 定义数量为:10
    org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    org.springframework.context.annotation.internalCommonAnnotationProcessor
    org.springframework.context.event.internalEventListenerProcessor
    org.springframework.context.event.internalEventListenerFactory
    extConfig
    myBeanDefinitionRegistryPostProcessor
    myBeanFactoryPostProcessor
    person
    PersonDao
    打印bean定义信息完毕
    Person 无参构造函数被执行

    可以看到该方法在postProcessBeanFactory方法之前执行,并且我们也可以利用postProcessBeanDefinitionRegistry为容器添加注册组件

    执行流程断点图如下:

    1.容器初始化——>2.refresh()——>invokeBeanFactoryPostProcessors(beanFactory);

    ——>PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

    getBeanFactoryPostProcessors()返回为空List,进入实际执行方法:

    1.postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);

    返回我们自定义的实现类和一个org.springframework.context.annotation.internalConfigurationAnnotationProcessor内置的配置注释处理器--ConfigurationClassPostProcessor类实现了PriorityOrdered优先排序和BeanDefinitionRegistryPostProcessor 接口,会在第一次For循环即会执行,第二次是实现了Order接口的实现类,第三次才是自定义的MyBeanDefinitionRegistryPostProcessor 。

    2.invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);

    	for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
    			postProcessor.postProcessBeanDefinitionRegistry(registry);
    		}

    执行实现的postProcessBeanDefinitionRegistry方法。

    三、ApplicationListener应用监听器

    在看ApplicationListener之前先看以下容器创建时refresh()中的两个方法:

    1.  // Initialize event multicaster for this context.为容器创建事件多播器
       initApplicationEventMulticaster();

    源代码如下:

    protected void initApplicationEventMulticaster() {
    		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    		if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
    			this.applicationEventMulticaster =
    					beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
    			if (logger.isTraceEnabled()) {
    				logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
    			}
    		}
    		else {
    			this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
    			beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
    			if (logger.isTraceEnabled()) {
    				logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
    						"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
    			}
    		}
    	}

    可以看到先从容器中获取事件多播器,如果没有获取到,则创建一个SimpleApplicationEventMulticaster,并注册到容器中。

    2.// Check for listener beans and register them. 注册事件监听器

     registerListeners();

    protected void registerListeners() {
    		// Register statically specified listeners first.
    		for (ApplicationListener<?> listener : getApplicationListeners()) {
    			getApplicationEventMulticaster().addApplicationListener(listener);
    		}
    
    		// Do not initialize FactoryBeans here: We need to leave all regular beans
    		// uninitialized to let post-processors apply to them!
    		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);
    			}
    		}
    	}

    从容器中获取类型为ApplicationListener的组件,并添加到事件多播器(派发器)中。

    在来看一个简单的事件分发布的例子:

    ApplicationListener实现类:

    @Component
    public class MyApplicationListener implements ApplicationListener<MessageEvent> {
        @Override
        public void onApplicationEvent(MessageEvent myEvent) {
            System.out.println("监听到自定义事件。。。");
            myEvent.printMsg(myEvent.getMessage());
        }
    }

    ApplicationEvent实现类:

    public class MessageEvent extends ApplicationEvent {
    
        private final String message;
    
        public MessageEvent(Object source, String message) {
            super(source);
            this.message = message;
        }
    
        public String getMessage() {
            return message;
        }
        public void printMsg(String message) {
            System.out.println(message);
        }
    }

    测试类:

      @Test
        public void test01() {
            AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ExtConfig.class);
            applicationContext.publishEvent(new MessageEvent(new Object(),"你好啊"));
            applicationContext.close();
        }

    测试结果如下:

    监听到自定义事件。。。
    你好啊

    执行流程很简单:

    publishEvent()方法进入--->

    执行getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);

    ---->invokeListener(listener, event);

    @Override
    	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    		Executor executor = getTaskExecutor();
    		for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
    			if (executor != null) {
    				executor.execute(() -> invokeListener(listener, event));
    			}
    			else {
    				invokeListener(listener, event);
    			}
    		}
    	}

    --->doInvokeListener(listener, event);

    回调listener.onApplicationEvent(event);方法,打印结果。

    3.使用注解实现事件监听。@EventListener与SmartInitializingSingleton

    先来看以下@EventListener源码:

    /** 
     * @see EventListenerMethodProcessor
     */
    @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface EventListener {

    从源码注释上我们看到了一个EventListenerMethodProcessor类,前去查看发现其实现了SmartInitializingSingleton接口,接口中

    只有一个方法:

    	/**
    	 * Invoked right at the end of the singleton pre-instantiation phase,
    	 * with a guarantee that all regular singleton beans have been created
    	 * already. {@link ListableBeanFactory#getBeansOfType} calls within
    	 * this method won't trigger accidental side effects during bootstrap.
    	 * <p><b>NOTE:</b> This callback won't be triggered for singleton beans
    	 * lazily initialized on demand after {@link BeanFactory} bootstrap,
    	 * and not for any other bean scope either. Carefully use it for beans
    	 * with the intended bootstrap semantics only.
    	 */
    	void afterSingletonsInstantiated();

    执行时机为在单实例bean预实例化阶段结束时立即调用,保证所有常规单例Bean均已创建。

    自定义方法如下:

    @Component
    public class TestListenerService {
        @EventListener
        public void  listener(ApplicationEvent event){
            System.out.println(event);
        }
    }

    还是刚才的测试类,结果如下:

    org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@3abfe836, started on Tue Nov 26 20:54:31 CST 2019]
    com.practice.bean.MessageEvent[source=java.lang.Object@4278a03f]
    监听到自定义事件。。。
    你好啊
    org.springframework.context.event.ContextClosedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@3abfe836, started on Tue Nov 26 20:54:31 CST 2019]
    

    可以看到监听到了三个事件,容器刷新,自定义事件,容器关闭事件。

    在EventListenerMethodProcessor类的afterSingletonsInstantiated()上打上断点,查看一下该方法在什么时候执行的:

    可以看到是从容器创建进入refresh()方法:---->

    // Instantiate all remaining (non-lazy-init) singletons./创建剩下的单实例Bean

    finishBeanFactoryInitialization(beanFactory);------>

    进入该方法后容器先调用getBean(beanName);方法创建好了所有剩下的单实例Bean,下面:

    // Trigger post-initialization callback for all applicable beans...
    		for (String beanName : beanNames) {
    			Object singletonInstance = getSingleton(beanName);
    			if (singletonInstance instanceof SmartInitializingSingleton) {
    				final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
    				if (System.getSecurityManager() != null) {
    					AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
    						smartSingleton.afterSingletonsInstantiated();
    						return null;
    					}, getAccessControlContext());
    				}
    				else {
    					smartSingleton.afterSingletonsInstantiated();
    				}
    			}
    		}

    再去遍历所有的Bean是否属于SmartInitializingSingleton类型,

    当beanName=org.springframework.context.event.internalEventListenerProcessor获取到EventListenerMethodProcessor实例并进入以下方法

     smartSingleton.afterSingletonsInstantiated();方法--->

    processBean(beanName, type);

    进入该方法,看下面两段代码:

    try {
    annotatedMethods = MethodIntrospector.selectMethods(targetType,(MethodIntrospector.MetadataLookup<EventListener>) method ->
    AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
    		}
    for (Method method : annotatedMethods.keySet()) {
    	for (EventListenerFactory factory : factories) {
    		if (factory.supportsMethod(method)) {
    		Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
    		ApplicationListener<?> applicationListener =
    				factory.createApplicationListener(beanName, targetType, methodToUse);
    				if (applicationListener instanceof ApplicationListenerMethodAdapter) {
    				((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
    							}
    				context.addApplicationListener(applicationListener);
    				break;
    			}
    		}
    }

    创建了一个applicationListener instanceof ApplicationListenerMethodAdapter,并添加到容器中,后序执行到:

    // Last step: publish corresponding event.

    finishRefresh();---->

    // Publish the final event.

    publishEvent(new ContextRefreshedEvent(this));通过事件多播器(派发器)发布事件。

    自定义事件是在applicationContext.publishEvent(new MessageEvent(new Object(),"你好啊"));

    容器关闭是在调用applicationContext.close();方法-->publishEvent(new ContextClosedEvent(this));

  • 相关阅读:
    Mono和IL2Cpp
    axios无法获取响应头headers的ContentDisposition
    elcascader(联机选择器)动态加载+编辑默认值回显
    Vue ElTree 拖拽排序方法(通用)
    Postman保存token并使用token的整个流程
    python 使用exec执行定义好的方法,提示“name 'XXX' is not defined”
    Python+flask+flaskapscheduer实现定时下发任务
    androidtools下的uiautomatorviewer截图,提示“Unexpected error while obtaining UI hierarchy”
    python 插入mysql数据库字符串中含有单引号或双引号报错
    python 根据传进来的参数,动态拼接sql
  • 原文地址:https://www.cnblogs.com/demo-alen/p/13547227.html
Copyright © 2011-2022 走看看