Spring Bean基础

1.1 定义Spring Bean

AbstractBeanDefinition中有Bean的配置元信息

1.1.1 什么是BeanDefinition?

BeanDefinition是Spring Framework中定义Bean的配置元信息接口,包含:

  • Bean的类名
  • Bean行为配置元素,如作用域,自动绑定的模式(@Autowired),声明周期回调等
  • 其他Bean引用,又称合作者或者依赖
  • 配置设置,比如Bean属性(Properties),例如数据库连接池的配置

1.2 通过BeanDefinition构建Bean

  • 通过BeanDefinitionBuilder构建
 // 1. 通过BeanDefinitionBuilder构建
       BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
       beanDefinitionBuilder.addPropertyValue("age", 14);
       beanDefinitionBuilder.addPropertyValue("name", "xiaomage");

       // 获取BeanDefinition实例
       BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
  • 通过AbstractBeanDefinition构建
// 2. 通过AbstractBeanDefinition
        GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
        genericBeanDefinition.setBeanClass(User.class);

        // 通过MutablePropertyValues临时存储properties属性值
        MutablePropertyValues propertyValues = new MutablePropertyValues();
//        propertyValues.addPropertyValue("age", 14);
//        propertyValues.addPropertyValue("name", "xiaomage");
        propertyValues
                .add("age", 14)
                .add("name", "xiaomage");
        // setPropertyValues:设置Bean的属性值
        genericBeanDefinition.setPropertyValues(propertyValues);

1.3 注册Bean(BeanDefinition 注册)

  • XML配置元信息
    • <bean id="…" class="…"… />
  • Java注解配置元信息(AnnotationConfigApplicationContext)
    • @Bean
    • @Component
    • @Import
  • Java API配置元信息
    • 命名方式:org.springframework.beans.factory.support.BeanDefinitionRegistry#registerBeanDefinition
    • 非命名方式:org.springframework.beans.factory.support.BeanDefinitionReaderUtils#registerWithGeneratedName
    • 配置类方式:org.springframework.context.annotation.AnnotatedBeanDefinitionReader#register

1.4 实例化Spring bean

  • 常规方式

    • 通过构造器(配置元信息:XML,JAVA注解和JavaApi)
    • 通过静态工厂
    • 通过Bean工厂方法
    • 通过FactoryBean
  • 特殊方式

    • 通过ServiceLoaderFactoryBean
    • 通过AutowireCapableBeanFactory#createBean
    • 通过BeanDefininationReistry#registerBeanDefinition(String,BeanDefinition)

静态工厂:

 <!--  添加factory-method-->
  <bean id="user-create-by-static-method" class="edu.ahau.thinking.in.spring.ioc.overview.domain.User" factory-method="createUser"/>

在User类里添加createUser静态方法,跟factory-method中的字符串一样;

public static User createUser(){
        User user = new User();
        user.setAge(12);
        user.setName("zasn");
        return user;
    }

1.4.1 ServiceLoaderFactoryBean

1.4.1.1 先介绍java的控制反转(ServiceLoader)

  1. 点进ServiceLoader,查看:发现有前缀限制,
    在这里插入图片描述
  2. 因此需要在resource包下建立META-INF/services/xxx文件,文件的名字就是接口名称,文件里面的全限定类名是实现接口的类;
    在这里插入图片描述
  3. java代码获取
ServiceLoader<UserFactory> serviceLoader = ServiceLoader.load(UserFactory.class, Thread.currentThread().getContextClassLoader());

对ServiceLoader对象遍历Iterator<UserFactory> iterator = serviceLoader.iterator();

1.4.1.2 通过AutowireCapableBeanFactoryBean获取ServiceLoader

<bean id="serviceLoaderFactoryBean" class="org.springframework.beans.factory.serviceloader.ServiceLoaderFactoryBean">
<!--    org.springframework.beans.factory.serviceloader.AbstractServiceLoaderBasedFactoryBean中的serviceType-->
    <property name="serviceType" value="edu.ahau.thinking.in.spring.bean.factory.UserFactory"/>
  </bean>
  • 使用Spring应用上下文获取AutowireCapableBeanFactory
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/META-INF/special-bean-instantiation-context.xml");
        AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory();
        ServiceLoader<UserFactory> serviceLoaderFactoryBean = beanFactory.getBean("serviceLoaderFactoryBean", ServiceLoader.class);

通过AutowireCapableBeanFactory可以实例化Bean,通过调用createBean(Class),入参的class对象和不能是接口,而是一个实体类。

UserFactory bean = beanFactory.createBean(DefaultUserFactory.class);

1.5 Bean的初始化

三种方法:

  • @PostConstruct
  • 实现InitializingBean接口
  • 自定义方法(initMethod)

代码如下:

public class DefaultUserFactory implements UserFactory, InitializingBean {
    @PostConstruct
    public void init() {
        System.out.println("由@PostConstruct,UserFactory初始化中....");
    }

    @Override
    public void initUserFactory(){
        System.out.println("由自定义,UserFactory初始化中....");
    }

    // 实现InitializingBean接口,在设置属性后初始化
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("实现InitializingBean接口,在设置属性后初始化....");
    }
}
public class BeanInitializationDemo {
    public static void main(String[] args) {

        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 注册配置类
        applicationContext.register(BeanInitializationDemo.class);
        // 启动Spring应用上下文
        applicationContext.refresh();
        // 依赖查找
        applicationContext.getBean(UserFactory.class);
        // 关闭Spring应用上下文
        applicationContext.close();
    }

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

输出结果:

由@PostConstruct,UserFactory初始化中....
实现InitializingBean接口,在设置属性后初始化....
由自定义,UserFactory初始化中....

得到初始化的顺序:@PostConstruct > 实现InitializingBean接口 > 自定义自定义方法(优先级从大到小)

@Bean(initMethod = "initUserFactory") 在@Bean注解中需要取到initMethod的映射关系;

查看AbstractBeanDefinition中的setInitMethodName(String initMethodName)方法,在这个地方进行debug,需要加上debug的condition条件才能很明显的看到initMethodName.在这里插入图片描述

1.5.1 Bean的延迟初始化

@Bean处加上@Lazy,比较一下即可:
非延迟加载,控制台如下

由@PostConstruct,UserFactory初始化中....
实现InitializingBean接口,在设置属性后初始化....
由自定义,UserFactory初始化中....
Spring应用上下文已启动

延迟加载,控制台如下

Spring应用上下文已启动
由@PostConstruct,UserFactory初始化中....
实现InitializingBean接口,在设置属性后初始化....
由自定义,UserFactory初始化中....

根据控制台打印数据可以看出:延迟加载影响Bean初始化位置。延迟加载,Spring应用上下文启动是在Bean初始化之前;反之,非延迟加载。

查看org.springframework.context.support.AbstractApplicationContext#refresh源码,应用上下文启动的时候会初始化没有延迟加载的Bean
在这里插入图片描述

1.6 Bean的销毁阶段

  • @PreDestroy
  • 实现DisposableBean接口
  • 自定义方法@Bean(destroyMethod = “destroyFactory”)

原理与1.5 Bean的实例化时类似的,查看close()方法,
@PreDestroy到最后的实现依然是调用DisposableBean的destroy()方法;

1.7 SpringBean的GC

正常的注册Bean,调用System.gc()进行强制GC

public class BeanGarbageCollectionDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext beanFactory = new AnnotationConfigApplicationContext();

        beanFactory.register(BeanInitializationDemo.class);

        beanFactory.refresh();

        beanFactory.close();

        System.gc();

    }
}

在Bean对象中覆写Object中的finalize()方法

@Override
protected void finalize() throws Throwable{
    System.out.println("当前 DefaultUserFactory 对象正在被回收。。。");
}

控制台:

当前 DefaultUserFactory 对象正在被回收。。。

如果在调用System.gc()后,没有显示"对象正在被回收。。。",这是正常的行为,需要在gc之前将线程睡眠大概5s左右;

Spring基础配置主要包括以下几个方面的内容:\[1\]\[2\]\[3\] 1. Spring的类包必须已经放在Spring的类容器下面。这意味着我们需要将Spring的类包放在项目的类路径下,以便Spring容器能够正确加载和管理这些类。 2. 应用程序应当为Spring提供完备的Bean的配置信息。这些配置信息可以通过XML文件或者注解的方式进行定义,用于描述Bean的属性、依赖关系、行为配置等。 3. Bean的类都已经放在Spring的类容器下面。这意味着我们需要将所有需要由Spring管理的Bean的类放在Spring容器能够扫描到的位置,以便Spring能够正确实例化和管理这些Bean。 4. Spring的配置文件是Spring容器对Bean进行生产以及关系注入的图纸。这个配置文件是一个或多个标准的XML文档,其中最常见的是ApplicationContext.xml,它是Spring的默认配置文件。在容器启动时,如果找不到其他的配置文件,Spring会尝试加载这个默认的配置文件。 5. Bean的配置信息由Bean的元数据信息组成,包括Bean的实现类、属性信息、依赖关系、行为配置以及创建方式定义等。这些信息用于告诉Spring容器如何实例化和装配Bean,以及如何为上层应用提供准备就绪的运行环境。 综上所述,Spring基础配置包括将Spring的类包放在类路径下、提供完备的Bean的配置信息、将Bean的类放在Spring容器能够扫描到的位置、配置Spring的配置文件以及定义Bean的元数据信息。这些配置将帮助Spring容器正确加载和管理Bean,为应用程序提供准备就绪的运行环境。 #### 引用[.reference_title] - *1* *2* *3* [Spring bean配置的六种方式](https://blog.csdn.net/echizao1839/article/details/88063013)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值