笔记整理-SpringBoot中的扩展点

SpringBoot有哪些扩展点

aware 感知类接口

aware系列的扩展接口,允许spring应用感知/获取特定的上下文环境或对象。

bean生命周期控制类接口

bean生命周期类的接口,可以控制spring容器对bean的处理。

app生命周期控制类接口

app生命周期控制类接口,可以控制spring应用启动/销毁时的逻辑

下面详细介绍各种扩展点的使用

aware 感知类接口

ApplicationContextAware

package cn.test.ext.aware;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * ApplicationContextAware
 * 通过实现该接口,组件可以获取ApplicationContext对象的引用,
 * 从而访问应用程序上下文中的bean以及其他特定的spring功能
 */
@Component
@Slf4j
public class TestAppCtxAware implements ApplicationContextAware {
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        String applicationName = applicationContext.getApplicationName();
        log.info("context-path:{}",applicationName);
        String displayName = applicationContext.getDisplayName();
        log.info("displayName:{}",displayName);
        String id = applicationContext.getId();
        log.info("spring-applicationName:{}",id);
        long startupDate = applicationContext.getStartupDate();
        log.info("startupDate:{}",startupDate);
//        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
//        log.info("beanDefinitionNames:{}", Arrays.asList(beanDefinitionNames).toString());
    }
}

BeanFactoryAware

package cn.test.ext.aware;

import cn.test.web.TestController;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.stereotype.Component;

/**
 * BeanFactoryAware
 * 实现该接口,可以使自定义类获取bean工厂对象的引用,
 * 允许你在运行时从bean工厂中获取其他bean
 */
@Slf4j
@Component
public class TestBeanFactoryAware implements BeanFactoryAware {
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {

        boolean b = beanFactory.containsBean("testController");
        log.info("spring容器内是否含有 testController这个bean :{}",b);

        TestController testController =(TestController) beanFactory.getBean("testController");
        String tgwt43t = testController.t1("tgwt43t");
        log.info("get bean方式调用 TestController里的t1方法,返回值:{}",tgwt43t);

    }
}

EnvironmentAware

package cn.test.ext.aware;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * EnvironmentAware
 * 实现该接口,你的组件可以获取 Environment 环境对象的引用,
 * 从而可以访问spring应用程序的配置属性和配置文件
 */
@Component
@Slf4j
public class TestEnvironmentAware implements EnvironmentAware {

    @Override
    public void setEnvironment(Environment environment) {
        //获取当前默认的profile环境
        String[] defaultProfiles = environment.getDefaultProfiles();
        log.info("defaultProfiles:{}",Arrays.asList(defaultProfiles));
        //获取某个属性配置
        String property = environment.getProperty("spring.application.name");
        log.info("property->spring.application.name:{}",property);

    }
}

MessageSourceAware

package cn.test.ext.aware;

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

/**
 * MessageSourceAware
 * 实现该接口,你的组件可以获取 messageSource 消息源对象的引用,
 * 从而访问 国际化消息内容
 */
@Component
@Slf4j
public class TestMessageSourceAware implements MessageSourceAware {
    @Override
    public void setMessageSource(MessageSource messageSource) {
//        messageSource.getMessage()
    }
}

ResourceLoaderAware

package cn.test.ext.aware;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Component;

import java.util.Properties;

/**
 * ResourceLoaderAware
 * 实现该接口,你的组件可以获取 ResourceLoader 资源加载器 对象的引用。
 * 从而可以加载外部资源文件
 */
@Slf4j
@Component
public class TestResourceLoaderAware implements ResourceLoaderAware {
    @SneakyThrows
    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        //ResourceLoader可以加载自定义位置的自定义的properties配置文件

        //这里测试加载classpath下的test.properties文件
        Resource resource = resourceLoader.getResource("classpath:test.properties");
        if (resource.isFile()) {
            String filename = resource.getFilename();
            log.info("filename:{}",filename);
            Properties properties = new Properties();
            properties.load(resource.getInputStream());
            properties.list(System.out);
            String aaa = properties.getProperty("aaa");
            log.info("aaa-->:{}",aaa);
        }
    }
}

ServletContextAware

package cn.test.ext.aware;

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

import javax.servlet.ServletContext;

/**
 * ServletContextAware
 * 实现该接口,你的组件可以获取 ServletContext Servlet上下文对象的引用,
 * 从而访问与web应用程序相关的功能
 */
@Component
@Slf4j
public class TestServletContextAware implements ServletContextAware {
    @Override
    public void setServletContext(ServletContext servletContext) {
        //添加java web 过滤器
//        servletContext.addFilter()

        //添加java web servlet
//        servletContext.addServlet()

        //添加java web 监听器
//        servletContext.addListener();
    }
}

bean生命周期控制类接口

InitializingBean

package cn.test.ext.beanlife;

import cn.test.ext.ITestStrategy;
import cn.test.ext.MyStrategyFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

/**
 * InitializingBean
 * 实现该接口,你的bean可以在 spring容器初始化当前bean时 执行自定义逻辑
 *
 * 必须在afterPropertiesSet方法里写你自定义的执行逻辑
 */
@Slf4j
@Component
public class TestInitializingBean implements ITestStrategy, InitializingBean {

    private static String str ;

    //实现InitializingBean接口,必须重写afterPropertiesSet方法
    //这样当springboot启动加载TestInitializingBean时,会自动执行里边的afterPropertiesSet方法
    @Override
    public void afterPropertiesSet() throws Exception {
        //本方法里可以做一些初始化的操作,如设置类静态变量值 / 将类注册到策略工厂/ 执行一些其他方法或动作/...

        //设置类静态变量值
        str = "qwe123!";

        //将k1策略 (本类) 注册到 策略工厂里
        MyStrategyFactory.register("k1",this);
        log.info("注册了策略:{}到策略工厂里",this);
    }

    @Override
    public void execTestMethod() {
        log.info("start----执行k1策略...");

        System.err.println(str);
    }
}

DisposableBean

package cn.test.ext.beanlife;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.stereotype.Component;

/**
 * DisposableBean
 * 实现该接口,你的bean可以在销毁阶段执行自定义逻辑。
 * 该接口包含一个destory(),你可以在此方法中定义销毁逻辑。
 */
@Slf4j
@Component
public class TestDisposableBean implements DisposableBean {
    @Override
    public void destroy() throws Exception {

        log.info("TestDisposableBean 这个bean销毁了...");
    }
}

BeanPostProcessor

package cn.test.ext.beanlife;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

/**
 * BeanPostProcessor
 * 该接口定义了在spring容器实例化bean之后和初始化之前,
 * 对bean进行自定义处理的方法。
 * 通过实现该接口,你可以插入自定义逻辑来处理bean
 */
@Component
@Slf4j
public  class TestBeanPostProcessor implements BeanPostProcessor {

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("testController")){

            log.info("BeanPostProcessor Before 处理到了 beanName:{}",beanName);
        }
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("testController")){

            log.info("BeanPostProcessor After 处理到了 beanName:{}",beanName);

        }
        return bean;
    }
}

BeanFactoryPostProcessor

package cn.test.ext.beanlife;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

/**
 * BeanFactoryPostProcessor接口
 * 允许在 所有bean定义加载到容器之后,但在bean实例化之前对他们进行自定义处理。
 * 通过实现该接口,你可以修改或添加新的bean定义
 *
 *
 */
@Component
@Slf4j
public class TestBeanFctoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

        log.info("postProcessBeanFactory 触发了....");
    }
}

BeanDefinitionRegistryPostProcessor

package cn.test.ext.beanlife;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.stereotype.Component;

/**
 * BeanDefinitionRegistryPostProcessor接口
 *
 * 这个接口是BeanFactoryPostProcessor接口的扩展,
 * 允许在bean定义注册过程中对 bean定义进行自定义处理,
 * 它提供了对bean定义注册表的直接访问,可以添加,修改或删除bean定义
 */
@Slf4j
@Component
public class TestBeanDefineRegistPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        log.info("postProcessBeanDefinitionRegistry 触发了...");

    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        log.info("postProcessBeanFactory 触发了...");
    }
}

app生命周期控制类接口

SmartLifecycle

package cn.test.ext.applife;

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

/**
 * SmartLifecycle接口 可以感知springboot应用生命周期变化,是spring的一个扩展点,可以实现随springboot启动和销毁的操作。
 *
 * 自定义类实现SmartLifecycle接口后,至少要重写3个方法start(),stop(),isRunning() ,其他方法可以按需实现
 *
 * springboot中的内嵌tomcat启动/关闭,就是利用SmartLifecycle实现的,
 * 见 org.springframework.boot.web.servlet.context.WebServerStartStopLifecycle
 */
@Component
@Slf4j
public class TestSmartLifeCycle implements SmartLifecycle {

    //模拟一个任务 (实际开发中,可以在这里引入netty,实现netty随springboot启动和销毁)
    private static boolean xxxStat;

    /**
     * bean初始化完毕后,该方法会被执行
     */
    @Override
    public void start() {
        xxxStat = true;
        log.info("启动了 xxxStat ");
    }

    /**
     * 容器关闭后,spring容器发现当前对象实现了SmartLifecycle,
     * 就调用stop(Runnable),如果只是实现了Lifecycle,就调用stop()
     */
    @Override
    public void stop() {
      log.info("stop---容器关闭了");
        xxxStat = false;
    }

    /**
     * 当前状态
     * @return
     */
    @Override
    public boolean isRunning() {
        log.info("isRunning 获取当前状态:{}",xxxStat);

        return xxxStat;
    }

    /**
     * start方法被执行前,先看此方法返回值,
     * 返回false就不执行start方法了
     * @return
     */
    @Override
    public boolean isAutoStartup() {
        log.info("isAutoStartup 是否自启动");

        return true;
    }

    /**
     * 容器关闭后,spring容器发现当前对象实现了SmartLifecycle,就调用stop(Runnable),
     * 如果只是实现了Lifecycle,就调用stop()
     * @param callback
     */
    @Override
    public void stop(Runnable callback) {
        //必须调用stop方法 ,确保SmartLifecycle这个bean里的任务停止了
        this.stop();
        //必须执行callback.run方法,否则app exit时无法销毁这个SmartLifecycle
        callback.run();
        log.info("stop Runnable---容器关闭了");
    }

    /**
     * 返回值决定
     * start方法 在众多Lifecycle实现类中的执行顺序(stop也是)
     * @return
     */
    @Override
    public int getPhase() {
        log.info("SmartLifecycle 当前优先级 1");

        return 1;
    }
}


CommandLineRunner

CommandLineRunner可以让springboot-jar启动时接收一些jvm参数或自定义cmd参数,然后执行一些操作

package cn.test.ext.applife;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class TestCmdLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
      log.info("CommandLineRunner 执行了...");
    }
}

ApplicationRunner

ApplicationRunner可以让springboot-jar启动时接收一些应用配置参数如server.port,然后执行一些操作

package cn.test.ext.applife;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class TestApplictionRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("ApplicationRunner 执行了...");

    }
}

ApplicationListener

要通过spring内置的ApplicationListener监听ContextRefreshedEvent
上下文刷新事件,springboot启动时会触发一次,
一般常用来做业务缓存预热,如在springboot启动时把系统字典数据/系统配置项数据加到缓存中,方便后续调用。

package cn.test.ext.applife;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class AppCtxRefreshListener implements ApplicationListener<ContextRefreshedEvent> {

    /**
     * 监听到上下文刷新事件时,
     * 执行相应的操作
     * @param contextRefreshedEvent 上下文刷新事件
     */
    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        log.info("监听到了spring应用 上下文刷新事件...");
    }
}


你可能感兴趣的:(SpringBoot技术笔记,spring,boot,笔记,java)