Spring Boot05

目录

3.3依赖注入

3.3.1注解@Autowired

 3.3.2消除歧义性-------@Primary和@Quelifier

 3.3.3带有参数的构造方法类的装配

3.4生命周期


继续总结

3.3依赖注入

那之前啊,我们将Bean装配到SpringIoC容器当中,从而通过容器去获取Bean对象,在真实的程序中难免会有俩个Bean之间的依赖关系,例如电力工人和工具,电力工人工作的前提是要有工具,为了解决这种依赖关系,我们就要学习今天的依赖注入(dependency injection)简称DI

为了更好的理解我们引入以下示例

第一步:创建两个接口(电力工人接口,电力工具接口)

第二步:创建两个实现类(电力工人实现类,电力工具实现类)

第三步:通过@Component接口将两个Bean装配到SpringIoC容器中

第四步:@Autowired添加依赖注入

第五步:测试

接口

//创建电力工人接口
public interface Electrician {
    public void use();
    public void setUtiles(electricityPower_tools e);
}

//创建电力工具接口
public interface electricityPower_tools {
    public void use();
}


实现类

//电力工人实现类

@Component
public class Electricianimpl implements com.itheima.pojo.Electrician {
    @Autowired
    private electricityPower_tools e = null;

    @Override
    public void use() {
        System.out.println("电力工人");
        e.use();
    }

    @Override
    public void setUtiles(electricityPower_tools e) {
        this.e = e;
    }
}
//电力工具实现类
@Component
public class electricityPower_toolsimpl implements com.itheima.pojo.electricityPower_tools {
    @Override
    public void use() {
        System.out.println("钳子工具被使用");
    }
}

最后进行测试

public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
        Electrician electrician = (Electrician)applicationContext.getBean(Electricianimpl.class);
        electrician.use();
}

那我们发现,我们成功获取Electrician,并调用其属性electricityPower_tools的use()方法

3.3.1注解@Autowired

        @Autowired是比较常用的注解,所以我们要进一步探讨此注解,我们继续思考一个问题,工具不可能只有一个把,例如电笔、钳子等,这个时候就出现问题了,当SpringIoC依赖注入electricityPower_tools时,如果electricityPower_tools接口有两个实现类,且都在SpringIoC容器中,那Spring IoC将要注入谁呢,这个时候就会报错

报错演示

我们在创建一个electricityPower_tools接口的实现类

//电笔工具类
@Component
public class electricityPower_toolsimpl2 implements electricityPower_tools {
    @Override
    public void use() {
        System.out.println("电笔工具被使用");
    }
}

        这个时候我们在运行就会报错

 现在我们来解决一下这个问题

第一种方式:我们将依赖注入的属性名改为具体的实现类的名称,这里改为钳子实现类,

这种方式能解决问题的原因:@Autowired默认根据属性的类型进行注入,如果IoC容器中对应的类型不是唯一的,那么它会根据属性名进行注入

第二种和第三种我们看下一节

 

 3.3.2消除歧义性-------@Primary和@Quelifier

我们继续上面的问题,现在是有两个工具实现类,导致SpringIoC不知道应该注入哪一个,其实我们可以使用@Primary注解为其中一个设置优先级,这也是一种解决方案

我们举个栗子,我们为电笔工具类设置优先级,也可以解决问题

这里记得改回来 

 

 如果我们为电笔工具类和钳子工具类都设置@Primary,依然会出现问题,这里大家可以自己尝试

接着再来说@Qualifier注解

        上面两种方式都不是很灵活,不可♥啊,咋可咋办,使用@Qualifier注解呗,它的属性value需要一个字符串去定义,它将与@Autowired组合在一起使用,通过类型或者名称一起找到Bean

@Autowired

//根据名称注入

@Qualifier(“electricityPower_toolsimpl2”)

private electricityPower_tools  electricityPower_tools= null;

@Autowired

//根据类型注入

@Qualifier(“electricityPower_tools.class”)

private electricityPower_tools  electricityPower_tools= null;

 3.3.3带有参数的构造方法类的装配

其实我们可以通过带参数的构造方法将依赖注入

我们将@Autowired删掉,在构造方法参数前加上

@Autowired @Qualifier("electricityPower_toolsimpl2")

//改成这样
@Component
public class Electricianimpl implements Electrician {
    
    private electricityPower_tools  electricityPower_tools= null;
    public Electricianimpl(@Autowired @Qualifier("electricityPower_toolsimpl2") electricityPower_tools electricityPower_tools) {
        this.electricityPower_tools = electricityPower_tools;
    }
    @Override
    public void use() {
        System.out.println("电力工人");
        electricityPower_tools.use();
    }

    @Override
    public void setUtiles(electricityPower_tools e) {
        this.electricityPower_tools = e;
    }
}

3.4生命周期

我们有必要了解Bean的生命周期,例如当我们通过SpringIoC容器获取数据源后,我们希望在Bean销毁时关闭数据源(执行close方法),以此达到释放资源的目的,这个时候就要了解Bean的生命周期

       

大致分为Bean的定义、Bean的初始化、Bean的生存期、Bean的销毁4个部分。

Bean定义大致过程:

        1.资源定位:Spring通过我们的配置,例如@ComponentScan定义扫描指定的包,找到@Component修饰的类

       2. Bean定义:一旦找到资源,会对他进行解析,并将定义信息保存起来。此时还没有实例化Bean,仅仅是Bean的定义

        3.发布Bean定义:然后将Bean定义发布到SpringIoC容器中。此时IoC容器也只是定义,没有Bean实例

           接下来会实例化Bean,完成依赖注入

        如果我们不希望在IoC容器创建时就完成Bean的实例化和依赖注入,可以在@ComponnetScan注解中添加配置项lazyInit,默认为false,也就是默认不进行延迟初始化,如果将其改为true,在Spring发布Bean定义后,将不会立即进行Bean的初始化和依赖注入

来个实例

1.正常情况

我们先在Electricianimpl构造方法中加一句打印

public Electricianimpl(@Autowired @Qualifier("electricityPower_toolsimpl2") electricityPower_tools electricityPower_tools) {
        System.out.println("完成依赖注入");
        this.electricityPower_tools = electricityPower_tools;
    }

在此处打断点

调试方式运行结果

 2.lazyInit=true的情况

 修改配置类

 调试方式运行结果

 Spring在完成依赖注入后,还提供一系列接口和配置来完成Bean的初始化过程,除了BeanPostProcess对所以Bean有效,其他接口只针对单个Bean有效

查看源图像

 为了测试生命周期,我们对电力工人类进行改造

package com.POJO.impl;

import com.POJO.Electrician;
import com.POJO.electricityPower_tools;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@Component
public class Electricianimpl implements Electrician, BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {

    private electricityPower_tools  electricityPower_tools= null;

    @Override
    public void use() {
        System.out.println("电力工人");
        electricityPower_tools.use();
    }

    @Override
    @Autowired
    @Qualifier("electricityPower_toolsimpl2")
    public void setUtiles(electricityPower_tools electricityPower_tools) {
        this.electricityPower_tools = electricityPower_tools;
    }


    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("调用BeanNameAware");
    }

    @Override
    public void setBeanName(String s) {
        System.out.println("调用BeanFactoryAwar");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("调用DisposableBean");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("调用InitializingBean");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("调用ApplicationContextAware");
    }
    @PostConstruct
    public void init(){
        System.out.println("自定义初始化方法");
    }
    @PreDestroy
    public void destroy1(){
        System.out.println("自定义销毁方法");
    }
}

如果出现一下问题 ,加入一下依赖即可

<dependency>
    <groupId>javax.annotation</groupId>
    <artifactId>javax.annotation-api</artifactId>
    <version>1.3.2</version>
</dependency>

 同时我们还要创建一个BeanPostProcessorExample类(Bean后置处理器)

package com.POJO.impl;

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

@Component
public class BeanPostProcessorExample implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("BeanPostProcess调用postProcessBeforeInitialization方法,参数【"+bean.getClass().getSimpleName()+"】【"+beanName+"】");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("BeanPostProcess调用postProcessAfterInitialization方法,参数【"+bean.getClass().getSimpleName()+"】【"+beanName+"】");

        return bean;
    }
}

测试结果:我们可以看到Bean后置处理器对所以Bean都生效,其他接口只有实现并重写该接口的方法的Bean才会生效

 有时候Bean的定义可能会使用第三方的类,此时使用@Bean注解来配置自定义初始化和销毁方法,如下所示:

@Bean(initMethod = "init" destroyMethod = "destroy")

DisposableBean接口中的destroy为什么没有执行?

看看上面的测试结果,没有destroy方法的执行语句,why?

        对于Bean的作用域如果是多例-prototype,IOC容器并不会执行相关的清理工作,只有单例模式下才会进行Bean的销毁,因此示例代码中destroy方法根本不会被调用,多例Bean的生命周期不归IOC容器来管理,单例Bean的生命周期归IOC容器管理。

        但是我们的是单例呀,我认为是还没等destroy方法执行,Bean就已经销毁,故而没有执行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不背八股睡不着

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值