Gardez ces 16 interfaces d'extension SpringBoot à l'esprit pour écrire un code plus beau


1. Origines

L'idée centrale de Spring est le conteneur. Lorsque le conteneur est rafraîchi, l'extérieur semble calme, mais l'intérieur est plein de vagues turbulentes et d'un vaste océan. Springboot encapsule encore plus Spring, suivant la convention est supérieure à la configuration, plus le mécanisme d'assemblage automatique. Dans de nombreux cas, nous n'avons qu'à citer une dépendance, et nous pouvons terminer l'assemblage d'une fonction avec une configuration presque nulle.

J'aime beaucoup ce mécanisme d'assemblage automatique, donc j'utiliserai également cette fonctionnalité lors du développement de middleware et d'outils de dépendance publique moi-même. Permettre aux utilisateurs d'accéder à un coût minimum. Si vous voulez jouer avec l'assemblage automatique, vous devez comprendre le cycle de vie de construction de Spring pour les beans et diverses interfaces d'extension. Bien sûr, comprendre les différents cycles de vie des haricots peut également favoriser notre compréhension du printemps. Le code métier peut également faire un usage raisonnable de ces points d'extension pour écrire un code plus beau.

Dans cet article, je résume presque toutes les interfaces d'extension de Spring & Springboot , ainsi que les scénarios d'utilisation de chaque point d'extension. Et trié un graphe d'appel séquentiel d'un bean depuis son chargement jusqu'à l'initialisation finale de tous les points extensibles au sein du printemps. Ainsi, nous pouvons également observer étape par étape comment les haricots sont chargés dans le conteneur à ressort.

2. Diagramme de séquence d'appel de démarrage d'interface extensible

Voici la séquence d'appel de tous les points extensibles du cycle de vie du Bean dans le conteneur de printemps que j'ai organisé, qui seront analysés un par un ci-dessous

8ba761fa25a0ebb4cc3b0c2e7a7898a0.jpeg

3、ApplicationContextInitializer

org.springframework.context.ApplicationContextInitializer

Il s'agit de l'interface de rappel pour l' ensemble du conteneur Spring pour initialiser le ConfigurableApplicationContext avant qu'il ne soit actualisé En bref, il s'agit d'appeler la méthode initialize de cette classe avant que le conteneur ne soit actualisé. Ce point peut être étendu par l'utilisateur lui-même. Les utilisateurs peuvent faire certaines choses avant que tout le conteneur de printemps ne soit initialisé.

Le scénario envisageable peut être d'activer certaines configurations au début, ou d'utiliser l'opportunité lorsque la classe n'a pas été chargée par le chargeur de classe à ce moment pour effectuer des opérations telles que l'injection dynamique de bytecode.

La méthode d'extension est :

public  classe TestApplicationContextInitializer implémente ApplicationContextInitializer {
     @Remplacer
     public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out. println( "[ApplicationContextInitializer]");      
    }
}

Étant donné que le conteneur Spring n'a pas encore été initialisé, il existe trois façons de faire en sorte que votre propre extension prenne effet :

  • Dans la classe de démarrage, utilisez l'instruction springApplication.addInitializers(new TestApplicationContextInitializer()) pour joindre

  • Configuration du fichier de configuration context.initializer.classes=com.example.demo.TestApplicationContextInitializer

  • Extension Spring SPI, ajoutez org.springframework.context.ApplicationContextInitializer=com.example.demo.TestApplicationContextInitializer à spring.factories

4、BeanDefinitionRegistryPostProcessor

org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor

Cette interface est exécutée après avoir lu la beanDefinition dans le projet , fournissant un point d'extension supplémentaire

Scénario d'utilisation : vous pouvez enregistrer dynamiquement votre propre beanDefinition ici et vous pouvez charger des beans en dehors du chemin de classe

La méthode d'extension est :

public  classe TestBeanDefinitionRegistryPostProcessor implémente BeanDefinitionRegistryPostProcessor {
     @Remplacer
     public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registre) lève BeansException {
        System.out. println( "[BeanDefinitionRegistryPostProcessor] postProcessBeanDefinitionRegistry");      
    }

     @Remplacer
     public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) lève BeansException {
        System.out.println( "[BeanDefinitionRegistryPostProcessor] postProcessBeanFactory");
    }
}


5、BeanFactoryPostProcesseur

org.springframework.beans.factory.config.BeanFactoryPostProcessor

Cette interface est l'interface étendue de beanFactory , et le temps d'appel est après que le printemps a lu les informations beanDefinition et avant l'instanciation des beans.

À ce stade, les utilisateurs peuvent implémenter cette interface d'extension pour gérer certaines choses par eux-mêmes, comme la modification des méta-informations du beanDefinition enregistré .

La méthode d'extension est :

public  classe TestBeanFactoryPostProcessor implémente BeanFactoryPostProcessor {
     @Remplacer
     public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) lève BeansException {
        System.out. println( "[BeanFactoryPostProcessor]");      
    }
}


6、InstanciationAwareBeanPostProcessor

org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor

Cette interface hérite de l'interface BeanPostProcess , la différence est la suivante :

L'interface BeanPostProcess n'est étendue que pendant la phase d'initialisation du bean (avant et après l'injection du contexte de printemps), et l'interface InstantiationAwareBeanPostProcessor ajoute 3 méthodes sur cette base, augmentant la portée de l'évolutivité à la phase d'instanciation et à la phase d'injection de propriété.

Les principaux points d'extension de cette classe ont les cinq méthodes suivantes, qui se trouvent principalement dans les deux étapes du cycle de vie du bean : l'étape d' instanciation et l'étape d'initialisation , qui seront expliquées ensemble ci-dessous, et l'ordre d'appel est le suivant :

  • postProcessBeforeInstantiation : Avant d'instancier le bean, cela équivaut à avant le nouveau bean

  • postProcessAfterInstantiation : Une fois le bean instancié, cela équivaut à après le nouveau bean

  • postProcessPropertyValues​​​​ : le bean a été instancié et est déclenché lorsque la propriété est injectée. @Autowired , @Resource et d'autres principes d'annotation sont implémentés sur la base de cette méthode

  • postProcessBeforeInitialization : Avant que le bean ne soit initialisé, cela équivaut à injecter le bean dans le contexte du printemps

  • postProcessAfterInitialization : Une fois le bean initialisé, cela équivaut à injecter le bean dans le contexte du printemps

Scénario d'utilisation : ce point d'extension est très utile, qu'il s'agisse d'écrire un middleware ou une entreprise, cette fonctionnalité peut être utilisée. Par exemple, collectez des beans qui implémentent un certain type d'interface au cours de chaque cycle de vie, ou définissez uniformément la valeur d'un certain type de bean, etc.

La méthode d'extension est :

public  classe TestInstantiationAwareBeanPostProcessor implémente InstantiationAwareBeanPostProcessor {

     @Remplacer
     public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.
         retour bean;
    }

     @Remplacer
     public Object postProcessAfterInitialization(Object bean,  Chaîne beanName) lève BeansException {      
        System.out.println( "[TestInstantiationAwareBeanPostProcessor] après initialisation " + beanName);    &n bsp ;
         retour bean;
    }

     @Remplacer
     public Object postProcessBeforeInstantiation(Class<?> beanClass,  Chaîne beanName) lève BeansException {      
        System.out.println( "[TestInstantiationAwareBeanPostProcessor] avant instanciation " + beanName);    & nbsp ;
         retour  nul;
    }

     @Remplacer
     public booléen postProcessAfterInstantiation(Object bean,  Chaîne beanName) lève BeansException {      
        System.out.println( "[TestInstantiationAwareBeanPostProcessor] après instanciation " + beanName);    &nb sp ;
         retour  vrai;
    }

     @Remplacer
     public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean,  Chaîne beanName) lève BeansException {      
        System.out.println( "[TestInstantiationAwareBeanPostProcessor] postProcessPropertyValues " + beanName);    &n bsp;  ;
         retour pvs;
    }


7、SmartInstantiationAwareBeanPostProcessor

org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor

L'interface d'extension dispose de 3 méthodes de point de déclenchement :

  • predictBeanType : ce point de déclenchement se produit avant postProcessBeforeInstantiation (non marqué sur la figure, car il n'est généralement pas nécessaire de développer ce point), cette méthode est utilisée pour prédire le type de bean et renvoie le premier type de classe prédit avec succès. Si il ne peut pas être prédit, renvoie null ; Lorsque vous appelez BeanFactory.getType(nom), lorsque les informations sur le type de bean ne peuvent pas être obtenues via le nom du bean, appelez la méthode de rappel pour déterminer les informations sur le type.

  • determineCandidateConstructors:该触发点发生在postProcessBeforeInstantiation之后,用于确定该bean的构造函数之用,返回的是该bean的所有构造函数列表。用户可以扩展这个点,来自定义选择相应的构造器来实例化这个bean。

  • getEarlyBeanReference:该触发点发生在postProcessAfterInstantiation之后,当有循环依赖的场景,当bean实例化好之后,为了防止有循环依赖,会提前暴露回调方法,用于bean实例化的后置处理。这个方法就是在提前暴露的回调方法中触发。

扩展方式为:

public  classe TestSmartInstantiationAwareBeanPostProcessor implémente SmartInstantiationAwareBeanPostProcessor {

     @Remplacer
     public Class<?> predictBeanType(Class<?> beanClass, String beanName)  lance BeansException {
        System.out.
         renvoie beanClass;
    }

     @Remplacer
     public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass,  Chaîne beanName)  lance BeansException {      
        System.out.println( "[TestSmartInstantiationAwareBeanPostProcessor] determineCandidateConstructors " + beanName);    & nbsp;  ;
         retour  nul;
    }

     @Remplacer
     public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
         Système.
         retour bean;
    }
}


8、BeanFactoryAware

org.springframework.beans.factory.BeanFactoryAware

Cette classe n'a qu'un seul point de déclenchement, qui se produit après l'instanciation du bean et avant l'injection de la propriété, c'est-à-dire avant le Setter. La méthode de point d'extension de cette classe est setBeanFactory , qui peut obtenir la propriété de BeanFactory .

Le scénario d'utilisation est que vous pouvez obtenir la BeanFactory après l'instanciation du bean mais avant son initialisation. À ce stade, vous pouvez effectuer des personnalisations spéciales pour chaque bean. Ou vous pouvez obtenir la BeanFactory pour la mise en cache et l'utiliser à l'avenir.

La méthode d'extension est :

public  classe TestBeanFactoryAware implémente BeanFactoryAware {
     @Remplacer
     public void setBeanFactory(BeanFactory beanFactory) lance BeansException {
        System.out.println( "[TestBeanFactoryAware] " + beanFactory.getBean(TestBeanFactoryAware .class).getClass(). getSimpleName());      
    }
}


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  la classe NormalBeanA implémente BeanNameAware{
     public NormalBeanA() {
        System.out. println( "Constructeur NormalBean");      
    }

     @Remplacer
     public void setBeanName(String name) {
        System.out.println( "[BeanNameAware] " + nom);
    }
}


11、@PostConstruct

javax.annotation.PostConstruct

Ce n'est pas un point d'extension, mais une annotation. Sa fonction est dans la phase d'initialisation du bean. Si @PostConstruct est marqué sur une méthode , cette méthode sera appelée en premier. Le point ici est de prêter attention au point de déclenchement de cette norme, qui est après postProcessBeforeInitialization et avant InitializingBean.afterPropertiesSet .

Scénario d'utilisation : les utilisateurs peuvent marquer une certaine méthode pour initialiser une certaine propriété

La méthode d'extension est :

public  classe NormalBeanA {
     public NormalBeanA() {
        System.out. println( "Constructeur NormalBean");      
    }

     @PostConstruct
     public void init(){
        System.out.println( "[PostConstruct] NormalBeanA");
    }
}


12、InitializingBean

org.springframework.beans.factory.InitializingBean

Cette classe, comme son nom l'indique, est également utilisée pour initialiser les beans. L'interface InitializingBean fournit une méthode d'initialisation pour le bean, qui inclut uniquement la méthode afterPropertiesSet . Toutes les classes qui héritent de cette interface exécuteront cette méthode lors de l'initialisation du bean. Le moment de déclenchement de ce point d'extension est avant postProcessAfterInitialization .

Scénario d'utilisation : L'utilisateur implémente cette interface pour initialiser certains indicateurs métier au démarrage du système.

La méthode d'extension est :

public  la classe NormalBeanA implémente InitializingBean{
     @Remplacer
     public void afterPropertiesSet() lève Exception {
        System.out. println( "[InitializingBean] NormalBeanA");      
    }
}


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  classe TestFactoryBean implémente FactoryBean<TestFactoryBean.TestFactoryInnerBean> {

     @Remplacer
     public TestFactoryBean. TestFactoryInnerBean getObject() lève Exception {
        System.out. println( "[FactoryBean] getObject");      
         retour  nouveau TestFactoryBean.TestFactoryInnerBean();
    }

     @Remplacer
     public Class<?> getObjectType() {
         renvoie TestFactoryBean.TestFactoryInnerBean . classe;      
    }

     @Remplacer
     public booléen isSingleton() {
         retour  vrai;
    }

     public  statique  classe TestFactoryInnerBean{

    }
}


14、SmartInitializingSingleton

org.springframework.beans.factory.SmartInitializingSingleton

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

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

扩展方式为:

public  classe TestSmartInitializingSingleton implémente SmartInitializingSingleton {
     @Remplacer
     public void afterSingletonsInstantiated() {
        System.out. println( "[TestSmartInitializingSingleton]");      
    }
}


15、CommandLineRunner

org.springframework.boot.CommandLineRunner

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

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

扩展方式为:

public  classe TestCommandLineRunner implémente CommandLineRunner {

     @Remplacer
     public void run(String... args) throws Exception {
        System.out. println( "[TestCommandLineRunner]");      
    }
}


16、DisposableBean

org.springframework.beans.factory.DisposableBean

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

扩展方式为:

public  la classe NormalBeanA implémente DisposableBean {
     @Remplacer
     public void destroy() lève Exception {
        System.out. println( "[DisposableBean] NormalBeanA");      
    }
}


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

    Il s'agit d'un événement spécifique au Web qui indique à tous les beans que la requête HTTP a été traitée. Ne peut être appliqué qu'aux applications Web utilisant DispatcherServlet. Lorsque vous utilisez Spring comme contrôleur MVC frontal, le système déclenchera automatiquement cet événement lorsque Spring aura terminé de traiter les demandes des utilisateurs.

18. Enfin

À partir de ces points d'extension spring&springboot , nous pouvons voir à peu près tout le cycle de vie du bean. Lors du développement d'une entreprise ou de l'écriture d'une entreprise de middleware, nous pouvons utiliser raisonnablement les points d'extension fournis par le printemps pour faire certaines choses à chaque étape du démarrage du printemps. Afin d'atteindre l'objectif de l'initialisation personnalisée.

original:

Je suppose que tu aimes

Origine blog.csdn.net/zhaomengsen/article/details/132124825
conseillé
Classement