IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 关于 Spring Bean 了解的可能还不够 -> 正文阅读

[Java知识库]关于 Spring Bean 了解的可能还不够

定义Spring Bean

对应代码中的 BeanDefinition,是 Spring Framework 中定义 Bean 的配置元信息接口,主要包含:

  1. Bean 的类名,全限定名称,具体实现类
  2. Bean 配置元信息:作用域、自动绑定(Auto Wiring)、生命周期回调……
  3. Bean 的引用:合作者(Collaborators)或者依赖(Dependencies),
  4. 配置的设置:Bean 的属性(比如连接池的大小)

BeanDefinition 元信息

概览

属性说明备注
ClassBean 全类名,具体的类,不能是抽象类或接口
NameBean 的名称或者 ID
ScopeBean 的作用域(singleton、prototype、……)
Constructor argumentsBean 构造器参数(用于依赖注入)
PropertiesBean 的属性设置(用于依赖注入)
Autowiring modeBean 自动绑定模式(比如:通过名称 byName……)
Lazy initialization modeBean 延迟初始化(延迟「需要时再初始化,缩短时间」、非延迟「默认」)
Initialization methodBean 初始化回调方法名称
Destruction methodBean 销毁回调方法名称

构建

通过 BeanDefinitionBuilder

// 1. 通过 BeanDefinitionBuilder 构建
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
// 通过属性设置(挨个添加),此处可以使用「beanDefinitionBuilder.addPropertyValue("name","Steve").addPropertyValue("id",30);」
beanDefinitionBuilder.addPropertyValue("name","Steve");
beanDefinitionBuilder.addPropertyValue("id",30);
// 获取 BeanDefinition 实例
BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
// beanDefinition 有好多 set 方法,BeanDefinition 并非 Bean 的终态,可以自定义修改

通过 AbstractBeanDefinition 以及派生类

// 2. 通过 AbstractBeanDefinition 以及派生类
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
// 设置 Bean 类型
genericBeanDefinition.setBeanClass(User.class);
// 通过 MutablePropertyValues 批量操作属性,此处可以使用 「propertyValues.add("name","Steve").add("id",31)」
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.addPropertyValue("name","Steve");
propertyValues.addPropertyValue("id",31);
genericBeanDefinition.setPropertyValues(propertyValues);

命名Spring Bean

Bean 名称

推荐阅读:spring学习之bean的命名-segmentfault

每个 Bean 都有一个或者多个标识符,标识符要在 Bean 的所在容器唯一。通常情况下,一个 Bean 有一个标识符,如果需要额外的标识符则使用别名扩充。
?

基于 XML 的情况下,可以用 id 或者 name 属性规定 Bean 的标识符。如果想使用别名,在 name 属性使用「,」或者「;」分开。
?

Bean 的 id 或者 name 可以留空,留空后,容器会为 Bean 自动生成唯一的名称。推荐使用驼峰,符合 Java 命名规范。
?

Spring 中可查看BeanNameGenerator 的两个实现。

注解实现

具体看:AnnotationBeanNameGenerator

比如用到的 @component@Repository@Service@Controller等,其实后三者只是简单包了一层第一个

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {

	/**
	 * The value may indicate a suggestion for a logical component name,
	 * to be turned into a Spring bean in case of an autodetected component.
	 * @return the suggested component name, if any (or empty String otherwise)
	 */
	@AliasFor(annotation = Component.class)
	String value() default "";

}

默认实现

具体看:DefaultBeanNameGenerator

Spring Bean 的别名

好处

  1. 可以复用现有的 BeanDefinitio
  2. 能够通过命名看出来使用场景(比如同一个 Bean 在 A 系统里叫 beanInA,在 B 系统里可以叫 beanInB)

注册 Spring Bean

基础

XML 配置元信息

Java 注解

@Bean@Component@Import

Java API 配置元信息

  1. 命名方式:BeanDefinitionRegistry#registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
  2. 非命名方式:BeanDifinitionReaderUtils#registerWithGeneratedName(AbstractBeanDefinition definition, BeanDefinitionRegistry registry)
  3. 配置类方式:AnnotatedBeanDefinitionReader#register(Class?<?>... componentClasses)

代码

import static org.springframework.beans.factory.support.BeanDefinitionBuilder.genericBeanDefinition;

/**
 * 注解 BeanDefinition 示例
 *
 * @author Steve
 * @date
 */
@Import(AnnotationBeanDefinitionDemo.Config.class)// 通过 @Import 进行导入
public class AnnotationBeanDefinitionDemo {
    public static void main(String[] args) {
        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 注册 配置类
        // 方式 3:配置类方式;详细看:AnnotationConfigApplicationContext#register(Class<?>... componentClasses)  -> AnnotatedBeanDefinitionReader#register(Class<?>... componentClasses) 
        applicationContext.register(AnnotationBeanDefinitionDemo.class);

        registerUserBeanDefinition(applicationContext,"mindartisan-user");
        registerUserBeanDefinition(applicationContext);

        // 启动 Spring 应用上下文
        applicationContext.refresh();

        // 输出Config 类型的 Bean:{com.mindartisan.spring.geek.bean.definition.AnnotationBeanDefinitionDemo$Config=com.mindartisan.spring.geek.bean.definition.AnnotationBeanDefinitionDemo$Config@7f416310}
        System.out.println("Config 类型的 Bean:" + applicationContext.getBeansOfType(Config.class));
        // User 类型的 Bean:{user=User{id=1, name='Steve'}}
        System.out.println("User 类型的 Bean:" + applicationContext.getBeansOfType(User.class));

        // 关闭 Spring 应用上下文
        applicationContext.close();
    }


    /**
     * bean 的注册方式
     *
     * @param beanDefinitionRegistry
     * @param beanName
     */
    public static void registerUserBeanDefinition(BeanDefinitionRegistry beanDefinitionRegistry, String beanName) {
        BeanDefinitionBuilder beanDefinitionBuilder = genericBeanDefinition(User.class);
        beanDefinitionBuilder
                .addPropertyValue("id", 1L)
                .addPropertyValue("name", "Steve");
        if (StringUtils.hasText(beanName)) {
            // 命名方式注册 BeanDefinition
            beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinitionBuilder.getBeanDefinition());
        } else {
            // 非命名方式
            BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinitionBuilder.getBeanDefinition(), beanDefinitionRegistry);
        }

    }

    public static void registerUserBeanDefinition(BeanDefinitionRegistry beanDefinitionRegistry) {
        registerUserBeanDefinition(beanDefinitionRegistry, null);
    }


    @Component// 通过 @Component 定义当前类作为 Spring Bean(组件)
    public static class Config {

        /**
         * 通过 Java 注解,定义 Bean
         *
         * @return
         */
        @Bean(name = {"user", "steve-user"})// 通过 @Bean,定义 Bean
        public User user() {
            User user = new User();
            user.setId(1L);
            user.setName("Steve");
            return user;
        }
    }
}

扩展

通过外部单体对象注册,主要用到的是 SingletonBeanRegistry#registerSingleton(String beanName, Object singletonObject); 方法
SingtonBeanRegistrationDemo.class:

/**
 * 外部单体 Bean 注册实例
 * 外部 bean:不被 Spring 管理的类
 *
 * @author Steve
 * @date
 */
public class SingtonBeanRegistrationDemo {
    public static void main(String[] args) {
        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 这里的 userFactory 未被 Spring 管理
        UserFactory userFactory = new DefaultUserFactory();
        ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
        // 启动 Spring 应用上下文
        applicationContext.refresh();
        // 注册外部单例对象
        beanFactory.registerSingleton("userFactory", userFactory);
        // 通过依赖查找的方式获取 userFactory
        UserFactory userFactoryByLookup = beanFactory.getBean("userFactory", UserFactory.class);
        System.out.println("userFactory == userFactoryByLookup:" + (userFactory == userFactoryByLookup));
        // 关闭 Spring 应用上下文
        applicationContext.close();
    }
}

实例化 Spring Bean

常规

通过构造器(配置元信息:XML、Java 注解、Java API)

通过静态工厂方法(配置元信息:XML、Java API)

通过 Bean 工厂方法(配置元信息:XML、Java API)

通过 FactoryBean 方式(配置元信息:XML、Java 注解、Java API)

代码

具体方式看 xml 中注释,和 main 方法中的命名

User.class:

/**
 * 用户
 *
 * @author Steve
 * @date
 */
public class User {

    private Long id;

    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

    /**
     * 通过静态方法实例化
     *
     * @return {@link User}
     */
    public static User createUser(){
        User user = new User();
        user.setId(1L);
        user.setName("Steve");
        return user;
    }
}

bean-instantiation-context.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--静态方法实例化 Bean-->
    <bean id="user-by-static-method" class="com.mindartisan.spring.geek.ioc.overview.domain.User"
          factory-method="createUser"/>
    <!--实例 Bean 方法实例化 bean-->
    <bean id="user-by-instance-method" factory-bean="userFactory" factory-method="createUser"/>
    <bean id="userFactory" class="com.mindartisan.spring.geek.bean.factory.DefaultUserFactory"/>
    <!--FactoryBean 实例化 bean-->
    <bean id="user-by-factory-bean" class="com.mindartisan.spring.geek.bean.factory.UserFactoryBean"/>
</beans>

BeanInstantinationDemo.class:

/**
 * Bean 实例化 demo
 *
 * @author Steve
 * @date
 */
public class BeanInstantinationDemo {
    public static void main(String[] args) {
        BeanFactory beanFactory = new ClassPathXmlApplicationContext("META-INF/bean-instantiation-context.xml");

        User userByStaticMethod = beanFactory.getBean("user-by-static-method", User.class);
        // 输出「User{id=1, name='Steve'}」
        System.out.println(userByStaticMethod);

        User userByInstanceMethod = beanFactory.getBean("user-by-instance-method", User.class);
        // 输出「User{id=1, name='Steve'}」
        System.out.println(userByInstanceMethod);
        // 输出「false」
        System.out.println(userByStaticMethod == userByInstanceMethod);

        User userByFactoryBean = beanFactory.getBean("user-by-factory-bean", User.class);
        // 输出「User{id=1, name='Steve'}」
        System.out.println(userByFactoryBean);
        // 输出「false」
        System.out.println(userByStaticMethod == userByFactoryBean);
        
        // 输出「false」
        System.out.println(userByFactoryBean == userByInstanceMethod);


    }
}

UserFactory.class:

/**
 * 工厂类
 *
 * @author Steve
 * @date
 */
public interface UserFactory {

    default User createUser(){
        return User.createUser();
    }
}

DefaultUserFactory.class:

/**
 * 默认用户工厂
 *
 * @author Steve
 * @date
 */
public class DefaultUserFactory implements UserFactory {
}

UserFactoryBean.class:

/**
 * 实现了 FactoryBean 的实现
 *
 * @author Steve
 * @date
 */
public class UserFactoryBean implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        return User.createUser();
    }

    @Override
    public Class<?> getObjectType() {
        return User.class;
    }
}

特殊

通过 ServiceLoaderFactoryBean(配置元信息:XML、Java 注解、Java API)

通过 AutowireCapableBeanFactory#createBean(Java.lang.Class,int,boolean)

通过 BeanDefinitionRegistry#registerBeanDefinition(String,BeanDefinition)

参考:注册 Spring Bean -> Java API 配置元信息

代码

SpecialBeanInstantinationDemo.class:

package com.mindartisan.spring.geek.bean.definition;

import com.mindartisan.spring.geek.bean.factory.DefaultUserFactory;
import com.mindartisan.spring.geek.bean.factory.UserFactory;
import com.mindartisan.spring.geek.ioc.overview.domain.User;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.Iterator;
import java.util.ServiceLoader;

/**
 * 特殊的 Bean 实例化 demo
 *
 * @author Steve
 * @date
 */
public class SpecialBeanInstantinationDemo {
    public static void main(String[] args) {
        // serviceloader
        BeanFactory beanFactory = new ClassPathXmlApplicationContext("META-INF/special-bean-instantiation-context.xml");
        // 从 ServiceLoaderFactoryBean 中创建一个 ServiceLoader,再通过遍历的方式获取所有该 ServiceLoader 的实现类
        // 在此代码中,创建一个「SecondUserFactory」的实现,displayServiceLoader 会输出两个「User{id=1, name='Steve'}」
        ServiceLoader<UserFactory> userFactoryServiceLoader = beanFactory.getBean("userFactoryServiceLoader", ServiceLoader.class);

        displayServiceLoader(userFactoryServiceLoader);
        // demoServiceLoader();

        System.out.println("---------------");

        // 通过 applicationContext 获取 autowireCapableBeanFactory
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("META-INF/special-bean-instantiation-context.xml");
        AutowireCapableBeanFactory autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory();

        // 通过 autowireCapableBeanFactory 创建 userFactory 对象
        // 注意:在 AutowireCapableBeanFactory#createBean(Class<T> beanClass) 的时候,beanClass 要具体的类,不能是接口或者抽象类
        UserFactory userFactory = autowireCapableBeanFactory.createBean(DefaultUserFactory.class);
        User user = userFactory.createUser();
        // 输出「User{id=1, name='Steve'}」
        System.out.println(user);

    }

    /**
     * serviceloader demo
     */
    public static void demoServiceLoader() {
        ServiceLoader<UserFactory> userFactoryServiceLoader = ServiceLoader.load(UserFactory.class,
                Thread.currentThread().getContextClassLoader());
        displayServiceLoader(userFactoryServiceLoader);
    }

    public static void displayServiceLoader(ServiceLoader<UserFactory> userFactoryServiceLoader) {
        Iterator<UserFactory> userFactoryIterator = userFactoryServiceLoader.iterator();
        while (userFactoryIterator.hasNext()) {
            UserFactory userFactory = userFactoryIterator.next();
            // 输出「User{id=1, name='Steve'}」
            System.out.println(userFactory.createUser());
        }
    }

}

special-bean-instantiation-context.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="userFactoryServiceLoader"
          class="org.springframework.beans.factory.serviceloader.ServiceLoaderFactoryBean">
        <property name="serviceType" value="com.mindartisan.spring.geek.bean.factory.UserFactory"/>
    </bean>
</beans>

SecondUserFactory.class:

/**
 * 次要用户工厂
 *
 * @author Steve
 * @date
 */
public class SecondUserFactory implements UserFactory {
}

META-INF/services/com.mindartisan.spring.geek.bean.factory.UserFactory

与 ServiceLoader 有关

com.mindartisan.spring.geek.bean.factory.DefaultUserFactory
com.mindartisan.spring.geek.bean.factory.SecondUserFactory

上述内容指定了com.mindartisan.spring.geek.bean.factory.UserFactory的实现类

扩展:ServiceLoader

体现了 SPI 机制

JDK 的 ServiceLoader

在 main 方法中,使用了 JDK 自带的ServiceLoader。上述的_META-INF/services/com.mindartisan.spring.geek.bean.factory.UserFactory__之所以在 _META/INF/services这个路径下是因为 ServiceLoader 中下述代码:

private static final String PREFIX = "META-INF/services/";

JDK 的 ServiceLoader

Spring 中的 「ServiceLoader」

在 Spring 中,也提供了适配 JDK 中ServiceLoader的实现:ServiceLoaderFactoryBean.class,其父类AbstractServiceLoaderBasedFactoryBean.class有三个子类,如下:
Spring 的 ServiceLoader
三个子类中对 AbstractServiceLoaderBasedFactoryBean#getObjectToExpose(ServiceLoader<?> serviceLoader)有三种不同的实现:

  1. ServiceFactoryBean:返回一个
  2. ServiceLoaderFactoryBean:
  3. ServiceListFactoryBean:返回所有

在使用时,还要注意设置 serviceType,xml 的配置方式如下:

<bean id="userFactoryServiceLoader" class="org.springframework.beans.factory.serviceloader.ServiceLoaderFactoryBean">
  <property name="serviceType" value="com.mindartisan.spring.geek.bean.factory.UserFactory"/>
</bean>

初始化 Spring Bean

实现

  1. @PostConstruct 标注方法
  2. 实现 InitializingBean 接口的 afterPropertiesSet() 方法
  3. 自定义初始化方法
    1. XML 配置:<bean init-method = “init” …/>
    2. Java 注解:@Bean(initMethod=“init”)
    3. Java API:AbstractBeanDefinition#setInitMethodName(String)

代码

BeanInitializationDemo.class

@Configuration
public class BeanInitializationDemo {
    public static void main(String[] args) {
        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(BeanInitializationDemo.class);
        // 启动 Spring 应用上下文
        applicationContext.refresh();
        UserFactory userFactory = applicationContext.getBean(UserFactory.class);
        // 关闭 Spring 应用上下文
        applicationContext.close();
    }

    @Bean(initMethod = "initUserFactory")
    public UserFactory userFactory() {
        return new DefaultUserFactory();
    }
}

DefaultUserFactory.class

/**
 * 默认用户工厂
 *
 * @author Steve
 * @date
 */
public class DefaultUserFactory implements UserFactory, InitializingBean {

    // Bean 初始化使用
    // 1. 基于 @PostConstruct 注解
    @PostConstruct
    public void init() {
        System.out.println("@PostConstruct:UserFactory 初始化中");
    }


    public void initUserFactory() {
        System.out.println("自定义初始化方法 initUserFactory():UserFactory 初始化中");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet:UserFactory 初始化中");
    }
}

顺序

参考:Spring official

  1. 使用注解
  2. 继承接口,重写方法
  3. 手动配置的方法

延迟初始化 Spring Bean

实现

  1. XML 配置<bean lazy-init = “true” …/>
  2. Java 注解:@Lazy

代码:

BeanInitializationDemo.class

@Configuration
public class BeanInitializationDemo {
    public static void main(String[] args) {
        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(BeanInitializationDemo.class);
        // 启动 Spring 应用上下文
        applicationContext.refresh();
        // 非延迟初始化在 Spring 应用上下文启动完成后被初始化
        System.out.println("Spring 应用上下文已经启动");
        UserFactory userFactory = applicationContext.getBean(UserFactory.class);
        System.out.println("使用了 @Lazy 注解「当前为 true」:"+userFactory);
        // 关闭 Spring 应用上下文
        applicationContext.close();
    }

    @Bean(initMethod = "initUserFactory")
    @Lazy(value = true)
    public UserFactory userFactory() {
        return new DefaultUserFactory();
    }
}

@Lazy(value = true) 时,输出以下内容:

Spring 应用上下文已经启动
@PostConstruct:UserFactory 初始化中
afterPropertiesSet:UserFactory 初始化中
自定义初始化方法 initUserFactory():UserFactory 初始化中
使用了 @Lazy 注解「当前为 true」:com.mindartisan.spring.geek.bean.factory.DefaultUserFactory@197d671

BeanInitializationDemo.class

@Configuration
public class BeanInitializationDemo {
    public static void main(String[] args) {
        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(BeanInitializationDemo.class);
        // 启动 Spring 应用上下文
        applicationContext.refresh();
        // 非延迟初始化在 Spring 应用上下文启动完成后被初始化
        System.out.println("Spring 应用上下文已经启动");
        UserFactory userFactory = applicationContext.getBean(UserFactory.class);
        System.out.println("使用了 @Lazy 注解「当前为 false」:"+userFactory);
        // 关闭 Spring 应用上下文
        applicationContext.close();
    }

    @Bean(initMethod = "initUserFactory")
    @Lazy(value = false)
    public UserFactory userFactory() {
        return new DefaultUserFactory();
    }
}

@Lazy(value = fale) 时,输出以下内容:

@PostConstruct:UserFactory 初始化中
afterPropertiesSet:UserFactory 初始化中
自定义初始化方法 initUserFactory():UserFactory 初始化中
Spring 应用上下文已经启动
使用了 @Lazy 注解「当前为 false」:com.mindartisan.spring.geek.bean.factory.DefaultUserFactory@6b4a4e18

延迟初始化和非延迟初始化的主要区别是:延迟初始化在 Spring 应用上下文之后,非延迟在之前。

销毁Spring Bean

方式

  1. @PreDestory标注方法
  2. 实现 DisposableBean#destory()方法
  3. 自定义销毁方法
    1. XML 配置:<bean destroy = "xxx" … />
    2. Java 注解:@Bean(destroy = "xxx")
    3. Java API:AbstractBeanDefinition#setDestroyMethodName(String)

代码

BeanInitializationDemo.class

@Configuration
public class BeanInitializationDemo {
    public static void main(String[] args) {
        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(BeanInitializationDemo.class);
        // 启动 Spring 应用上下文
        applicationContext.refresh();
        // 非延迟初始化在 Spring 应用上下文启动完成后被初始化
        System.out.println("Spring 应用上下文已经启动");
        UserFactory userFactory = applicationContext.getBean(UserFactory.class);
        System.out.println("使用了 @Lazy 注解「当前为 false」:"+userFactory);
        System.out.println("Spring 应用上下文准备关闭");
        // 关闭 Spring 应用上下文
        applicationContext.close();
        System.out.println("Spring 应用上下文已经关闭");
    }

    @Bean(initMethod = "initUserFactory",destroyMethod = "doDestroy")
    @Lazy(value = false)
    public UserFactory userFactory() {
        return new DefaultUserFactory();
    }
}

DefaultUserFactory.class:

/**
 * 默认用户工厂
 *
 * @author Steve
 * @date
 */
public class DefaultUserFactory implements UserFactory, InitializingBean, DisposableBean {

    // Bean 初始化使用
    // 1. 基于 @PostConstruct 注解
    @PostConstruct
    public void init() {
        System.out.println("@PostConstruct:UserFactory 初始化中");
    }


    public void initUserFactory() {
        System.out.println("自定义初始化方法 initUserFactory():UserFactory 初始化中");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet:UserFactory 初始化中");
    }

    @PreDestroy
    public void preDestroy() {
        System.out.println("@PreDestroy:UserFactory 销毁中");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean#destroy():UserFactory 销毁中");
    }

    /**
     * 自定义销毁方法
     */
    public void doDestroy() {
        System.out.println("自定义销毁方法 doDestroy():UserFactory 销毁中");
    }
}

@Lazy(value = fale) 时,输出以下内容:

@PostConstruct:UserFactory 初始化中
afterPropertiesSet:UserFactory 初始化中
自定义初始化方法 initUserFactory():UserFactory 初始化中
Spring 应用上下文已经启动
使用了 @Lazy 注解「当前为 false」:com.mindartisan.spring.geek.bean.factory.DefaultUserFactory@197d671
Spring 应用上下文准备关闭
@PreDestroy:UserFactory 销毁中
DisposableBean#destroy():UserFactory 销毁中
自定义销毁方法 doDestroy():UserFactory 销毁中
Spring 应用上下文已经关闭

顺序

参考:Spring official

  1. 使用注解
  2. 继承接口,重写方法
  3. 手动配置的方法

源码分析

@PreDestory 标注方法

比较简单,直接 IDEA 搜 @PreDestory 的 usage:

  1. CommonAnnotationBeanPostProcessor.CommonAnnotationBeanPostProcessor();
  2. InitDestroyAnnotationBeanPostProcessor.setDestroyAnnotationType()

再在当前类下搜destroyAnnotationType,会发现buildLifecycleMetadata()方法中使用反射去找标注了注解的方法,有的话,就添加到销毁方法的集合中currDestroyMethods.add(new LifecycleElement(method));

实现 DisposableBean#destory()方法

首先看上文的输出,确定好是在 applicationContext.close() 将 Bean 销毁:

  1. AbstractApplicationContext.close();
  2. AbstractApplicationContext.doClose();
  3. AbstractApplicationContext.destroyBeans();
  4. ConfigurableBeanFactory.destroySingletons();
  5. DefaultListableBeanFactory.destroySingletons();
  6. DefaultSingletonBeanRegistry.destroySingletons();「这里通过遍历循环调用下一步」
  7. DefaultSingletonBeanRegistry.destroySingleton();
  8. DefaultSingletonBeanRegistry.destroyBean(String beanName, @Nullable DisposableBean bean);
  9. DisposableBean.destroy();

垃圾回收 Spring Bean

  • 未理解,待办
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-08 22:14:58  更:2022-03-08 22:19:16 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 11:34:45-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码