Spring boot监听器、启动器、异步调用、bean定义

Spring boot异步调用

package com.yasuo.application.listener;

import com.yasuo.application.event.YasuoApplicationEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;

/**
 * @desc: 用@EventListener装饰具体方法  然后将监听器加入spring容器中
 * @auther: MateEgg
 * @date: 2018/9/24 01:39
 * @version: 1.0
 */
@Slf4j
@EnableAsync
@Component
public class YasuoApplicationListenerThree {

    /**
     * @param yasuoApplicationEvent
     * @annotation Async表示异步方法 此方法被调用的时候异步执行
     */
    @Async
    @EventListener
    public void onApplicationEvent(YasuoApplicationEvent yasuoApplicationEvent) throws InterruptedException {
        for (int i = 0; i < 100; i++) {
            log.info("YasuoApplicationListenerThree is executing...{}", i);
            Thread.currentThread().sleep(1000);
        }

    }
}

Spring boot的事件监听机制

除了通常的Spring Framework事件之外,例如 ContextRefreshedEventSpringApplication发送一些额外的应用程序事件。

某些事件实际上是在ApplicationContext创建之前触发的,因此您无法在这些事件上注册侦听器@Bean。您可以使用SpringApplication.addListeners(…)方法或 SpringApplicationBuilder.listeners(…)方法注册它们 。

如果您希望自动注册这些侦听器,你可以在项目中创建META-INF/spring.factories并使用该org.springframework.context.ApplicationListener键引用侦听器 ,如以下示例所示:

org.springframework.context.ApplicationListener = com.example.project.MyListener

应用程序运行时,应按以下顺序发送应用程序事件:

  1. ApplicationStartingEvent在运行开始,但除了监听器注册和初始化以外的任何处理之前,
  2. ApplicationEnvironmentPreparedEvent在Environment将被用于已知的上下文,但在上下文被创建前,
  3. ApplicationPreparedEvent在refresh开始前,但在bean定义已被加载后,
  4. ApplicationStartedEvent上下文已被刷新后,但是任何应用程序和命令行被调用前。
  5. ApplicationReadyEvent应用程序和命令行被调用后发送。它表示应用程序已准备好为请求提供服务。
  6. ApplicationFailedEvent如果在启动时异常发送。
自定义监听器注册的几种方式:
定义事件:
package com.yasuo.application.event;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEvent;
import org.springframework.stereotype.Component;

/**
 * @desc: 继承ApplicationEvent自定义监听事件
 * @auther: MateEgg
 * @date: 2018/9/24 00:58
 * @version: 1.0
 */
public class YasuoApplicationEvent extends ApplicationEvent {

    public YasuoApplicationEvent(Object source) {
        // 父类的构造方法是对父类中的一个Object类型的字段source初始化
        super(source);
    }

}
第一种监听器注册方式:
package com.yasuo.application.listener;

import com.yasuo.application.event.YasuoApplicationEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

/**
 * @desc: 第一种监听器注册方式 利用@Component注解将其加入spring容器中
 * @auther: MateEgg
 * @date: 2018/9/24 00:57
 * @version: 1.0
 */
@Slf4j
@Component
public class YasuoApplicationListenerOne implements ApplicationListener {

    @Override
    public void onApplicationEvent(YasuoApplicationEvent yasuoApplicationEvent) {
        log.info("YasuoApplicationListenerOne is executing...");
    }
}
第二种监听器注册方式:
package com.yasuo.application.listener;

import com.yasuo.application.event.YasuoApplicationEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;

/**
 * @desc: 第二种监听器注册方式  在yaml文件中配置监听器的路径
 * @auther: MateEgg
 * @date: 2018/9/24 01:04
 * @version: 1.0
 */
@Slf4j
public class YasuoApplicationListenerTwo implements ApplicationListener {

    @Override
    public void onApplicationEvent(YasuoApplicationEvent yasuoApplicationEvent) {
        log.info("YasuoApplicationListenerTwo is executing...");
    }
}
context:
  listener:
    classes: com.yasuo.application.listener.YasuoApplicationListenerTwo
第三种监听器注册方式:
package com.yasuo.application.listener;

import com.yasuo.application.event.YasuoApplicationEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;

/**
 * @desc: 用@EventListener装饰具体方法  然后将监听器加入spring容器中
 * @auther: MateEgg
 * @date: 2018/9/24 01:39
 * @version: 1.0
 */
@Slf4j
@EnableAsync
@Component
public class YasuoApplicationListenerThree {

    /**
     * @param yasuoApplicationEvent
     * @annotation Async表示异步方法 此方法被调用的时候异步执行
     */
    @Async
    @EventListener
    public void onApplicationEvent(YasuoApplicationEvent yasuoApplicationEvent) throws InterruptedException {
        log.info("YasuoApplicationListenerThree is executing...");
    }
}
ApplicationContext发布事件:
package com.yasuo.application;

import com.yasuo.application.event.YasuoApplicationEvent;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(Application.class, args);
        run.publishEvent(new YasuoApplicationEvent("Test ApplicationListeners"));
    }
}

输出结果:
2018-09-24 04:16:31.872  INFO 17396 --- [           main] c.y.a.l.YasuoApplicationListenerOne      : YasuoApplicationListenerOne is executing...
2018-09-24 04:16:31.868  INFO 17396 --- [           main] c.y.a.l.YasuoApplicationListenerTwo      : YasuoApplicationListenerTwo is executing...
2018-09-24 04:16:31.876  INFO 17396 --- [cTaskExecutor-1] c.y.a.l.YasuoApplicationListenerThree    : YasuoApplicationListenerThree is executing...

监听spring boot事件:

配置监听器:
package com.yasuo.application.listener;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.*;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;

/**
 * @desc: 监听spring boot内置六种事件
 * @auther: MateEgg
 * @date: 2018/9/24 02:17
 * @version: 1.0
 */
@Slf4j
public class YasuoApplicationListenerFour implements ApplicationListener {

    @Override
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
        if (applicationEvent instanceof ApplicationStartingEvent) {
            //此时log.info()不会输出日志所以替换为system.out.println()
//            log.info("YasuoApplicationListenerFour is executing...{}", "ApplicationStartingEvent");
            System.out.println("Spring boot 开始启动");
            return;
        }

        if (applicationEvent instanceof ApplicationEnvironmentPreparedEvent) {
            log.info("YasuoApplicationListenerFour is executing...{}", "ApplicationEnvironmentPreparedEvent");
            return;
        }

        if (applicationEvent instanceof ApplicationPreparedEvent) {
            log.info("YasuoApplicationListenerFour is executing...{}", "ApplicationPreparedEvent");
            return;
        }

        if (applicationEvent instanceof ApplicationStartedEvent) {
            log.info("YasuoApplicationListenerFour is executing...{}", "ApplicationStartedEvent");
            return;
        }

        if (applicationEvent instanceof ApplicationReadyEvent) {
            log.info("YasuoApplicationListenerFour is executing...{}", "ApplicationReadyEvent");
            return;
        }

        if (applicationEvent instanceof ApplicationFailedEvent) {
            log.info("YasuoApplicationListenerFour is executing...{}", "ApplicationFailedEvent");
            return;
        }

        log.info("YasuoApplicationListenerFour is executing...{}", "无人认领");
    }

}
META-INF/spring.factories文件:
# Initializers
org.springframework.context.ApplicationContextInitializer=

# Application Listeners
org.springframework.context.ApplicationListener=\
com.yasuo.application.listener.YasuoApplicationListenerFour

# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=

# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=

# Failure analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=

# Template availability providers
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=
输出结果:
// 只截取了部分输出结果
Spring boot 开始启动
2018-09-24 04:21:37.735  INFO 16004 --- [           main] c.y.a.l.YasuoApplicationListenerFour     : YasuoApplicationListenerFour is executing...ApplicationEnvironmentPreparedEvent

Spring boot命令行与系统属性:

获取系统属性:
System.out.println("系统属性env=" + System.getProperty("env"));
命令行属性:

命令行属性会作为参数传给main方法

package com.yasuo.application.args;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @desc:
 * @auther: MateEgg
 * @date: 2018/9/24 04:42
 * @version: 1.0
 */
@Component
public class YasuoApplicationArguments {

    @Autowired
    public YasuoApplicationArguments(ApplicationArguments args) {
        // 判断命令行参数是否包含name sex
        boolean name = args.containsOption("name");
        boolean sex = args.containsOption("sex");
        // 根据key获取命令行参数的值
        System.out.println(args.getOptionValues("name"));
        System.out.println(args.getOptionValues("sex"));
        // 获取不规范的命令行参数  不是 --key=value 格式
        List others = args.getNonOptionArgs();
        System.out.println(others);
    }
}
获取上下文环境:

命令行属性和系统属性以及配置文件的值都是可以通过上下文环境获取

package com.yasuo.application.args;

import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

/**
 * @desc:
 * @auther: MateEgg
 * @date: 2018/9/24 05:16
 * @version: 1.0
 */
@Component
public class YasuoEnvironmentAware implements EnvironmentAware {

    @Override
    public void setEnvironment(Environment environment) {

        String env1 = System.getProperty("env");
        System.out.println("系统属性env=" + env1);
        String env = environment.getProperty("env");
        System.out.println("YasuoEnvironmentAware结果..." + environment.getProperty("env") + "..." + environment.getProperty("name"));
    }
}
动态设置系统属性:

在spring boot的启动监听事件中设置、以便属性可以在整个spring生命中被使用

System.setProperty("laji", "MateEgg");

Spring boot内部接口分析:

bean初始化顺序:

bean初始化顺序:Constructor > @PostConstruct > InitializingBean > init-method

InitializingBean   // 初始化bean  执行顺序为Constructor > @PostConstruct >InitializingBean > init-method
Aware接口:

Aware接口作用:实现Aware接口可以让bean感知到自身的在spring 框架中的特定属性

BeanNameAware // 获取bean的名称 在bean的普通属性设置之后在 InitializingBean > init-method方法之前调用
BeanFactoryAware  // 获取beanFactory实例   在bean的普通属性设置之后在 InitializingBean > init-method方法之前调用
ApplicationContextAware   // 获取ApplicationContext实例   在bean的普通属性设置之后在 InitializingBean > init-method方法之前调用
启动器的作用:
ApplicationRunner    // 在容器启动的时候执行一些内容。比如读取配置文件,数据库连接之类的    在容器启动完成时执行       --参数为ApplicationArguments
CommandLineRunner    // 在容器启动的时候执行一些内容。比如读取配置文件,数据库连接之类的    在容器启动完成时执行     --参数为String 数组    参数来源为programe command  eg:--foo=foo

ApplicationArguments 在使用时可以直接注入 @Autowired private ApplicationArguments args;

BeanFactory和FactoryBean的区别

区别:BeanFactory是个Factory,也就是IOC容器或对象工厂,FactoryBean是个Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。但对FactoryBean而言,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似 。

FactoryBean表示它是一个Bean,不同于普通Bean的是:它是实现了FactoryBean接口的Bean,根据该Bean的ID从BeanFactory中获取的实际上是FactoryBean的getObject()返回的对象,而不是FactoryBean本身,如果要获取FactoryBean对象,请在id前面加一个&符号来获取。

public interface FactoryBean {    
   T getObject() throws Exception;    
   Class getObjectType();    
   boolean isSingleton();    
} 
// 在该接口中还定义了以下3个方法。

// T getObject():返回由FactoryBean创建的bean实例,如果isSingleton()返回true,则该实例会放到Spring容器中单实例缓存池中。

// boolean isSingleton():返回由FactoryBean创建的bean实例的作用域是singleton还是prototype。

// Class getObjectType():返回FactoryBean创建的bean类型。

Spring boot中bean的动态注册:

BeanDefinitionRegistryPostProcessor:
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)    // 继承BeanDefinitionRegistryPostProcessor实现postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)可以做到动态注册bean到spring中
BeanDefinitionRegistry:
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
void removeBeanDefinition(String beanName)
BeanDefinition getBeanDefinition(String beanName)
boolean containsBeanDefinition(String beanName)
//  以Map的形式注册bean  提供了根据beanName删除和获取  beanDefiniation,得到持有的beanDefiniation的数目,根据beanName判断是否包含              beanDefiniation等的方法

SimpleBeanDefinitionRegistry是BeanDefinitionRegistry三种默认实现方式中的一种,用线程安全的ConcurrentHashMap的方式存储BeanDefinition private final Map beanDefinitionMap = new ConcurrentHashMap(64);;

BeanDefinitionBuilder:
    private void registerTransactionManagerDefinitionBuilder(String transactionManagerName, BeanDefinitionRegistry beanFactory, String dataSourceName) {
        BeanDefinitionBuilder transactionManagerDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(DataSourceTransactionManager.class);
        transactionManagerDefinitionBuilder.addPropertyReference("dataSource", dataSourceName);
        beanFactory.registerBeanDefinition(transactionManagerName, transactionManagerDefinitionBuilder.getRawBeanDefinition());
    }

// 这是BeanDefinitionBuilder的简单的使用例子,通过构造方法与要实例化的类关联,通过addPropertyReference()方法为实例化的类添加属性,通过transactionManagerDefinitionBuilder.getRawBeanDefinition()方法转化为BeanDefintion类的实例

你可能感兴趣的