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左右;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值