Java Spring & Springboot 容器中 Bean 的生命周期内可扩展的接口

Spring & Springboot可扩展的接口启动调用顺序图

org.springframework.context.ApplicationContextInitializer

        spring 容器在刷新之前初始化 ConfigurableApplicationContext 的回调接口,也就是在容器刷新之前调用此类的 initialize 方法。这个点允许被用户自己扩展。用户可以在整个 spring 容器还没被初始化之前做一些事情。

public class Test implements ApplicationContextInitializer {      
    @Override      
    public void initialize(ConfigurableApplicationContext applicationContext) {      
        System.out.println("Test.initialize");      
    }      
}  

注:因为这时候 spring 容器还没被初始化,所以想要自己的扩展的生效,有以下三种方式:

  1. 启动类中配置 
    springApplication.addInitializers(new TestApplicationContextInitializer()) 
  2. 配置文件配置
    context.initializer.classes=com.example.demo.TestApplicationContextInitializer
  3. Spring SPI 扩展,在 spring.factories 中加入
    org.springframework.context.ApplicationContextInitializer=com.example.demo.TestApplicationContextInitializer

 org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor

        读取项目中的 beanDefinition 之后执行的接口

@Component
public class Test implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        System.out.println("Test.postProcessBeanDefinitionRegistry");
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("Test.postProcessBeanFactory");
    }
}

org.springframework.beans.factory.config.BeanFactoryPostProcessor

        spring 在读取 beanDefinition 信息之后,实例化 bean 之前实行的接口

@Component
public class Test implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("Test.postProcessBeanFactory");
    }
}

org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor

        该接口继承了 BeanPostProcess 接口。

  • BeanPostProcess 接口有两个方法,只在 bean 的初始化阶段进行扩展(注入 spring 上下文前后),
  1. postProcessBeforeInitialization
            初始化 bean 之前,相当于把 bean 注入 spring 上下文之前
  2. postProcessAfterInitialization
            初始化 bean 之后,相当于把 bean 注入 spring 上下文之后
  •  InstantiationAwareBeanPostProcessor 接口在此基础上增加了 3 个方法,把可扩展的范围增加了实例化阶段和属性注入阶段。
  1. postProcessBeforeInstantiation:实例化 bean 之前,相当于 new 这个 bean 之前
  2. postProcessAfterInstantiation:实例化 bean 之后,相当于 new 这个 bean 之后
  3. postProcessProperties:调用时机为 postProcessAfterInstantiation执行之后并返回 true, 返回的 PropertyValues 将作用于给定 bean 属性赋值.
  4. postProcessPropertyValues: 已经被标注 @Deprecated,后续将会被postProcessProperties 取代。

@Component
public class Test implements InstantiationAwareBeanPostProcessor {

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        System.out.print("beanName:"+beanName+"执行..postProcessAfterInstantiation\n");

        // 会影响postProcessProperties 是否执行,返回false不执行
        return true;
    }

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        System.out.print("beanName:"+beanName+"执行..postProcessBeforeInstantiation\n");
        return null ;
    }

    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        System.out.print("beanName:"+beanName+"执行..postProcessProperties\n");
        return pvs;
    }

    //************************************** BeanPostProcessor **********************************************

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.print("beanName:"+beanName+"执行..postProcessAfterInitialization\n");
        return bean;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.print("beanName:"+beanName+"执行..postProcessBeforeInitialization\n");
        return bean;
    }
}

org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor

该扩展接口有 3 个触发点方法:

  • predictBeanType:该触发点发生在 postProcessBeforeInstantiation 之前 ,这个方法用于预测 Bean 的类型,返回第一个预测成功的 Class 类型,如果不能预测返回 null;当你调用 BeanFactory.getType(name) 时当通过 bean 的名字无法得到 bean 类型信息时就调用该回调方法来决定类型信息。
  • determineCandidateConstructors:该触发点发生在 postProcessBeforeInstantiation 之后,用于确定该 bean 的构造函数之用,返回的是该 bean 的所有构造函数列表。用户可以扩展这个点,来自定义选择相应的构造器来实例化这个 bean。
  • getEarlyBeanReference:该触发点发生在 postProcessAfterInstantiation 之后,当有循环依赖的场景,当 bean 实例化好之后,为了防止有循环依赖,会提前暴露回调方法,用于 bean 实例化的后置处理。这个方法就是在提前暴露的回调方法中触发。
@Component
public class Test implements SmartInstantiationAwareBeanPostProcessor {      
      
    @Override      
    public Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {      
        System.out.println("Testr.predictBeanType: " + beanName);      
        return beanClass;      
    }      
      
    @Override      
    public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {      
        System.out.println("Test.determineCandidateConstructors: " + beanName);      
        return null;      
    }      
      
    @Override      
    public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {      
        System.out.println("Test.getEarlyBeanReference: " + beanName);      
        return bean;      
    }      
}   

org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor

        该触发点发生在postProcessAfterInstantiation之前,用户实例化后做扩展,参与 bean 的初始化的过程。

@Component
public class Test implements MergedBeanDefinitionPostProcessor{
    @Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition rootBeanDefinition, Class<?> aClass, String s) {

    }

    
}

org.springframework.beans.factory.BeanFactoryAware

        这个接口只有一个触发点方法,发生在 bean 的实例化之后,注入属性之前,也就是 Setter 之前。这个类的扩展点方法为 setBeanFactory,可以拿到 BeanFactory 这个属性         

@Component
public class Test implements BeanFactoryAware {      
    @Override      
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {      
        System.out.println("Test.setBeanFactory: " + beanFactory.getBean(TestBeanFactoryAware.class).getClass().getSimpleName());      
    }      
}  

 org.springframework.context.support.ApplicationContextAwareProcessor

        该类本身并没有可扩展点方法,但是该类内部的invokeAwareInterfaces方法却有 6 个扩展点可供实现 ,这些类触发的时机在 bean 实例化之后,初始化之前。

package org.springframework.context.support;

import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.Aware;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.EmbeddedValueResolver;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.lang.Nullable;
import org.springframework.util.StringValueResolver;

// 注意,这里class前没有public修饰符,表明这个工具Spring没有打算给外部使用。
class ApplicationContextAwareProcessor implements BeanPostProcessor {

	private final ConfigurableApplicationContext applicationContext;

	private final StringValueResolver embeddedValueResolver;


	/**
	 * Create a new ApplicationContextAwareProcessor for the given context.
	 * 使用给定的应用上下文创建一个ApplicationContextAwareProcessor实例,通常该方法
	 * 由应用上下文对象自己调用,比如在类AbstractApplicationContext中 : 
	 * new ApplicationContextAwareProcessor(this)
	 */
	public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
		this.applicationContext = applicationContext;
		this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
	}


	// 接口BeanPostProcessor规定的方法,会在bean创建时,实例化后,初始化前,对bean对象应用
	@Override
	@Nullable
	public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
		AccessControlContext acc = null;

		if (System.getSecurityManager() != null &&
				(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
						bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
						bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
			acc = this.applicationContext.getBeanFactory().getAccessControlContext();
		}

		if (acc != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				// 检查bean上是否实现了某个Aware接口,有的话做相应调用
				invokeAwareInterfaces(bean);
				return null;
			}, acc);
		}
		else {
			// 检查bean上是否实现了某个Aware接口,有的话做相应调用
			invokeAwareInterfaces(bean);
		}

		// 返回处理后的bean
		return bean;
	}

	// 检查bean上是否实现了某个Aware接口,有的话做相应调用
	private void invokeAwareInterfaces(Object bean) {
		if (bean instanceof Aware) {
			if (bean instanceof EnvironmentAware) {
				((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
			}
			if (bean instanceof EmbeddedValueResolverAware) {
				((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
			}
			if (bean instanceof ResourceLoaderAware) {
				((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
			}
			if (bean instanceof ApplicationEventPublisherAware) {
				((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
			}
			if (bean instanceof MessageSourceAware) {
				((MessageSourceAware) bean).setMessageSource(this.applicationContext);
			}
			if (bean instanceof ApplicationContextAware) {
				((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
			}
		}
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) {
		return bean;
	}

}
  • EnvironmentAware: 可以获得系统内的所有参数。当然个人认为这个 Aware 没必要去扩展,因为 spring 内部都可以通过注入的方式来直接获得。
    @Component
    public class Test implements EnvironmentAware {
        @Override
        public void setEnvironment(Environment environment) {
            System.out.println(environment.getProperty("yunfang.profile"));
        }
    }
  • EmbeddedValueResolverAware:用于获取基于 String 类型的 properties 的变量,一般我们都用 @Value 的方式去获取,如果实现了这个 Aware 接口,把 StringValueResolver 缓存起来,通过这个类去获取 String 类型的变量,效果是一样的。
    @Component
    public class Test implements EmbeddedValueResolverAware {
    
    
        @Override
        public void setEmbeddedValueResolver(StringValueResolver resolver) {
            StringBuilder name = new StringBuilder("${").append("yunfang.profile").append("}");
            System.out.println(resolver.resolveStringValue(name.toString()));
        }
    }
  • ResourceLoaderAware:用于获取 ResourceLoader 的一个扩展类,ResourceLoader 可以用于获取 classpath 内所有的资源对象,可以扩展此类来拿到 ResourceLoader 对象。
    @Component
    public class Test implements ResourceLoaderAware {
    
        @Override
        public void setResourceLoader(ResourceLoader resourceLoader) {
            Resource resource = null;
            String location = "";
            InputStream inputStream = null;
    
            System.out.println("=============classpath:**=============");
            location = "classpath:application-dev.yml";
            resource = resourceLoader.getResource(location);
            System.out.println(resource.exists());
    
            System.out.println("=============file:///**=============");
            location = "file:///E:/Projects/yunfang-lite/test1.txt";
            resource = resourceLoader.getResource(location);
            System.out.println(resource.exists());
    
            System.out.println("=============https://**=============");
            location = "https://profile-avatar.csdnimg.cn/2f61592ca35d4be3b9f6e165e84ba664_laiyucannian.jpg";
            resource = resourceLoader.getResource(location);
            System.out.println(resource.exists());
        }
    }
  • ApplicationEventPublisherAware:用于获取 ApplicationEventPublisher 的一个扩展类,ApplicationEventPublisher 可以用来发布事件,结合 ApplicationListener 来共同使用。这个对象也可以通过 spring 注入的方式来获得。
    @Component
    public class Test implements ApplicationEventPublisherAware {
    
        @Override
        public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
    
        }
    }
  • MessageSourceAware:用于获取 MessageSource 的一个扩展类,MessageSource 主要用来做国际化。
  • ApplicationContextAware:用来获取 ApplicationContext 的一个扩展类,就是 spring 上下文管理器,可以手动的获取任何在 spring 上下文注册的 bean。同时 ApplicationContext 也实现了 BeanFactoryMessageSourceApplicationEventPublisher 等接口,也可以用来做相关接口的事情。
    @Component
    public class Test implements ApplicationContextAware {
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            
        }
    }

org.springframework.beans.factory.BeanNameAware 

        这个类也是 Aware 扩展的一种,触发点在 bean 的初始化之前,也就是 postProcessBeforeInitialization 之前,这个类的触发点方法只有一个:setBeanName 

在初始化 bean 之前拿到 spring 容器中注册的的 beanName

@Component
public class Test implements BeanNameAware {
    @Override
    public void setBeanName(String s) {

    }
}

@PostConstruct

         在 bean 的初始化阶段,如果对一个方法标注了 @PostConstruct,会先调用这个方法。这里重点是要关注下这个标准的触发点,这个触发点是在 postProcessBeforeInitialization 之后,InitializingBean.afterPropertiesSet 之前。

@Component
public class PostConstructTest{
    @Autowired
    private UsersMapper usersMapper;

    private static PostConstructTest postConstructTest;

    @PostConstruct
    public void init(){
        postConstructTest= this;
    }

    public static void test(){
        postConstructTest.usersMapper.selectBuId("1");
    }

}

org.springframework.beans.factory.InitializingBean

        用来初始化 bean 的。InitializingBean 接口为 bean 提供了初始化方法的方式,它只包括 afterPropertiesSet 方法,凡是继承该接口的类,在初始化 bean 的时候都会执行该方法。这个扩展点的触发时机在 postProcessAfterInitialization 之前。

@Component
public class Test implements InitializingBean {
    @Override
    public void afterPropertiesSet() throws Exception {
        
    }
}

 org.springframework.beans.factory.FactoryBean

        通过实现该接口定制实例化 Bean 的逻辑。 

FactoryBean 表现的是一个工厂的职责。 即一个 Bean A 如果实现了 FactoryBean 接口,那么 A 就变成了一个工厂,根据 A 的名称获取到的实际上是工厂调用 getObject () 返回的对象,而不是 A 本身,如果要获取工厂 A 自身的实例,那么需要在名称前面加上 '&' 符号

@Configuration
@ComponentScan("com.test")
public class TestConfig {
}

@Component("studentBean")
public class StudentBean implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        return new TeacherBean();
    }
   
    @Override
    public Class<?> getObjectType() {  //注意这个方法主要作用是:该方法返回的类型是在ioc容器中getbean所匹配的类型
        return StudentBean.class;
    }
    //一个学生学习方法
    public void study(){
        System.out.println("学生学习。。。");
    }
}
public class TeacherBean {
    public void teacher(){
        System.out.println("老师教书。。。。");
    }
}
public class Test{
     public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(TestConfig.class);
        //加上了“&”符号
        StudentBean studentBean = (StudentBean)annotationConfigApplicationContext.getBean("&studentBean");
        studentBean.study();

        TeacherBean teacherBean = (TeacherBean) annotationConfigApplicationContext.getBean("studentBean");
        teacherBean.teacher();
    }
}

 org.springframework.beans.factory.SmartInitializingSingleton

        在 spring 容器管理的所有单例对象(非懒加载对象)初始化完成之后调用的回调接口。其触发时机为 postProcessAfterInitialization 之后。

@Component
public class Test implements SmartInitializingSingleton {
    @Override
    public void afterSingletonsInstantiated() {
        
    }
}

 org.springframework.boot.CommandLineRunner

        整个项目启动完毕后,自动执行。如果有多个 CommandLineRunner,可以利用 @Order 来进行排序。 

@Component
public class Test implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("启动完成。。。");
    }
}

org.springframework.beans.factory.DisposableBean

        当此对象销毁时,会自动执行这个方法。

@Component
public class Test implements DisposableBean {
    @Override
    public void destroy() throws Exception {
        
    }
}

org.springframework.context.ApplicationListener

        ApplicationListener 可以监听某个事件的 event,触发时机可以穿插在业务方法执行过程中,用户可以自定义某个业务事件。

spring 主要的内置事件:

  • ContextRefreshedEvent

    ApplicationContext 被初始化或刷新时,该事件被发布。这也可以在 ConfigurableApplicationContext 接口中使用 refresh() 方法来发生。此处的初始化是指:所有的 Bean 被成功装载,后处理 Bean 被检测并激活,所有 Singleton Bean 被预实例化,ApplicationContext 容器已就绪可用。

  • ContextStartedEvent

    当使用 ConfigurableApplicationContext (ApplicationContext 子接口)接口中的 start() 方法启动 ApplicationContext 时,该事件被发布。你可以调查你的数据库,或者你可以在接受到这个事件后重启任何停止的应用程序。

  • ContextStoppedEvent

    当使用 ConfigurableApplicationContext 接口中的 stop() 停止 ApplicationContext 时,发布这个事件。你可以在接受到这个事件后做必要的清理的工作

  • ContextClosedEvent

    当使用 ConfigurableApplicationContext 接口中的 close() 方法关闭 ApplicationContext 时,该事件被发布。一个已关闭的上下文到达生命周期末端;它不能被刷新或重启

  • RequestHandledEvent

    这是一个 web-specific 事件,告诉所有 bean HTTP 请求已经被服务。只能应用于使用 DispatcherServlet 的 Web 应用。在使用 Spring 作为前端的 MVC 控制器时,当 Spring 处理用户请求结束后,系统会自动触发该事件

原文:牢记这16个SpringBoot 扩展接口,写出更加漂亮的代码 - 掘金

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值