Java构造、静态代码块与SpringBean初始化及销毁过程

1 篇文章 0 订阅

前言

Spring Bean的初始化方式就那么几种,但是初始化Bean的方式不同,Bean中静态代码块,构造代码块,构造器以及其他初始化方法的执行顺序如何,这也都是需要我们去掌握的,可能哪天碰到一道面试题,也就是类似于本文中提及到的初始化过程

此文描述的不是SpringBean的生命周期,后期我们会好好聊下它的生命周期,咱们今天阐述的是一个Bean内部方法的执行顺序

此文描述的不是SpringBean的生命周期,后期我们会好好聊下它的生命周期,咱们今天阐述的是一个Bean内部方法的执行顺序

初始化方式

SpringBean的初始化方式,相信大家并不陌生,我们今天对注解注入和配置文件注入进行讲解.我们先了解下注解注入和配置文件注入方式

注解

常用Spring的注解有: @Component,@Repository,@Service,@Controller,(@Configuration,@Bean等还有很多组合注入方式,不做一一解读)但每个注解有它不同的应用场景,不过你也可以用其中任意一个修饰你的表现层,服务层及数据层,但是如果用一个@Controller 修饰你的数据层及服务层,看到这样的代码你不会觉得恶心吗?每个各司其职,岂不是更好,下面我对每个注解简单的介绍下,我们后面的文章会详细解读

@Repository

Spring2.0 添加,一种封装存储、检索和搜索行为的机制,模拟对象集合,你可以标记在任何的类上,用来表明该类是用来执行与数据库相关的操作,并支持自动处理数据库操作产生的异常,其遵循 DDD:Domain-Driven Design(领域驱动设计)而设计的,简称DDD ,DDD 是一套综合软件系统分析和设计的面向对象建模方法,后期我们谈这个

@Service

Spring2.5 添加和他孪生兄弟还有@Component,@Controller,都是在Spring2.5 中产出.主要标记在服务层中,处理核心业务逻辑,如果存在DB的使用,可以使用@Repository注入的Bean,也同样遵循DDD而产出

@Controller

Spring2.5添加,上面已经讲到了,它的作用主要解释与表现层,作为web控制器使用,前端页面上的交互都与@Controller修饰的类进行交互,入参的判断及异常最终的处理,都会落在Controller中,不过也可以通过@ControllerAdvice处理全局异常,但是它是在Spring 3.2中添加的.

@Component 

Spring2.5添加,为什么最后将@Component,因为@Component可以作用在任何类上面,可以回头看下@Repository,@Service,@Controller 都被@Component修饰,但凡类上面标记@Component注解,都可以被添加到容器中

配置文件

注解方式和配置文件的方式没有什么区别,只是注解不需要在xml自己配置bean

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">


    <context:component-scan base-package="com.ijson"/>


    <bean class="com.ijson.MyBeanService" init-method="initMethod" destroy-method="destroyMethod"/>


    <context:annotation-config/>
    <task:annotation-driven/>


</beans>

初始化过程

有了上面的铺垫,我们来讲下两种初始化方式他们的构造器,静态代码块,构造代码块的初始化过程,结合上面的xml我们看下一下代码,其执行顺序可参照代码中的注释

package com.ijson;


import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;


import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;


/**
 * desc:
 * author: cuiyongxu
 * create_time: 2021/8/24-3:55 PM
 **/


public class MyBeanService implements InitializingBean, DisposableBean {


    static {
        System.out.println("static");//1
    }


    static {
        System.out.println("static-2");//2
    }


    {
        System.out.println("{}-1");//3
    }


    {
        System.out.println("{}-2");//4
    }




    public MyBeanService() {
        System.out.println("MyBeanService");//5
    }




    @PostConstruct
    public void init2() {
        System.out.println("init2");//6
    }


    @PostConstruct
    public void init() {
        System.out.println("init");//7
    }




    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet");//8
    }


    public void initMethod() {
        System.out.println("init-method");//9
    }


    /**
     * bean 销毁顺序,终止容器时,销毁过程
     */
    @PreDestroy
    public void preDestroy() {
        System.out.println("preDestroy");//1
    }


    @PreDestroy
    public void preDestroy2() {
        System.out.println("preDestroy2");//2
    }


    @Override
    public void destroy() throws Exception {
        System.out.println("destroy");//3
    }


    private void destroyMethod() {
        System.out.println("destroy-method");//4
    }
}

以下代码反编译,为啥要反编译?看后面总结

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//


package com.ijson;


import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;


public class MyBeanService implements InitializingBean, DisposableBean {
    
    public MyBeanService() {
        System.out.println("{}-1");
        System.out.println("{}-2");
        System.out.println("MyBeanService");
    }


    @PostConstruct
    public void init2() {
        System.out.println("init2");
    }


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


    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet");
    }


    public void initMethod() {
        System.out.println("init-method");
    }


    @PreDestroy
    public void preDestroy() {
        System.out.println("preDestroy");
    }


    @PreDestroy
    public void preDestroy2() {
        System.out.println("preDestroy2");
    }


    public void destroy() throws Exception {
        System.out.println("destroy");
    }


    private void destroyMethod() {
        System.out.println("destroy-method");
    }


    static {
        System.out.println("static");
        System.out.println("static-2");
    }
}

总结:

静态代码块:优先于各种代码块以及构造函数,它会在类初始化(可了解下JVM类加载过程)的时候执行一次,执行完成便销毁,如果一个类中有多个静态代码块,会按照书写顺序依次执行

构造代码块:在创建对象时被调用,创建对象就会调用一次,在咱们上面的示例中只会执行一次,因为加载容器中之后,不会被销毁,也就一直存在这个Bean.他优先于构造函数执行,需要注意,构造代码块不是优先于构造函数执行,而是依托于构造函数,也就是说,你不实例化对象,构造代码块是不会执行的,看下反编译后的MyBeanService的构造函数,我们看到构造代码块的代码被添加到了构造函数中,且在构造函数代码之前,即依托于构造函数

构造函数:构造函数的命名必须和类名完全相同,没有显式返回类型,当前类初始化时,就会自动调用构造函数

@PostConstruct: 优先要说的,它不是Spring的注解,它位于rt.jar中,源自Common Annotations 1.0,在jdk6发布时,被作为新特性添加到了jdk中,执行于构造函数之后,如果一个类中有多个@PostConstruct 则会按照书写顺序依次执行

InitializingBean:只包括afterPropertiesSet方法,继承该接口的类,在初始化bean的时候就会执行该方法.如果用户自行实现了安全策略,则优先执行安全管理器,再执行afterPropertiesSet方法,如果没有,则直接执行afterPropertiesSet,如下图源码所示

init-method: 只用在使用xml配置文件时才会有此项,在afterPropertiesSet之后执行,如下图源码所示

init-method: 想必看到上面的截图,应该就知道这个方法在谁的后面去执行了吧,这里就不做多说了

销毁过程

看到上面的代码.最后几行有销毁的逻辑,当然也需要参照xml文件中的描述,下面讲述下销毁过程
@PreDestroy 在这里可以理解为当前Bean销毁之前执行,并且只会被服务器调用一次,如果同一个Bean 出现多个带有@PreDestroy注解的方法,则按照书写顺序依次执行
DisposableBean:destroy允许在容器销毁该Bean的之前进行一次回调,如下图

destroy-method: 可参照上图源码,可以看到会在destroy之后,执行一次 

更多文章点击:https://www.ijson.com/detl/2021_08_24/E36N7z.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值