上文我们介绍了IOC和DI,IOC是一种设计模式,DI是它的具体实现,有很多的框架都有这样的实现,本文主要以spring框架的实现,来看具体的注入实现逻辑。

spring是如何将对象加入容器的

spring将对象加入容器的方式有很多种,最主要的是xml和注解的形式,而当下注解的形式应用更加的广泛,所以这里我们也主要介绍注解注入模式下的相关知识点。

spring下的注解也是有很多种的,其中应用最为广泛的就是模式注解。

模式注解 stereotype annotations

咋一看,这是啥,说实话我也不太清楚,官方说的就叫这哈,其实他说的就是平时最常用的那些 @Component @Service @Controller @Repository @Configuration 注解。

如果一个类被打上 @Component注解,那他就会被容器扫描到并加入到容器里去。那这里我们用spring的方式再来实现一下上篇文章的获取英雄的需求。

先给 Diana这个英雄打上一个 @Component注解:

@Component
public class Diana{
private String skillName = "Diana R"; public Diana() {
} public void q(){
System.out.println("Diana Q");
} public void w(){
System.out.println("Diana W");
} public void e(){
System.out.println("Diana E");
} public void r(){
System.out.println(this.skillName);
}
}

假设现在有一个Controller需要用到 Diana

@RestController
public class BannerController { @Autowired
private Diana diana; @RequestMapping(value = "/v2/banner", method = {RequestMethod.GET})
public String test() {
diana.r();
return "Hello SpringBoot";
}
}

@Autowired的意思就是说在这里注入一个对象,然后我们启动应用,

通过浏览器访问 http://localhost:8081/v2/banner,会发现在控制台会输出 Diana的r方法的打印内容,说明这里确实拿到了 Diana这个对象。

对象的注入时机

如果我们把 Diana@Component注解去掉,其他地方不变,再运行程序会发生什么,试试看。

重新启动的时候会提示我们下面的错误:

看错误提示,说程序没有找到对应的bean,就是说我这里要注入bean了,但是在容器里没有找到。

这里就会得出一个结论:容器在初始化后就会给相应的代码片段进行对象的注入

从提示信息中可以看到Autowired(required=true),这里设置的默认是true,表示注入的时候,该对象必须存在,否则就会注入失败。当然这里可设置不报错,Autowired(required=false),这个时候再启动就不会报错了,但是在访问的时候会报空指针异常。

那这里spring的容器究竟是在什么时候实例化的对象呢,是在访问controller的时候呢,还是在容器启动的时候呢?我们可以通过下面的手段检测一下,在 Diana的无参构造方法中放一个打印语句,然后再启动程序:

public Diana() {
System.out.println("I am Diana");
}

程序启动以后,会看到在控制台会显示出构造方法中打印的语句

这就说明在容器启动后把类加载到容器以后,就会实例化一个对象出来。这就又得出一个结论:容器初始化以后就会对bean进行实例化

对象的延迟注入

上面提到容器在确定后就会把对象(也就是bean)实例化,那有没有办法让他不马上实例化?

spring提供了@Lazy这个注解,用以表明某个bean可以延迟加载,用之前的 Diana延时一下,给他加上@Lazy这个注解:

@Component
@Lazy
public class Diana{
private String skillName = "Diana R"; public Diana() {
System.out.println("I am Diana");
} public void q(){
System.out.println("Diana Q");
} public void w(){
System.out.println("Diana W");
} public void e(){
System.out.println("Diana E");
} public void r(){
System.out.println(this.skillName);
}
}

再次启动程序,会发现在控制台还是会执行构造方法里的打印语句,这是什么情况,不是明明已经加了延迟加载了么?

这里会设计到spring的一个机制,就是说如果某个bean没有设置延迟加载,这个bean会在容器启动就实例化,并且这个bean里面所依赖的其他bean都会进行过实例化,即使设置了懒加载。

我们在BannerController里用到了 Diana这个bean,并把它设置了延迟加载,但是并没有把BannerController也设置成延迟加载,所以容器再实例化BannerController的时候同样会 Diana这个bean进行实例化。如果要真正做到延迟加载,需要让BannerController也要延迟加载。给它加上@Lazy以后,再启动看一下:

这个时候控制就没有那条打印语句的输出内容了,此时我们通过浏览器来访问BannerController的路由,此时就会在控制台输出构造方法里打印语句的输出内容了。

对象的注入逻辑

上文 Diana的就是一个单独的类,没有实现任何接口,这种实现方式他是有问题的,很难进行扩展,这里不应该一类具体的实现类,而是要应该依赖抽象,这样才能满足开闭原则,让程序具有良好的扩展性。

这里让 Diana实现了一 Skill接口,

public interface Skill {
void q();
void w();
void e();
void r();
}

在BannerController注入这里也要改一下:

@Autowired
private Skill diana;

运行程序,发先能够运行成功,如果新添加一个英雄的实现类:

@Component
public class Irelia implements Skill { public Irelia() {
System.out.println("Hello, Irelia");
}
public void q(){
System.out.println("Irelia Q");
} public void w(){
System.out.println("Irelia W");
} public void e(){
System.out.println("Irelia E");
} public void r(){
System.out.println("Irelia R");
}
}

我们再去运行程序,发现还是能运行成功,并且发现注入的是 Diana而不是 Irelia,那这里我们可能会问为什么呀,前面好像也没指定注入哪个实现类。

难道是因为 private Skill diana;这里写了 diana么?你还别说,还真是这个原因,这里涉及到spring的注入机制了。

当spring的IOC容器注入bean的时候,如果发现有多个相同类型的bean时,就会去看它们的名称(name),如果名称符合要求,就会注入这个名称的bean。每个被容器扫描到的bean都会有一个默认的name,就是它的类名,首字母会小写,比如我们实例中的:BannerController的name就是bannerController,Irelia就是irelia。

可以试着把 private Skill diana改成 private Skill skill,再次运行,就会发生报错:

提示你找不到响应的bean。这里要明确一点哈,虽然报错了,但是这种写法是标准的,上面那个直接写实现类的名字不是标准的写法。

那怎么解决这个找不到的问题呢?

spring提供了一个@Qualifier的注解,给他传入要注入bean的名字,就可以指定注入的bean,@Qualifier("irelia")。

总结

Autowired的注入方式有两种,一种是按照类型注入,一种是按照名称注入,默认是按照类型注入,如果只有一个实现类 Diana,这里写成 private Skill skill,运行程序,你会发现是能够注入成功的。因为Skill类型下只有一个实现类,自然就是注入它了。如果有多个实现类,那就会先按照这个类型查找,这个类型下所有到的实现类再按照名称查找,直至找到符合要求的,找不到就报错。

更多关于spring IOC内容,请查看(博客网站)[https://www.immortalp.com]

欢迎大家去 我的博客 瞅瞅,里面有更多关于测试实战的内容哦!!

Spring IOC的核心机制:实例化与注入的更多相关文章

  1. Spring进阶之路(1)-Spring核心机制:依赖注入/控制反转

    原文地址:http://blog.csdn.net/wangyang1354/article/details/50757098 我们经常会遇到这样一种情景,就是在我们开发项目的时候经常会在一个类中调用 ...

  2. 7 -- Spring的基本用法 -- 3... Spring 的核心机制 : 依赖注入

    7.3 Spring 的核心机制 : 依赖注入 Spring 框架的核心功能有两个. Spring容器作为超级大工厂,负责创建.管理所有的Java对象,这些Java对象被称为Bean. Spring容 ...

  3. Spring IOC容器核心流程源码分析

    简单介绍 Spring IOC的核心方法就在于refresh方法,这个方法里面完成了Spring的初始化.准备bean.实例化bean和扩展功能的实现. 这个方法的作用是什么? 它是如何完成这些功能的 ...

  4. Spring Ioc源码分析系列--自动注入循环依赖的处理

    Spring Ioc源码分析系列--自动注入循环依赖的处理 前言 前面的文章Spring Ioc源码分析系列--Bean实例化过程(二)在讲解到Spring创建bean出现循环依赖的时候并没有深入去分 ...

  5. (转)Spring读书笔记-----Spring核心机制:依赖注入

    Java应用(从applets的小范围到全套n层服务端企业应用)是一种典型的依赖型应用,它就是由一些互相适当地协作的对象构成的.因此,我们说这些对象间存在依赖关系.加入A组件调用了B组件的方法,我们就 ...

  6. Spring核心机制:依赖注入

    转载:http://www.cnblogs.com/chenssy/ Java应用(从applets的小范围到全套n层服务端企业应用)是一种典型的依赖型应用,它就是由一些互相适当地协作的对象构成的.因 ...

  7. Spring读书笔记-----Spring核心机制:依赖注入

    spring框架为我们提供了三种注入方式,分别是set注入,构造方法注入,接口注入.今天就和大家一起来学习一下 依赖注入的基本概念 依赖注入(Dependecy Injection),也称为IoC(I ...

  8. Spring的核心机制:依赖注入

    依赖注入的概念 当一个对象要调用另一个对象时,一般是new一个被调用的对象,示例: class  A{ private B b=new B(); public  void  test(){ b.say ...

  9. 学习Spring IOC控制反转和DI依赖注入总结

    30岁的小曹,20岁的身体,还在坚持在能力允许控制范围内22点睡觉,5点起床锻炼身体,好好学习,除了加班或者像今天这样的深夜,再一次写已经有X百万人写过的 spring Ioc 的总结博客. 一.IO ...

随机推荐

  1. 在Sping的配置文件中,关于dataSource的配置,就我们常用的方法大致可以有三种:

    在Sping的配置文件中,关于dataSource的配置,就我们常用的方法大致可以有三种: 1.一般的配置方法,直接在配置中指定其值.具体的例子我们参照Mysql的配置如下: <bean id= ...

  2. 绕过XSS过滤姿势总结

    0x01 弹窗关键字检测绕过 基本WAF都针对常用的弹窗函数做了拦截,如alert().prompt().confirm(),另外还有代码执行函数eval(),想要绕过去也比较简单,我们以alert( ...

  3. Salesforce考试 | 如何维护我的Salesforce认证

    问题1 Salesforce证书是需要每年维护吗? Salesforce每年会发布3次Realese,分别是Spring.Summer和Winter,可以理解为一年3次的系统新版本更新,每次Relea ...

  4. Python-selenium-自动化测试模型

    1.线性测试 优势:每一个脚本都是完整独立的,每一个脚本对应一个测试用例 缺点:开发成本高,会有重复操作重复脚本:维护成本也高,修改重复操作的脚本时,要逐一进行修改. 2.模块化驱动测试 把重复的操作 ...

  5. 数据结构之栈—强大的四则复杂运算计算器(超过windows自带的科学计算器)【中缀转后缀表达式】

    比windows自带计算器还强的四则复杂运算计算器! 实测随机打出两组复杂算式:-7.5 * 6 / ( -2 + ( -6.5 -  -5.22 ) )与7.5+-3*8/(7+2) windows ...

  6. Connections in Galaxy War ZOJ - 3261 (并查集)

    点权并查集的反向离线操作 题目大意:有n个stars,每一个都一定的“颜值”.然后stars与stars之间可以相连,query c表示再与c相连的stars中,颜值比c高的,stars的标号,如果有 ...

  7. google protobuf c++ 反射

    const Descriptor *desc = DescriptorPool::generated_pool()->FindMessageTypeByName(msg_name); asser ...

  8. Go gRPC进阶-proto数据验证(九)

    前言 上篇介绍了go-grpc-middleware的grpc_zap.grpc_auth和grpc_recovery使用,本篇将介绍grpc_validator,它可以对gRPC数据的输入和输出进行 ...

  9. [php代码审计]bluecms v1.6 sp1

    一.环境搭建 bluecms v1.6 sp1源码 windows 7 phpstudy2016(php 5.4.45) seay源代码审计系统 源码在网上很容易下载,很多教程说访问地址 http:/ ...

  10. Redis 5.0.9 安装

    目录 系统环境 系统版本 内核版本 安装步骤 安装 gcc 依赖 下载 Redis 解压 Redis 切换到 redis 解压目录下,执行编译 指定目录安装 启动 Redis 服务 最后 系统环境 系 ...