牢记这16个SpringBoot 扩展接口,写出更加漂亮的代码

news2024/9/27 23:25:20


1、背景

Spring的核心思想就是容器,当容器refresh的时候,外部看上去风平浪静,其实内部则是一片惊涛骇浪,汪洋一片。Springboot更是封装了Spring,遵循约定大于配置,加上自动装配的机制。很多时候我们只要引用了一个依赖,几乎是零配置就能完成一个功能的装配。

我非常喜欢这种自动装配的机制,所以在自己开发中间件和公共依赖工具的时候也会用到这个特性。让使用者以最小的代价接入。想要把自动装配玩的转,就必须要了解spring对于bean的构造生命周期以及各个扩展接口。当然了解了bean的各个生命周期也能促进我们加深对spring的理解。业务代码也能合理利用这些扩展点写出更加漂亮的代码。

在这篇文章里,我总结了几乎Spring & Springboot所有的扩展接口,以及各个扩展点的使用场景。并且整理出了一个bean在spring内部从被加载到最后初始化完成所有可扩展点的顺序调用图。从而我们也能窥探到bean是如何一步步加载到spring容器中的。

2、可扩展的接口启动调用顺序图

以下是我整理的spring容器中Bean的生命周期内所有可扩展的点的调用顺序,下面会一个个分析

8ba761fa25a0ebb4cc3b0c2e7a7898a0.jpeg

3、ApplicationContextInitializer

org.springframework.context.ApplicationContextInitializer

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

可以想到的场景可能为,在最开始激活一些配置,或者利用这时候class还没被类加载器加载的时机,进行动态字节码注入等操作。

扩展方式为:

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

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

  • 在启动类中用springApplication.addInitializers(new TestApplicationContextInitializer())语句加入

  • 配置文件配置context.initializer.classes=com.example.demo.TestApplicationContextInitializer

  • Spring SPI扩展,在spring.factories中加入org.springframework.context.ApplicationContextInitializer=com.example.demo.TestApplicationContextInitializer

4、BeanDefinitionRegistryPostProcessor

org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor

这个接口在读取项目中的beanDefinition之后执行,提供一个补充的扩展点

使用场景:你可以在这里动态注册自己的beanDefinition,可以加载classpath之外的bean

扩展方式为:

public  class TestBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {      
     @Override      
     public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {      
        System.out.println( "[BeanDefinitionRegistryPostProcessor] postProcessBeanDefinitionRegistry");      
    }      
      
     @Override      
     public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {      
        System.out.println( "[BeanDefinitionRegistryPostProcessor] postProcessBeanFactory");      
    }      
}      


5、BeanFactoryPostProcessor

org.springframework.beans.factory.config.BeanFactoryPostProcessor

这个接口是beanFactory的扩展接口,调用时机在spring在读取beanDefinition信息之后,实例化bean之前。

在这个时机,用户可以通过实现这个扩展接口来自行处理一些东西,比如修改已经注册的beanDefinition的元信息。

扩展方式为:

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


6、InstantiationAwareBeanPostProcessor

org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor

该接口继承了BeanPostProcess接口,区别如下:

BeanPostProcess接口只在bean的初始化阶段进行扩展(注入spring上下文前后),而InstantiationAwareBeanPostProcessor接口在此基础上增加了3个方法,把可扩展的范围增加了实例化阶段和属性注入阶段。

该类主要的扩展点有以下5个方法,主要在bean生命周期的两大阶段:实例化阶段初始化阶段,下面一起进行说明,按调用顺序为:

  • postProcessBeforeInstantiation:实例化bean之前,相当于new这个bean之前

  • postProcessAfterInstantiation:实例化bean之后,相当于new这个bean之后

  • postProcessPropertyValues:bean已经实例化完成,在属性注入时阶段触发,@Autowired,@Resource等注解原理基于此方法实现

  • postProcessBeforeInitialization:初始化bean之前,相当于把bean注入spring上下文之前

  • postProcessAfterInitialization:初始化bean之后,相当于把bean注入spring上下文之后

使用场景:这个扩展点非常有用 ,无论是写中间件和业务中,都能利用这个特性。比如对实现了某一类接口的bean在各个生命期间进行收集,或者对某个类型的bean进行统一的设值等等。

扩展方式为:

public  class TestInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {      
      
     @Override      
     public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {      
        System.out.println( "[TestInstantiationAwareBeanPostProcessor] before initialization " + beanName);      
         return bean;      
    }      
      
     @Override      
     public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {      
        System.out.println( "[TestInstantiationAwareBeanPostProcessor] after initialization " + beanName);      
         return bean;      
    }      
      
     @Override      
&nbsp;&nbsp;&nbsp;&nbsp; public&nbsp;Object&nbsp;postProcessBeforeInstantiation(Class<?>&nbsp;beanClass,&nbsp;String&nbsp;beanName)&nbsp;throws&nbsp;BeansException&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println( "[TestInstantiationAwareBeanPostProcessor]&nbsp;before&nbsp;instantiation&nbsp;"&nbsp;+&nbsp;beanName);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return&nbsp; null;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; @Override&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; public&nbsp;boolean&nbsp;postProcessAfterInstantiation(Object&nbsp;bean,&nbsp;String&nbsp;beanName)&nbsp;throws&nbsp;BeansException&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println( "[TestInstantiationAwareBeanPostProcessor]&nbsp;after&nbsp;instantiation&nbsp;"&nbsp;+&nbsp;beanName);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return&nbsp; true;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; @Override&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; public&nbsp;PropertyValues&nbsp;postProcessPropertyValues(PropertyValues&nbsp;pvs,&nbsp;PropertyDescriptor[]&nbsp;pds,&nbsp;Object&nbsp;bean,&nbsp;String&nbsp;beanName)&nbsp;throws&nbsp;BeansException&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println( "[TestInstantiationAwareBeanPostProcessor]&nbsp;postProcessPropertyValues&nbsp;"&nbsp;+&nbsp;beanName);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return&nbsp;pvs;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;


7、SmartInstantiationAwareBeanPostProcessor

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实例化的后置处理。这个方法就是在提前暴露的回调方法中触发。

扩展方式为:

public&nbsp; class&nbsp;TestSmartInstantiationAwareBeanPostProcessor&nbsp;implements&nbsp;SmartInstantiationAwareBeanPostProcessor&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; @Override&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; public&nbsp;Class<?>&nbsp;predictBeanType(Class<?>&nbsp;beanClass,&nbsp;String&nbsp;beanName)&nbsp; throws&nbsp;BeansException&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println( "[TestSmartInstantiationAwareBeanPostProcessor]&nbsp;predictBeanType&nbsp;"&nbsp;+&nbsp;beanName);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return&nbsp;beanClass;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; @Override&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; public&nbsp;Constructor<?>[]&nbsp;determineCandidateConstructors(Class<?>&nbsp;beanClass,&nbsp;String&nbsp;beanName)&nbsp; throws&nbsp;BeansException&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println( "[TestSmartInstantiationAwareBeanPostProcessor]&nbsp;determineCandidateConstructors&nbsp;"&nbsp;+&nbsp;beanName);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return&nbsp; null;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; @Override&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; public&nbsp;Object&nbsp;getEarlyBeanReference(Object&nbsp;bean,&nbsp;String&nbsp;beanName)&nbsp;throws&nbsp;BeansException&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println( "[TestSmartInstantiationAwareBeanPostProcessor]&nbsp;getEarlyBeanReference&nbsp;"&nbsp;+&nbsp;beanName);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return&nbsp;bean;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;


8、BeanFactoryAware

org.springframework.beans.factory.BeanFactoryAware

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

使用场景为,你可以在bean实例化之后,但还未初始化之前,拿到&nbsp;BeanFactory,在这个时候,可以对每个bean作特殊化的定制。也或者可以把BeanFactory拿到进行缓存,日后使用。

扩展方式为:

public&nbsp; class&nbsp;TestBeanFactoryAware&nbsp;implements&nbsp;BeanFactoryAware&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; @Override&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; public&nbsp;void&nbsp;setBeanFactory(BeanFactory&nbsp;beanFactory)&nbsp;throws&nbsp;BeansException&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println( "[TestBeanFactoryAware]&nbsp;"&nbsp;+&nbsp;beanFactory.getBean(TestBeanFactoryAware .class).getClass().getSimpleName());&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;


9、ApplicationContextAwareProcessor

org.springframework.context.support.ApplicationContextAwareProcessor

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

d0fc28b46e59e448ee93fbaf7832f803.jpeg

可以看到,该类用于执行各种驱动接口,在bean实例化之后,属性填充之后,通过执行以上红框标出的扩展接口,来获取对应容器的变量。所以这里应该来说是有6个扩展点,这里就放一起来说了

  • EnvironmentAware:用于获取EnviromentAware的一个扩展类,这个变量非常有用, 可以获得系统内的所有参数。当然个人认为这个Aware没必要去扩展,因为spring内部都可以通过注入的方式来直接获得。

  • EmbeddedValueResolverAware:用于获取StringValueResolver的一个扩展类,&nbsp;StringValueResolver用于获取基于String类型的properties的变量,一般我们都用@Value的方式去获取,如果实现了这个Aware接口,把StringValueResolver缓存起来,通过这个类去获取String类型的变量,效果是一样的。

  • ResourceLoaderAware:用于获取ResourceLoader的一个扩展类,ResourceLoader可以用于获取classpath内所有的资源对象,可以扩展此类来拿到ResourceLoader对象。

  • ApplicationEventPublisherAware:用于获取ApplicationEventPublisher的一个扩展类,ApplicationEventPublisher可以用来发布事件,结合ApplicationListener来共同使用,下文在介绍ApplicationListener时会详细提到。这个对象也可以通过spring注入的方式来获得。

  • MessageSourceAware:用于获取MessageSource的一个扩展类,MessageSource主要用来做国际化。

  • ApplicationContextAware:用来获取ApplicationContext的一个扩展类,ApplicationContext应该是很多人非常熟悉的一个类了,就是spring上下文管理器,可以手动的获取任何在spring上下文注册的bean,我们经常扩展这个接口来缓存spring上下文,包装成静态方法。同时ApplicationContext也实现了BeanFactoryMessageSourceApplicationEventPublisher等接口,也可以用来做相关接口的事情。


10、BeanNameAware

org.springframework.beans.factory.BeanNameAware

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

使用场景为:用户可以扩展这个点,在初始化bean之前拿到spring容器中注册的的beanName,来自行修改这个beanName的值。

扩展方式为:

public&nbsp; class&nbsp;NormalBeanA&nbsp;implements&nbsp;BeanNameAware{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; public&nbsp;NormalBeanA()&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println( "NormalBean&nbsp;constructor");&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; @Override&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; public&nbsp;void&nbsp;setBeanName(String&nbsp;name)&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println( "[BeanNameAware]&nbsp;"&nbsp;+&nbsp;name);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;


11、@PostConstruct

javax.annotation.PostConstruct

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

使用场景:用户可以对某一方法进行标注,来进行初始化某一个属性

扩展方式为:

public&nbsp; class&nbsp;NormalBeanA&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; public&nbsp;NormalBeanA()&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println( "NormalBean&nbsp;constructor");&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; @PostConstruct&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; public&nbsp;void&nbsp;init(){&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println( "[PostConstruct]&nbsp;NormalBeanA");&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;


12、InitializingBean

org.springframework.beans.factory.InitializingBean

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

使用场景:用户实现此接口,来进行系统启动的时候一些业务指标的初始化工作。

扩展方式为:

public&nbsp; class&nbsp;NormalBeanA&nbsp;implements&nbsp;InitializingBean{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; @Override&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; public&nbsp;void&nbsp;afterPropertiesSet()&nbsp;throws&nbsp;Exception&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println( "[InitializingBean]&nbsp;NormalBeanA");&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;


13、FactoryBean

org.springframework.beans.factory.FactoryBean

一般情况下,Spring通过反射机制利用bean的class属性指定支线类去实例化bean,在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在bean中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。

FactoryBean接口对于Spring框架来说占用重要的地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂bean的细节,给上层应用带来了便利。从Spring3.0开始,FactoryBean开始支持泛型,即接口声明改为FactoryBean<T>的形式

使用场景:用户可以扩展这个类,来为要实例化的bean作一个代理,比如为该对象的所有的方法作一个拦截,在调用前后输出一行log,模仿ProxyFactoryBean的功能。

扩展方式为:

public&nbsp; class&nbsp;TestFactoryBean&nbsp;implements&nbsp;FactoryBean<TestFactoryBean.TestFactoryInnerBean>&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; @Override&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; public&nbsp;TestFactoryBean. TestFactoryInnerBean&nbsp;getObject()&nbsp;throws&nbsp;Exception&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println( "[FactoryBean]&nbsp;getObject");&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return&nbsp; new&nbsp;TestFactoryBean.TestFactoryInnerBean();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; @Override&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; public&nbsp;Class<?>&nbsp;getObjectType()&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return&nbsp;TestFactoryBean.TestFactoryInnerBean .class;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; @Override&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; public&nbsp;boolean&nbsp;isSingleton()&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return&nbsp; true;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; public&nbsp; static&nbsp; class&nbsp;TestFactoryInnerBean{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;


14、SmartInitializingSingleton

org.springframework.beans.factory.SmartInitializingSingleton

这个接口中只有一个方法afterSingletonsInstantiated,其作用是是 在spring容器管理的所有单例对象(非懒加载对象)初始化完成之后调用的回调接口。其触发时机为postProcessAfterInitialization之后。

使用场景:用户可以扩展此接口在对所有单例对象初始化完毕后,做一些后置的业务处理。

扩展方式为:

public&nbsp; class&nbsp;TestSmartInitializingSingleton&nbsp;implements&nbsp;SmartInitializingSingleton&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; @Override&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; public&nbsp;void&nbsp;afterSingletonsInstantiated()&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println( "[TestSmartInitializingSingleton]");&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;


15、CommandLineRunner

org.springframework.boot.CommandLineRunner

这个接口也只有一个方法:run(String... args),触发时机为整个项目启动完毕后,自动执行。如果有多个CommandLineRunner,可以利用@Order来进行排序。

使用场景:用户扩展此接口,进行启动项目之后一些业务的预处理。

扩展方式为:

public&nbsp; class&nbsp;TestCommandLineRunner&nbsp;implements&nbsp;CommandLineRunner&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; @Override&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; public&nbsp;void&nbsp;run(String...&nbsp;args)&nbsp;throws&nbsp;Exception&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println( "[TestCommandLineRunner]");&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;


16、DisposableBean

org.springframework.beans.factory.DisposableBean

这个扩展点也只有一个方法:destroy(),其触发时机为当此对象销毁时,会自动执行这个方法。比如说运行applicationContext.registerShutdownHook时,就会触发这个方法。

扩展方式为:

public&nbsp; class&nbsp;NormalBeanA&nbsp;implements&nbsp;DisposableBean&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; @Override&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; public&nbsp;void&nbsp;destroy()&nbsp;throws&nbsp;Exception&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println( "[DisposableBean]&nbsp;NormalBeanA");&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;


17、ApplicationListener

org.springframework.context.ApplicationListener

准确的说,这个应该不算spring&springboot当中的一个扩展点,ApplicationListener可以监听某个事件的event,触发时机可以穿插在业务方法执行过程中,用户可以自定义某个业务事件。

但是spring内部也有一些内置事件,这种事件,可以穿插在启动调用中。我们也可以利用这个特性,来自己做一些内置事件的监听器来达到和前面一些触发点大致相同的事情。

接下来罗列下spring主要的内置事件:

  • ContextRefreshedEvent

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

  • ContextStartedEvent

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

  • ContextStoppedEvent

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

  • ContextClosedEvent

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

  • RequestHandledEvent

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

18、最后

我们从这些spring&springboot的扩展点当中,大致可以窥视到整个bean的生命周期。在业务开发或者写中间件业务的时候,可以合理利用spring提供给我们的扩展点,在spring启动的各个阶段内做一些事情。以达到自定义初始化的目的。

原文:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/838255.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Scala编程语言入门教程

Scala教程 方便个人学习和查阅 学习目标 Scala介绍 简介 Scala创始人Martin Odersky马丁奥德斯基 再回到我们的scala语言&#xff0c;在Scala官网https://www.scala-lang.org/介绍了其六大特征。 Java和scala可以混编 类型推测(自动推测类型) 并发和分布式&#xff08;Ac…

nginx的优化和防盗链 重要!!!

实验一、隐藏版本号 要把nginx的版本号隐藏起来&#xff0c;防止恶意攻击 方法一&#xff1a;修改配置文件 在http模块中加入一个命令 server_token off&#xff1b; 过程&#xff1a; 备份&#xff0c;改配置文件一定要备份 修改配置文件 在http模块中添加 server_tokens …

城市与AI,正待济沧海

厦门&#xff0c;自古以来是海上丝绸之路的战略支点&#xff0c;是中国海洋贸易网络中的明珠。外来的理念与技术自厦门而入&#xff0c;中国的文化与商品自厦门而出。新事物、新科技往往在这里焕发最耀眼的生机——比如说&#xff0c;人工智能。 多年来&#xff0c;厦门持续推进…

外部排序算法总结

一.内排总结 在之前博客里&#xff0c;博主已经介绍了各种内部排序算法的原理和C语言代码实现&#xff0c;不懂的朋友可以在同系列专栏里选择查看&#xff0c;今天介绍常见排序算法的最后一点&#xff0c;也就是外部排序。在此之前&#xff0c;我们先对外部排序的各种算法做一…

Centos7/8 安装/配置 Redis5

目录 一、安装 Redis 二、创建符号链接 1.针对可执行程序设置符号链接 2.针对配置文件设置符号链接 三、修改配置文件 1.修改 ip 地址 2.关闭保护模式 四、设置工作目录 1.创建工作目录 2.在配置文件中&#xff0c;配置工作目录 五、设置日志文件 1.创建日志目录 2…

vue3中的自定义指令用法

我们都知道vue2中自定义指令全局和局部是这样写的 局部&#xff1a; 全局&#xff1a; 可vue3写法发生改变&#xff0c;如下&#xff1a; 全局&#xff1a; 局部&#xff1a;

python高阶技巧

目录 设计模式 单例模式 具体用法 工厂模式 优点 闭包 案例 修改闭包外部变量 闭包优缺点 装饰器 装饰器原理 装饰器写法 递归 递归的调用过程 递归的优缺点 用递归计算阶乘 设计模式 含义&#xff1a;设计模式是一种编程套路&#xff0c;通过这种编程套路可…

Docker极速安装Jenkins

安装 Jenkins 是一个常见的任务&#xff0c;使用 Docker 进行安装可以简化该过程并确保环境一致性。以下是在 Docker 中安装 Jenkins 的详细步骤&#xff1a; 安装 Docker: 首先&#xff0c;请确保您已在目标机器上安装了 Docker。根据您的操作系统&#xff0c;可以在 Docker 官…

展示Streamlit文本魔力(六):从头顶到脚尖

文章目录 1 前言✨2 st.markdown - 引入丰富的Markdown文本3 st.title - 引入引人注目的大标题4 st.header - 引入简洁的小标题5 st.subheader - 添加次级标题6 st.caption - 添加解释性文字7 st.code - 显示代码块8 st.text - 显示文本9 st.latex - 显示LaTeX公式10 st.divide…

【导出Word】如何使用Java+Freemarker模板引擎,根据XML模板文件生成Word文档(只含文本内容的模板)

这篇文章&#xff0c;主要介绍如何使用JavaFreemarker模板引擎&#xff0c;根据XML模板文件生成Word文档。 目录 一、导出Word文档 1.1、基础知识 1.2、制作模板文件 1.3、代码实现 &#xff08;1&#xff09;引入依赖 &#xff08;2&#xff09;创建Freemarker工具类 &…

linux下绑定进程到指定CPU的操作方法

taskset简介 # taskset Usage: taskset [options] [mask | cpu-list] [pid|cmd [args...]] Show or change the CPU affinity of a process. Options: -a, --all-tasks operate on all the tasks (threads) for a given pid -p, --pid operate on ex…

高级web前端开发工程师的职责说明(合集)

高级web前端开发工程师的职责说明1 职责&#xff1a; 1、根据需求文档&#xff0c;完成PC端、移动端页面及交互的开发&#xff0c;并保证兼容性和确保产品具有优质的用户体验; 2、熟练使用 HTML 、 CSS 、 JS 、 Ajax 等技术&#xff0c;能解决各种浏览器兼容性问题&#xff…

小鱼深度产品测评之:阿里云容器服务器ASK,一款不需购买节点,即可直接部署容器应用。

容器服务器ASK测评 1、引言2、帮助文档3、集群3.1集群列表3.1.1 详情3.1.1.1概览 tab3.1.1.2基本信息 tab3.1.1.4集群资源 tab3.1.1.5 集群日志 tab3.1.1.6 集群任务 tab 3.1.2 应用管理3.1.2.1 详情3.1.2.2 详情3.1.2.3 伸缩3.1.2.4 监控 3.1.3 查看日志3.1.3.1 集群日志3.1.3…

【网络基础实战之路】设计网络划分的实战详解

系列文章传送门&#xff1a; 【网络基础实战之路】设计网络划分的实战详解 【网络基础实战之路】一文弄懂TCP的三次握手与四次断开 【网络基础实战之路】基于MGRE多点协议的实战详解 【网络基础实战之路】基于OSPF协议建立两个MGRE网络的实验详解 PS&#xff1a;本要求基于…

机器学习笔记之优化算法(十)梯度下降法铺垫:总体介绍

机器学习笔记之优化算法——梯度下降法铺垫&#xff1a;总体介绍 引言回顾&#xff1a;线搜索方法线搜索方法的方向 P k \mathcal P_k Pk​线搜索方法的步长 α k \alpha_k αk​ 梯度下降方法整体介绍 引言 从本节开始&#xff0c;将介绍梯度下降法 ( Gradient Descent,GD ) …

vue2-组件和插件的区别

1、组件是什么&#xff1f; 组件就是把图形、非图形的各种逻辑均抽象为一个统一的概念&#xff08;组件&#xff09;来实现开发的模式&#xff0c;在vue中每一个.vue文件都可以被视为一个组件。 组件的优势&#xff1a; 降低整个系统的耦合度&#xff0c;在保持接口不变的情况下…

学C的第三十二天【动态内存管理】

相关代码gitee自取&#xff1a;C语言学习日记: 加油努力 (gitee.com) 接上期&#xff1a; 学C的第三十一天【通讯录的实现】_高高的胖子的博客-CSDN博客 1 . 为什么存在动态内存分配 学到现在认识的内存开辟方式有两种&#xff1a; 创建变量&#xff1a; int val …

ardupilot 中坐标变换矩阵和坐标系变换矩阵区别

目录 文章目录 目录摘要1.坐标变换矩阵与坐标系变换矩阵摘要 本节主要记录ardupilot 中坐标变换矩阵和坐标系变换矩阵的区别,这里非常重要,特别是进行姿态误差计算时,如果理解错误,很难搞明白后面算法。 1.坐标变换矩阵与坐标系变换矩阵 坐标变换矩阵的本质含义:是可以把…

webpack基础知识八:说说如何借助webpack来优化前端性能?

一、背景 随着前端的项目逐渐扩大&#xff0c;必然会带来的一个问题就是性能 尤其在大型复杂的项目中&#xff0c;前端业务可能因为一个小小的数据依赖&#xff0c;导致整个页面卡顿甚至奔溃 一般项目在完成后&#xff0c;会通过webpack进行打包&#xff0c;利用webpack对前…

Django实现音乐网站 ⑸

使用Python Django框架制作一个音乐网站&#xff0c; 本篇主要是配置媒体资源设置。 目录 配置介绍 设置媒体资源 创建媒体资源目录 修改settings.py 注册媒体资源路由 总结 配置介绍 静态资源是指项目配置的js/css/image等系统常用文件。对于一些经常变动的资源&#x…