lazy-Init 延迟加载

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

  1. <bean id="testBean" class="cn.lagou.LazyBean" />
  2. 该bean默认的设置为:
  3. <bean id="testBean" calss="cn.lagou.LazyBean" lazy-init="false" />

lazy-init=”false”,⽴即加载,表示在spring启动时,⽴刻进⾏实例化。 如果不想让⼀个singleton bean 在 ApplicationContext实现初始化时被提前实例化,那么可以将bean 设置为延迟实例化

  1. <bean id="testBean" calss="cn.lagou.LazyBean" lazy-init="true" />

也可以通过注解@Lazy来开启延迟加载,只有在使用的时候才会创建该对象。如果⼀个 bean 的 scope 属性为 scope=”pototype” 时,即使设置了 lazy-init=”false”,容器启动时也不 会实例化bean,⽽是调⽤ getBean ⽅法实例化的。

应⽤场景

(1)开启延迟加载⼀定程度提⾼容器启动和运转性能
(2)对于不常使⽤的 Bean 设置延迟加载,这样偶尔使⽤的时候再加载,不必要从⼀开始该 Bean 就占
⽤资源
注解:虽然懒加载可以减少内存消耗,但是对于服务器硬件来说,即使我们创建再多的对象也占用不了多少内存

FactoryBean 和 BeanFactory

BeanFactory接⼝是容器的顶级接⼝,定义了容器的⼀些基础⾏为,负责⽣产和管理Bean的⼀个⼯⼚,
具体使⽤它下⾯的⼦接⼝类型,⽐如ApplicationContext;
Spring中Bean有两种,⼀种是普通Bean,⼀种是⼯⼚Bean(FactoryBean),FactoryBean可以⽣成
某⼀个类型的Bean实例(返回给我们),也就是说我们可以借助于它⾃定义Bean的创建过程。
Bean创建的三种⽅式中的静态⽅法和实例化⽅法和FactoryBean作⽤类似,FactoryBean使⽤较多,尤
其在Spring框架⼀些组件中会使⽤,还有其他框架和Spring框架整合时使⽤

  1. // 可以让我们⾃定义Bean的创建过程(完成复杂Bean的定义)
  2. public interface FactoryBean<T> {
  3. @Nullable
  4. // 返回FactoryBean创建的Bean实例,如果isSingleton返回true,则该实例会放到Spring容器
  5. 的单例对象缓存池中Map
  6. T getObject() throws Exception;
  7. @Nullable
  8. // 返回FactoryBean创建的Bean类型
  9. Class<?> getObjectType();
  10. // 返回作⽤域是否单例
  11. default boolean isSingleton() {
  12. return true;
  13. }
  14. }

栗子

/**
 * @author zbc
 * @date 2020/2/29 17:31
 */
@Component("companyFactoryBean")
public class CompanyFactoryBean implements FactoryBean<Company> {

    private String companyInfo = "拉钩,中关村,hello";

    public void setCompanyInfo(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(strings[2]);
        return company;
    }

    @Override
    public Class<?> getObjectType() {
        return Company.class;
    }
}
@Test
public void testIoC() throws Exception {
     // 通过读取classpath下的xml文件来启动容器(xml模式SE应用下推荐)
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
        //输出的是CompanyFactoryBean
    Object company = applicationContext.getBean("&companyFactoryBean");
        //输出的是company
    Object company = applicationContext.getBean("companyFactoryBean");
    System.out.println(company);
}

后置处理器

Spring提供了两种后处理bean的扩展接⼝,分别为 BeanPostProcessor 和 BeanFactoryPostProcessor,两者在使⽤上是有所区别的。⼯⼚初始化(BeanFactory)—> Bean对象 在BeanFactory初始化之后可以使⽤BeanFactoryPostProcessor进⾏后置处理做⼀些事情 在Bean对象实例化(并不是Bean的整个⽣命周期完成)之后可以使⽤BeanPostProcessor进⾏后置处理做⼀些事情
注意:对象不⼀定是springbean,⽽springbean⼀定是个对象

BeanPostProcessor

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容器的实例化和依赖注⼊之后

BeanFactoryPostProcessor

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

@FunctionalInterface
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) 
throws BeansException;

}

此接⼝只提供了⼀个⽅法,⽅法参数为ConfifigurableListableBeanFactory,该参数类型定义了⼀些⽅法其中有个⽅法名为getBeanDefifinition的⽅法,我们可以根据此⽅法,找到我们定义bean 的 BeanDefifinition对象。然后我们可以对定义的属性进⾏修改,以下是BeanDefifinition中的⽅法⽅法名字类似我们bean标签的属性,setBeanClassName对应bean标签中的class属性,所以当我们拿到BeanDefifinition对象时,我们可以⼿动修改bean标签中所定义的属性值。
经典应用:读取配置,替换${jdbc.url},这是BeanFactoryPostProcessor在spring底层的经典应用

 <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
    </bean>

BeanDefifinition对象:我们在 XML 中定义的 bean标签,Spring 解析 bean 标签成为⼀个 JavaBean,这个JavaBean 就是 BeanDefifinition
注意:调⽤ BeanFactoryPostProcessor ⽅法时,这时候bean还没有实例化,此时 bean 刚被解析成
BeanDefifinition对象