软件编程
位置:首页>> 软件编程>> java编程>> 总结Bean的三种自定义初始化和销毁方法

总结Bean的三种自定义初始化和销毁方法

作者:zijikanwa  发布时间:2023-01-05 13:38:09 

标签:Bean,自定义,初始化,销毁

Bean三种自定义初始化和销毁

一. 三种方法概述

在配置类中指定 @Bean(initMethod = “init”,destroyMethod = “destory”)注解

实现InitializingBean接口并重写其afterPropertiesSet方法,实现DisposableBean接口并重写destroy方法

利用java的JSR250规范中的@PostConstruct标注在init方法上,@PreDestroy标注在destroy方法上

二. 方法详述

1. 方法1:配置类中指定

示例代码

public class CarA {
   public CarA() {
       System.out.println("CarA。。。构造函数");
   }
   public void initCarA(){
       System.out.println("CarA的init()方法");
   }
   public void destroyCarA(){
       System.out.println("CarA的destroy()方法");
   }
}
@Configuration
public class ConfigTest {
   @Bean(initMethod = "initCarA",destroyMethod = "destroyCarA")
   public CarA carA(){
       return new CarA();
   }
}

执行结果

CarA。。。构造函数
CarA的init()方法

服务启动

CarA的destroy()方法

2. 方法2:实现接口并重写方法

2.1 示例代码

public class CarB implements InitializingBean, DisposableBean {
   public CarB() {
       System.out.println("CarB。。。构造函数");
   }
   @Override
   public void afterPropertiesSet() throws Exception {
       System.out.println("CarB。。。afterPropertiesSet()方法执行");
   }
   @Override
   public void destroy() throws Exception {
       System.out.println("CarB。。。destroy()方法执行");
   }
}
@Configuration
public class ConfigTest {
   @Bean
   public CarB carB(){
       return new CarB();
   }
}

执行结果

CarB。。。构造函数
CarB。。。afterPropertiesSet()方法执行

服务启动

CarB。。。destroy()方法执行

2.2 概述

Spring 开放了扩展接口,允许我们自定义 bean 的初始化和销毁方法。即当 Spring 容器在 bean 进行到相应的生命周期阶段时,会自动调用我们自定义的初始化和销毁方法。这两个扩展接口是 InitializingBean 和 DisposableBean 。

InitializingBean 接口说明:该接口为 bean 提供了 bean 属性初始化后的处理方法,它只有 afterPropertiesSet 一个方法,凡是实现此接口的类,在 bean 的属性初始化后都会执行该方法。
package org.springframework.beans.factory;

public interface InitializingBean {
    void afterPropertiesSet() throws Exception;
}

DisposableBean 接口说明:该接口为单例 bean 提供了在容器销毁 bean 时的处理方法,它只有 destroy 一个方法,凡是实现此接口的类,在 bean 被销毁时都会执行该方法。

package org.springframework.beans.factory;
public interface DisposableBean {
    void destroy() throws Exception;
}

2.3 方法1 && 方法2

  • 相同点:都是在 bean 属性初始化之后需要执行的初始化方法。

  • 不同点

方法1:代码不与Spring耦合;执行效率较低(通过反射来执行initMethod 方法)

方法2:代码与Spring紧耦合;速度更快(将 bean 强制转换成 InitializingBean 接口类型,然后直接调用 afterPropertiesSet 方法)

  • 说明:afterPropertiesSet 和 initMethod 可以同时存在,但是 afterPropertiesSet 方法是在 initMethod 方法之前执行的。

  • 一个 bean 从创建到初始化的过程总结

通过构造器创建 bean

属性注入

执行 afterPropertiesSet 方法

执行 initMethod 方法

3. 方法3:利用java的JSR250规范

代码示例

public class CarC {
   public CarC() {
       System.out.println("CarC。。。构造函数");
   }
   @PostConstruct
   public void initCarC(){
       System.out.println("CarC。。。初始化方法initCarC()");
   }
   @PreDestroy
   public void destroyCarC(){
       System.out.println("CarC。。。销毁方法destroyCarC");
   }
}
@Configuration
public class ConfigTest {
   @Bean
   public CarC carC(){
       return new CarC();
   }
}

执行结果

CarC。。。构造函数
CarC。。。初始化方法initCarC()

服务启动

CarC。。。销毁方法destroyCarC

spring初始化后获取自定义注解Bean

目的是通过注解将特定类的信息(如接口编号)与类关联,之后可通过接口编号获取对应bean来执行对应逻辑。

一.新建注解类

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Service
public @interface ServiceCode {
    String code() default ""; 
    String className() default "";
}

包含接口编号和beanName信息。

二.新建接口类

@ServiceCode(code = "100010", className = "echoService")
@Service("echoService")
public class EchoService { 
}

三.实现接口ApplicationListener

来监听spring容器初始化完成后执行:

@Component
@Order(1)
public class ServiceInitListener implements ApplicationListener<ContextRefreshedEvent> {
    private static final Logger LOGGER = LoggerFactory.getLogger(ServiceInitListener.class); 
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        ApplicationContext applicationContext = event.getApplicationContext();
        //注意 需要时根容器才能通过注解获取到bean,比如event直接获取的容器中只有一些公共注册bean
        if (applicationContext.getParent() != null) {
            applicationContext = applicationContext.getParent();
        }
        Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(ServiceCode.class);
        for (Object bean : beansWithAnnotation.values()) {
            ServiceCode annotation = bean.getClass().getAnnotation(ServiceCode.class);
            String code = annotation.code();
            String className = annotation.className();
            //注册接口编号和beanName
            //在统一入口可通过code获取beanName,然后通过springContext获取对应bean执行自定义逻辑
            //或者完成其他逻辑
        }
    } 
}

注意:

 ContextRefreshedEvent获取到的上下文环境不是根spring容器,其中只有部分spring内置bean,无法通过注解获取到自定义bean,需要获取其父容器来完成操作。我第一次获取是beanList总为空,后来发现其容器内部bean没有自定义的service bean,获取父容器后操作一切正常。

通过@Order注解来定制执行顺序,越小越优先执行。

来源:https://blog.csdn.net/zijikanwa/article/details/120768948

0
投稿

猜你喜欢

  • 关于 swagger 本文不再赘述,网上文章很多。本文要讲的是Knife4j3.0.3 整合SpringBoot 2.6.4,因为 knif
  • 该方法把该字符串转换成一个新的字符数组。 String str="abcdefg"; char a[]; a=str.t
  • java中如何表示圆周率设计一个Shape接口和它的两个实现类Square和Circle。 要求如下(1) Shape接口中有一个抽象方法a
  • 项目结构这个是在网上找的资源,出处记不得了,记录一下。程序的总体结构,很简单的:核心代码代码如下:ArrComparator.java类im
  • 前言:文件的上传和下载在日常开发中很是常见,那么这一功能是如何实现的呢,下面我给大家介绍一下实现条件:1、需要一个form标签,method
  • 如果不知道,类的静态变量存储在那? 方法的局部变量存储在那? 赶快收藏Java内存区域主要可以分为共享内存,堆、方法区和线程私有内存,虚拟机
  • 最近有小伙伴问我,双枚举类该怎么写,还得包括根据key取值方法。于是就手写一个案例如下:/** * 关系类型枚举 */public enum
  • 前几天的一个晚上突然想到微信红包应该有一个随机算法,就自己试着写了下,也不知道对不对,看了看网上的说法,好像到现在为止官方也没有给出一个确切
  • 引言应用 Java 的开源库,编写一个搜索引擎,这个引擎能爬取一个网站的内容。并根据网页内容进行深度爬取,获取所有相关的网页地址和内容,用户
  • 最近公司需要做一个告警页面的功能,需要分页,查了很多资料发现PageHelper比较合适故写一篇从零开始的PageHelper使用的教程,也
  • Apache Dubbo是一款高性能、轻量级的开源 Java RPC 框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡
  • 背包问题主要是指一个给定容量的背包、若干具有一定价值和重量的物品,如何选择物品放入背包使物品的价值最大。其中又分01背包和无限背包,这里主要
  • 问题:在项目中,当保存数据超过数据库字段列长度限制时,如何解决?一种常见的解决办法是:截串存取。顾名思义,就是对大文本数据按指定长度进行截取
  • 一:SparkSQL1.SparkSQL简介Spark SQL是Spark的一个模块,用于处理结构化的数据,它提供了一个数据抽象DataFr
  • 一、静态静态的定时任务可以直接使用注解@Scheduled,并在启动类上配置@EnableScheduling即可@PostMapping(
  • 守护线程在Java中有两类线程User Thread(用户线程)Daemon Thread(守护线程)守护线程的功能非常简单,在其本身是一个
  • 本文实例讲述了Java Swing中JDialog实现用户登陆UI。分享给大家供大家参考,具体如下:JDialog是一种对话框组件,它常常与
  • 概述事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一致性。Spring Framework对事务管理提供了一致的
  • Vector的基本介绍1.:Vector类的定义:public class Vector<E>    ext
  • 一、线程池简介线程池的使用主要是解决两个问题:①当执行大量异步任务的时候线程池能够提供更好的性能,在不使用线程池时候,每当需要执行异步任务的
手机版 软件编程 asp之家 www.aspxhome.com