(二) springBoot 初始化器和监听器

系统初始化器介绍:

类名:ApplicationContextInitializer ;  介绍:spring容器刷新之前执行的一个回调函数;  作用:向springBoot容器注册属性; 也可以自定义初始化器来修改env, springcloud获取远程配置就是采用这个方式。使用方式:继承接口自定义实现。自定义初始化器实现的三种方式:

1 实现ApplicationContextInitializer接口,重写initialize方法。在SpringApplication类初始化后通过其addInitializers()方法设置进去

2 实现ApplicationContextInitializer接口,重写initialize方法。spring.factories内填写接口实现,key值为org.springframework.context.ApplicationContextInitializer接口

3 实现ApplicationContextInitializer接口,重写initialize方法。在application.properties内填写接口实现,key值为context.initializer.classes

以上三种实现方式都需要实现ApplicationContextInitializer接口,重写initialize方法。他们的运行顺序按order进行执行,order值越小越先执行,但是在application.properties内定义的优先于其它方式。

添加初始化器流程:

SpringFactoriesLoader介绍:

SpringFactoriesLoader工厂加载机制是 Spring 内部提供的一个约定俗成的加载方式,与 java spi 类似,只需要在模块的 META-INF/spring.factories 文件中,以 Properties 类型(即 key-value 形式)配置,就可以将相应的实现类注入 Spirng 容器中. properties的文件内容必须是kv形式,key是全限定名(抽象 | 接口) value是实现,多个实现用","分割。

SpringFactoriesLoader加载自定义初始化器如下图所示:

 

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
            Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = getClassLoader();
        // 保存结果到缓存
        Set<String> names = new LinkedHashSet<>(
                SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        // 通过反射实例化类
     List
<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
     // 对结果对象进行排序 AnnotationAwareOrderComparator.sort(instances);
return instances; }
  public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();
     //加载并获取指定key对应的value
return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList()); } private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) { MultiValueMap<String, String> result = cache.get(classLoader); if (result != null) { return result; }      // 读取指定资源配置文件 String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
     
try { Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); result = new LinkedMultiValueMap<>(); while (urls.hasMoreElements()) { URL url = urls.nextElement(); UrlResource resource = new UrlResource(url);
          //构造properties Properties properties
= PropertiesLoaderUtils.loadProperties(resource); for (Map.Entry<?, ?> entry : properties.entrySet()) { String factoryClassName = ((String) entry.getKey()).trim(); for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) { result.add(factoryClassName, factoryName.trim()); } } } cache.put(classLoader, result); return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } }

应用初始化器源码:


//类 SpringApplication
private void prepareContext(ConfigurableApplicationContext context,
            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments, Banner printedBanner) {
        context.setEnvironment(environment);
        postProcessApplicationContext(context);
        applyInitializers(context);
        listeners.contextPrepared(context);
        if (this.logStartupInfo) {
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
        }
        // Add boot specific singleton beans
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
        if (printedBanner != null) {
            beanFactory.registerSingleton("springBootBanner", printedBanner);
        }
        if (beanFactory instanceof DefaultListableBeanFactory) {
            ((DefaultListableBeanFactory) beanFactory)
                    .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
        // Load the sources
        Set<Object> sources = getAllSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        load(context, sources.toArray(new Object[0]));
        listeners.contextLoaded(context);
    }
protected void applyInitializers(ConfigurableApplicationContext context) {
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
initializer.getClass(), ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}
 

详情可参考:SpringFactoriesLoader详解(https://blog.csdn.net/zs18753479279/article/details/116404217

事件监听器:

监听模式:springBoot的事件监听,是观察者模式的一种应用。当系统有重大事件发生时,会通过广播器将事件发出,而系统的部分监听器是对一些事件感兴趣的,当这部分事件被发布出来后,监听器会监听到,从而触发一些动作。

监听器四要素:监听器、广播器、监听事件、监听事件触发机制

springBoot的事件发布是在run方法中实现的,首先通过SpringApplicationRunListeners listeners = getRunListeners(args)方法获得用于发射SpringBoot启动过程中的各种生命周期事件的对象SpringApplicationRunListeners,而getRunListeners方法内部会利用SPI机制,通过getSpringFactoriesInstance方法把SpringApplicationRunListener的实现类EventPublishingRunListener加载进来

private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
				SpringApplicationRunListener.class, types, this, args));
	}

SpringApplicationRunListeners是如何发射事件的呢?

其实SpringApplicationRunListeners对象没有承担广播事件的职责,而最终是委托EventPublishingRunListener来广播事件的。那么广播的事件从哪里来?

当从spring.factories中加载出EventPublishingRunListener类后会实例化,而实例化必然会通过EventPublishingRunListener的构造函数来进行实例化,从下面的源码可以看到在EventPublishingRunListener的构造函数中有一个for循环会遍历之前从spring.factories中加载的监听器,然后添加到集合中缓存起来,用于以后广播各种事件时直接从这个集合中取出来即可,而不用再去spring.factories中加载,提高效率。

public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {

    private final SpringApplication application;

    private final String[] args;

    private final SimpleApplicationEventMulticaster initialMulticaster;

    public EventPublishingRunListener(SpringApplication application, String[] args) {
        this.application = application;
        this.args = args;
        // 新建一个事件广播对象
        this.initialMulticaster = new SimpleApplicationEventMulticaster();
        for (ApplicationListener<?> listener : application.getListeners()) {
            // 将从spring.factories配置文件中获取获取的监听器加入到事件广播器的缓存之中
       this.initialMulticaster.addApplicationListener(listener);
        }
    }

    @Override
    public int getOrder() {
        return 0;
    }

    @Override
    public void starting() {
        this.initialMulticaster.multicastEvent(
                new ApplicationStartingEvent(this.application, this.args));
    }

    @Override
    public void environmentPrepared(ConfigurableEnvironment environment) {
        this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(
                this.application, this.args, environment));
    }

    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        this.initialMulticaster.multicastEvent(new ApplicationContextInitializedEvent(
                this.application, this.args, context));
    }

    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        for (ApplicationListener<?> listener : this.application.getListeners()) {
            if (listener instanceof ApplicationContextAware) {
                ((ApplicationContextAware) listener).setApplicationContext(context);
            }
            context.addApplicationListener(listener);
        }
        this.initialMulticaster.multicastEvent(
                new ApplicationPreparedEvent(this.application, this.args, context));
    }

    @Override
    public void started(ConfigurableApplicationContext context) {
        context.publishEvent(
                new ApplicationStartedEvent(this.application, this.args, context));
    }

    @Override
    public void running(ConfigurableApplicationContext context) {
        context.publishEvent(
                new ApplicationReadyEvent(this.application, this.args, context));
    }

    @Override
    public void failed(ConfigurableApplicationContext context, Throwable exception) {
        ApplicationFailedEvent event = new ApplicationFailedEvent(this.application,
                this.args, context, exception);
        if (context != null && context.isActive()) {
            // Listeners have been registered to the application context so we should
            // use it at this point if we can
            context.publishEvent(event);
        }
        else {
            // An inactive context may not have a multicaster so we use our multicaster to
            // call all of the context's listeners instead
            if (context instanceof AbstractApplicationContext) {
                for (ApplicationListener<?> listener : ((AbstractApplicationContext) context)
                        .getApplicationListeners()) {
                    this.initialMulticaster.addApplicationListener(listener);
                }
            }
            this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
            this.initialMulticaster.multicastEvent(event);
        }
    }

    private static class LoggingErrorHandler implements ErrorHandler {

        private static Log logger = LogFactory.getLog(EventPublishingRunListener.class);

        @Override
        public void handleError(Throwable throwable) {
            logger.warn("Error calling ApplicationEventListener", throwable);
        }

    }

}

springBoot启动过程中会调用spingApplicationRunListeners的如下方法发布事件

 

以发送starting事件为例来说明一下发布事件,到执行listener的具体方法为例:

发送事件的场景分别如下:

a 框架在刚启动的时候会发送一个starting事件

b 在环境准备好的时候(把一些系统属性与自定义属性加载到了容器中)会发送environmentPrepared事件

c 在当应用上下文(ApplicationContext)准备好了,并且应用初始化器(ApplicationContextInitializers)已经被调用,在 bean 的定义(bean definitions)被加载之前发送contextInitinized事

d Spring 上下文(context)刷新之前,且在 bean 的定义(bean definitions)被加载之后发送contextPrepared事件

e Spring 上下文(context)刷新之后,单例Bean实例化完成,且在 application/ command-line runners 被调用之前发送started事件。

f 在任何 application/ command-line runners 调用之后发送ready事件。


1 实现ApplicationListener接口,spring.factories内填写接口实现,key值为org.springframework.context.ApplicationListener

2 实现ApplicationListener接口,通过springApplication的addListeners方法加入进去

3 实现ApplicationListener接口,application.properties内填写接口实现,key值为org.springframework.context.ApplicationListener

4 实现SmartApplicationListener接口,重写supportEventType方法与onApplicationEvent方法,同之前三种方式注入框架

总结:

SpringBoot的初始化器与监听器都是通过SpringFactoriesLoader加载的,其原理是利用JAVA的SPI机制,去META-INF/spring.factories加载对应的接口实现类。初始化器在准备上下文prepareContext时执行。监听器是执行run方法的时候通过springRunApplicationListener触发,然后委托给实现类eventPlublisingRunListener,由这个事件广播器广播一个事件,进而调用与该事件类型匹配的监听器的回调方法,最后监听器执行onApplicationEvent方法完成监听器的响应。

 

 springBoot的Bean:

xml文件配置方式:

1 无参构造:属性需要有set方法,xml property配置属性值

2 有参构造:参数通过constructor-arg属性配置

3静态工厂方法:xml  class属性指定静态工厂类,factory-method指定工厂方法

4实例工厂方法:xml factory-bean指定工厂实例,factory-method指定工厂方法。

注解配置方式:

1 @Compent声明   

2 配置类中使用@Bean  

@Configuration
public class BeanConfiguration{

    @Bean("dog")
    Animal getDog() {
        return new Dog();
    }
}

3 继承FactoryBean,重写getObjects方法与getObjectType方法

@Component
public class MyCat implements FactoryBean<Animal> {
    @Override
    public Animal getObject() throws Exception {
        return new Cat();
    }

    @Override
    public Class<?> getObjectType() {
        return Animal.class;
    }
}

4 实现BeanDefinitionRegistryPostProcessor接口,重写postProcessBeanDefinitionRegistry与postProcessBeanFactory方法

@Component
public class MyBeanRegister implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
        rootBeanDefinition.setBeanClass(Monkey.class);
        registry.registerBeanDefinition("monkey", rootBeanDefinition);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    }
}


public class Monkey extends Animal {
    @Override
    String getName() {
        return "monkey";
    }
}

5 实现ImportBeanDefinitionRegistrar接口,重写registerBeanDefinitions方法

public class MyBeanImport implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
        rootBeanDefinition.setBeanClass(Bird.class);
        registry.registerBeanDefinition("bird", rootBeanDefinition);
    }
}

 

springBoot Aware介绍

Spring框架优点:Bean感知不到容器的存在

使用场景:需要使用spring容器的功能资源

引入缺点:容器和bean强耦合

常用Aware:

类名 作用
BeanNameAware

获得容器中bean的名称

BeanClassLoaderAware 获得类加载器
BeanFactoryAware 获得bean创建工厂
EnvironmentAware 获得环境变量
EmbeddedValueResolverAware 获取spring容器加载的properties文件属性值
ResourcedLoaderAware 获得资源加载器
ApplicationEventPublisherAware 获得应用事件发布器
MessageSourceAware

获得文本信息

ApplicationContextAware 获得当前应用上下文

springBoot启动加载器:

@Component
@Order(1)
public class FirstApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("\u001B[32m >>> startup first application runner<<<");
    }
}
@Component
@Order(1)
public class FirstCommandlineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("\u001B[32m >>> startup first runner<<<");
    }
}

 

posted @ 2022-10-11 21:50  小兵要进步  阅读(328)  评论(0编辑  收藏  举报