Spring IOC⾼级特性


主要介绍四个高级特性: SpringBean的生命周期,lazy-Init 延迟加载,FactoryBean 和 BeanFactory,后置处理器

SpringBean的生命周期

  1. 实例化Bean,根据配置情况调⽤ Bean 构造⽅法或⼯⼚⽅法实例化 Bean。
  2. 设置属性值,利⽤依赖注⼊完成 Bean 中所有属性值的配置注⼊。
  3. 调⽤BeanNameAware的setBeanName⽅法,如果 Bean 实现了 BeanNameAware 接⼝,则 Spring 调⽤ Bean 的 setBeanName() ⽅法传⼊当前 Bean 的 id 值。
  4. 调⽤BeanFactoryAware的setBeanFactory⽅法,如果 Bean 实现了 BeanFactoryAware 接⼝,则 Spring 调⽤ setBeanFactory() ⽅法传⼊当前⼯⼚实例的引⽤。
  5. 调⽤ ApplicationContextAware的setApplicationContext⽅法,如果 Bean 实现了 ApplicationContextAware 接⼝,则 Spring 调⽤ setApplicationContext() ⽅法传⼊当前 ApplicationContext 实例的引⽤。
  6. 调⽤ BeanPostProcessor 的预初始化⽅法,如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调⽤该接⼝的预初始化⽅法postProcessBeforeInitialzation() 对 Bean 进⾏加⼯操作。_此处⾮常重要,Spring 的 AOP 就是利⽤它实现的。_
  7. 调⽤InitializingBean的afterPropertiesSet⽅法,如果 Bean 实现了 InitializingBean 接⼝,则 Spring 将调⽤ afterPropertiesSet() ⽅法。
  8. 调⽤定制的初始化⽅法init-method,如果在配置⽂件中通过 init-method 属性指定了初始化⽅法,则调⽤该初始化⽅法。
  9. 调⽤ BeanPostProcessor 的后初始化⽅法,如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调⽤该接⼝的初始化⽅法 postProcessAfterInitialization()。此时,Bean 已经可以被应⽤系统使⽤了。
  10. 如果Bean是单例的,则将该 Bean 放⼊ Spring IoC 的缓存池中。如果Bean是原型,则将该 Bean 交给调⽤者
  11. 如果 Bean 实现了 DisposableBean 接⼝,则 Spring 会调⽤ destory() ⽅法将 Spring 中的 Bean 销毁。如果在配置⽂件中通过 destory-method 属性指定了 Bean 的销毁⽅法,则 Spring 将调⽤该⽅法对 Bean 进⾏销毁。

lazy-Init 延迟加载

ApplicationContext 容器的默认⾏为是在启动服务器时将所有 singleton bean 提前进⾏实例化。提前实例化意味着作为初始化过程的⼀部分,ApplicationContext 实例会创建并配置所有的singleton bean。

如果不想让⼀个singleton bean 在 ApplicationContext实现初始化时被提前实例化,那么可以将bean 设置为延迟实例化。

在bean的类上,加入@Lazy则会被延迟加载。

@Service
@Lazy
public class UserService {

}

如果⼀个设置了⽴即加载的 bean1,引⽤了⼀个延迟加载的 bean2 ,那么 bean1 在容器启动时被实例 化,⽽ bean2 由于被 bean1 引⽤,所以也被实例化,这种情况也符合延时加载的 bean 在第⼀次调⽤ 时才被实例化的规则。

应⽤场景

  • 开启延迟加载⼀定程度提⾼容器启动和运转性能
  • 对于不常使⽤的 Bean 设置延迟加载,这样偶尔使⽤的时候再加载,不必要从⼀开始该 Bean 就占 ⽤资源

FactoryBean 和 BeanFactory

BeanFactory接⼝是容器的顶级接⼝,定义了容器的⼀些基础⾏为,负责⽣产和管理Bean的⼀个⼯⼚, 具体使⽤它下⾯的⼦接⼝类型,⽐如ApplicationContext;此处我们重点分析FactoryBean

Spring中Bean有两种,⼀种是普通Bean,⼀种是⼯⼚Bean(FactoryBean),FactoryBean可以⽣成 某⼀个类型的Bean实例(返回给我们),也就是说我们可以借助于它⾃定义Bean的创建过程。

Bean创建的三种⽅式中的静态⽅法和实例化⽅法和FactoryBean作⽤类似,FactoryBean使⽤较多,尤 其在Spring框架⼀些组件中会使⽤,还有其他框架和Spring框架整合时使⽤

public interface FactoryBean<T> {

	String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

	/**
	 * 返回FactoryBean创建的Bean实例,如果isSingleton返回true,则该实例会放到Spring容器 的单例对象缓存池中Map
	 */
	@Nullable
	T getObject() throws Exception;

	/**
	 * 返回FactoryBean创建的Bean类型
	 */
	@Nullable
	Class<?> getObjectType();

	/**
	 * 返回作⽤域是否单例
	 */
	default boolean isSingleton() {
		return true;
	}

}

简单使用

@Data
public class Company {

    private String name;
    private String address;
    private int scale;

}

实现FactoryBean

public class CompanyFactoryBean implements FactoryBean<Company> {

    /**
     * 公司名称,地址,规模
     */
    private String companyInfo;

    public CompanyFactoryBean(String companyInfo) {
        this.companyInfo = companyInfo;
    }

    @Override
    public Company getObject() throws Exception {
        // 模拟创建复杂对象Company
        Company company = new Company();
        String[] strings = companyInfo.split(",");
        company.setName(strings[0]);
        company.setAddress(strings[1]);
        company.setScale(Integer.parseInt(strings[2]));
        return company;
    }

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

注册FactoryBean

@Configuration
public class FactoryBeanConfig {

    @Bean
    public CompanyFactoryBean companyBean() {
        return new CompanyFactoryBean("明日曦月,南京,2");
    }

}

获取两个Bean

public static void main(String[] args) {
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.storyhasyou.spring");
	// 获取FactoryBean产⽣的对象
    Company company = applicationContext.getBean("companyBean", Company.class);
	// 获取FactoryBean,需要在id之前添加“&”
    CompanyFactoryBean companyFactoryBean = applicationContext.getBean("&companyBean", CompanyFactoryBean.class);
    System.out.println(company); // Company(name=明日曦月, address=南京, scale=2)
    System.out.println(companyFactoryBean); // com.storyhasyou.spring.factorybean.CompanyFactoryBean@52e677af
}

使用场景

  • 在与Spring整合中的框架用的多,比如spring-mybatis

后置处理器

Spring提供了两种后处理bean的扩展接⼝,分别为 BeanPostProcessor 和 BeanFactoryPostProcessor,两者在使⽤上是有所区别的。

⼯⼚初始化(BeanFactory)—> Bean对象,在BeanFactory初始化之后可以使⽤BeanFactoryPostProcessor进⾏后置处理做⼀些事情,在Bean对象实例化(并不是Bean的整个⽣命周期完成)之后可以使⽤BeanPostProcessor进⾏后置处理做⼀些事情。

对象不⼀定是spring bean,⽽spring bean⼀定是个对象

BeanPostProcessor

BeanPostProcessor是针对Bean级别的处理,可以针对某个具体的Bean.

public interface BeanPostProcessor {

	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}


	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

}

该接⼝提供了两个⽅法,分别在Bean的初始化⽅法前和初始化⽅法后执⾏。
具体这个初始化⽅法指的是什么⽅法?类似我们在定义bean时,定义了init-method所指定的⽅法。

定义⼀个类实现了BeanPostProcessor,默认是会对整个Spring容器中所有的bean进⾏处理。如果要对 具体的某个bean处理,可以通过⽅法参数判断,两个类型参数分别为Object和String,第⼀个参数是每个bean的实例,第⼆个参数是每个bean的name或者id属性的值。所以我们可以通过第⼆个参数,来判断我们将要处理的具体的bean。

处理是发⽣在Spring容器的实例化和依赖注⼊之后。

准备Bean对象

import lombok.Data;
import org.springframework.stereotype.Component;

/**
 * @author fangxi
 * @date 2020/4/13
 */
@Data
@Component
public class User {

    private String name;
    private String phone;
}

拦截具体实现

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

/**
 * @author fangxi
 * @date 2020/4/13
 * 拦截实例化之后的对象,实例化了并且注入属性了
 */
@Component
public class UserBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if ("user".equals(beanName)) {
            System.out.println("user bean 被UserBeanPostProcessor#before");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if ("user".equals(beanName)) {
            System.out.println("user bean 被UserBeanPostProcessor#after");
        }
        return bean;
    }

}

测试使用

public class SpringExample {

    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.storyhasyou.spring");
        User user = applicationContext.getBean("user", User.class);
        System.out.println(user);
    }
}

//输出
user bean 被UserBeanPostProcessor#before
user bean 被UserBeanPostProcessor#after
User(name=null, phone=null)

BeanFactoryPostProcessor

BeanFactory级别的处理,是针对整个Bean的⼯⼚进⾏处理,典型应⽤:PropertyPlaceholderConfigurer

@FunctionalInterface
public interface BeanFactoryPostProcessor {

	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

此接⼝只提供了⼀个⽅法,⽅法参数为ConfigurableListableBeanFactory,该参数类型定义了⼀些⽅法

其中有个⽅法名为getBeanDefinition的⽅法,我们可以根据此⽅法,找到我们定义bean 的 BeanDefinition对象。然后我们可以对定义的属性进⾏修改。

BeanDefinition对象:我们在 XML 中定义的 bean 标签,Spring 解析 bean 标签成为⼀个 JavaBean, 这个JavaBean 就是 BeanDefinition

调⽤ BeanFactoryPostProcessor ⽅法时,这时候bean还没有实例化,此时 bean 刚被解析成 BeanDefinition对象

@Component
public class UserBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanDefinition beanDefinition = beanFactory.getBeanDefinition("user");
        // 可以使用beanDefinition对象干涉spring创建bean的动作
        beanDefinition.setLazyInit(true);
        beanDefinition.setDescription("hehe");
        beanDefinition.setPrimary(true);
    }
}

Author: Re:0
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source Re:0 !
 Previous
Spring Boot启动之前做了哪些事 Spring Boot启动之前做了哪些事
探究一下在调用我们写的main方法之前,SpringBoot框架为我们做了哪些事情。
2022-04-13
Next 
使用Spring实现观察者模式 使用Spring实现观察者模式
观察者模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新,其主要解决一个对象状态改变给其他关联对象通知的问题,保证易用和低耦合。更多观察者模式的资料:观察者模式
2022-04-08
  TOC