Spring框架03-IOC应用

DragonflyDavid

Spring IOC应用

Spring IOC基础

image.png

BeanFactory与ApplicationContext区别

  • BeanFactory是Spring框架中IoC容器的顶层接⼝,它只是⽤来定义⼀些基础功能,定义⼀些基础规范
  • ApplicationContext是它的⼀个⼦接⼝,所以ApplicationContext是具备BeanFactory提供的全部功能的

通常,我们称BeanFactory为SpringIOC的基础容器ApplicationContext是容器的⾼级接⼝,⽐BeanFactory要拥有更多的功能,比如说国际化支持和资源访问(xml,java配置类)等等
image.png

启动IOC容器方式

  • Java环境下启动IOC容器

    • ClassPathXmlApplicationContext:从类的根路径下加载配置文件(推荐使用)
    • FileSystemXmlApplicationContext:从磁盘路径上加载文件
    • AnnotationConfigApplicationContext:纯注解模式下加载配置类

Bean的作用范围及⽣命周期

作⽤范围的改变

在spring框架管理Bean对象的创建时,Bean对象默认都是单例的,但是它⽀持配置的⽅式改变作⽤范围。作⽤范围官⽅提供的说明如下图:
image.png

在上图中提供的这些选项中,我们实际开发中⽤到最多的作⽤范围就是singleton(单例模式)和prototype(原型模式,也叫多例模式)。配置⽅式参考下⾯的代码:

<!--配置service对象-->
<bean id="transferService" class="com.lagou.service.impl.TransferServiceImpl" scope="singleton">
</bean>
不同作⽤范围的⽣命周期
单例模式 singleton
  • 对象出⽣:当创建容器时,对象就被创建了
  • 对象活着:只要容器在,对象⼀直活着
  • 对象死亡:当销毁容器时,对象就被销毁了
⼀句话总结:单例模式的bean对象⽣命周期与容器相同
多例模式 prototype
  • 对象出⽣:当使⽤对象时,创建新的对象实例
  • 对象活着:只要对象在使⽤中,就⼀直活着
  • 对象死亡:当对象⻓时间不⽤时,被java的垃圾回收器回收了
⼀句话总结:多例模式的bean对象,spring框架只负责创建,不负责销毁
Bean标签属性

在基于xml的IoC配置中,bean标签是最基础的标签。它表示了IoC容器中的⼀个对象。换句话说,如果⼀个对象想让spring管理,在XML的配置中都需要使⽤此标签配置,Bean标签的属性如下:

  • id属性:⽤于给bean提供⼀个唯⼀标识。在⼀个标签内部,标识必须唯⼀
  • class属性:⽤于指定创建Bean对象的全限定类名
  • name属性:⽤于给bean提供⼀个或多个名称(别名)。多个名称⽤空格分隔
  • factory-bean属性:⽤于指定创建当前bean对象的⼯⼚bean的唯⼀标识。当指定了此属性之后,class属性失效
  • factory-method属性:⽤于指定创建当前bean对象的⼯⼚⽅法,如配合factory-bean属性使⽤,则class属性失效。如配合class属性使⽤,则⽅法必须是static的
  • scope属性:⽤于指定bean对象的作⽤范围。通常情况下就是singleton。当要⽤到多例模式时,可以配置为prototype
  • init-method属性:⽤于指定bean对象的初始化⽅法,此⽅法会在bean对象装配后调⽤。必须是⼀个⽆参⽅法
  • destory-method属性:⽤于指定bean对象的销毁⽅法,此⽅法会在bean对象销毁前执⾏。它只能为scope是singleton时起作⽤
DI依赖注⼊的xml配置
  • 依赖注⼊分类

    • 按照注⼊的⽅式分类

      • 构造函数注⼊:顾名思义,就是利⽤带参构造函数实现对类成员的数据赋值
      • set⽅法注⼊:它是通过类成员的set⽅法实现数据的注⼊(使⽤最多的)
    • 按照注⼊的数据类型分类

      • 基本类型和String:注⼊的数据类型是基本类型或者是字符串类型的数据。
      • 其他Bean类型:注⼊的数据类型是对象类型,称为其他Bean的原因是,这个对象是要求出现在IoC容器中的。那么针对当前Bean来说,就是其他Bean了
      • 复杂类型(集合类型):注⼊的数据类型是Aarry,List,Set,Map,Properties中的⼀种类型

xml与注解相结合模式

注意:

  • 实际企业开发中,纯xml模式使⽤已经很少了
  • 引⼊注解功能,不需要引⼊额外的jar
  • xml+注解结合模式,xml⽂件依然存在,所以,springIOC容器的启动仍然从加载xml开始
  • 哪些bean的定义写在xml中,哪些bean的定义使⽤注解

    第三⽅jar中的bean定义在xml,⽐如德鲁伊数据库连接池,⾃⼰开发的bean定义使⽤注解
xml中标签与注解的对于(IOC)
xml形式 对应的注解形式
标签 @Component("accountDao"),注解加在类上bean的id属性内容直接配置在注解后⾯如果不配置,默认定义个这个bean的id为类的类名⾸字⺟⼩写;另外,针对分层代码开发提供了@Componenet的三种别名@Controller、@Service、@Repository分别⽤于控制层类、服务层类、dao层类的bean定义,这四个注解的⽤法完全⼀样,只是为了更清晰的区分⽽已
标签的scope属性 @Scope("prototype"),默认单例,注解加在类上
标签的init- method属性 @PostConstruct,注解加在⽅法上,该⽅法就是初始化后调⽤的⽅法
标签的destory- method属性 @PreDestory,注解加在⽅法上,该⽅法就是销毁前调⽤的⽅法

Spring IOC高级特性

lazy-Init延迟加载

Bean的延迟加载(延迟创建)

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

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

lazy-init="false",⽴即加载,表示在spring启动时,⽴刻进⾏实例化,如果使用注解则为@Lazy,默认参数就是true

import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

@Component
@Lazy
public class BeanExp {
}

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

<bean id="testBean" class="cn.boc.LazyBean" lazy-init="false" />

设置 lazy-inittrue的 bean将不会在 ApplicationContext启动时提前被实例化,⽽是第⼀次向容器通过 getBean索取 bean时实例化的

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

也可以在容器层次中通过在 元素上使⽤ "default-lazy-init" 属性来控制延时初始化。如下⾯配置:

<beans default-lazy-init="true">
<!-- no beans will be eagerly pre-instantiated... -->
</beans>

如果⼀个 bean 的 scope 属性为 scope="pototype" 时,即使设置了 lazy-init="false",容器启动时也不会实例化bean,⽽是调⽤ getBean ⽅法实例化的

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

FactoryBean和BeanFactory

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

    String name;
    String address;
    int type;

    public String getName() {
        return name;
    }

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

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    @Override
    public String toString() {
        return "BeanExp3{" +
                "name='" + name + '\'' +
                ", address='" + address + '\'' +
                ", type=" + type +
                '}';
    }
}
MyFactoryBean类
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class MyFactoryBean implements FactoryBean<BeanExp3> {

    @Value("测试Bean,中环大厦,1")
    public String info;

    @Override
    public BeanExp3 getObject() throws Exception {
        System.out.println("info:" + info);
        BeanExp3 beanExp3 = new BeanExp3();
        String[] array = info.split(",");
        beanExp3.setName(array[0]);
        beanExp3.setAddress(array[1]);
        beanExp3.setType(Integer.valueOf(array[2]));
        return beanExp3;
    }

    @Override
    public Class<?> getObjectType() {
        return BeanExp.class;
    }
}
xml配置
<bean id="BeanExp3" class="com.boc.MyFactoryBean">
<property name="companyInfo" value="测试Bean,中环大厦,1"/>
</bean>
测试,获取FactoryBean产⽣的对象
 Object beanExp3 = appcationContext.getBean("myFactoryBean");
 System.out.println(beanExp3);
测试,获取FactoryBean,需要在id之前添加“&”
 Object beanExp3 = appcationContext.getBean("&myFactoryBean");
 System.out.println(beanExp3);

后置处理器

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

⼯⼚初始化(BeanFactory)—> Bean对象

在BeanFactory初始化之后可以使⽤BeanFactoryPostProcessor进⾏后置处理做⼀些事情

在Bean对象实例化(并不是Bean的整个⽣命周期完成)之后可以使⽤BeanPostProcessor进⾏后置处理做⼀些事情

注意:对象不⼀定是springbean,⽽springbean⼀定是个对象

SpringBean的⽣命周期
image.png

BeanPostProcessor

BeanPostProcessor是针对Bean级别的处理,可以针对某个具体的Bean
image.png
该接⼝提供了两个⽅法,分别在Bean的初始化⽅法前和初始化⽅法后执⾏,具体这个初始化⽅法指的是   什么⽅法,类似我们在定义bean时,定义了init-method所指定的⽅法

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

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

BeanFactoryPostProcessor

BeanFactory级别的处理,是针对整个Bean的⼯⼚进⾏处理,典型应
⽤:PropertyPlaceholderConfigurer
image.png
此接⼝只提供了⼀个⽅法,⽅法参数为ConfigurableListableBeanFactory,该参数类型定义了⼀些⽅法
image.png
其中有个⽅法名为getBeanDefinition的⽅法,我们可以根据此⽅法,找到我们定义bean的BeanDefinition对象。然后我们可以对定义的属性进⾏修改,以下是BeanDefinition中的⽅法
image.png
⽅法名字类似我们bean标签的属性,setBeanClassName对应bean标签中的class属性,所以当我们拿到BeanDefinition对象时,我们可以⼿动修改bean标签中所定义的属性值。

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

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

阅读 1.1k

苏格拉没有底
尽心,知命

尽心,知命

182 声望
18 粉丝
0 条评论

尽心,知命

182 声望
18 粉丝
文章目录
宣传栏