Spring深入 1.IOC核⼼理论回顾

⼀、IOC核⼼理论回顾

知识点:

1.IOC理念该要
2.实体Bean的创建
3.Bean的基本特性
4.依赖注入

1、Ioc理论概要

在JAVA的世界中,⼀个对象A怎么才能调⽤对象B?通常有以下⼏种⽅法。

类别 描述 时间点
外部传入 构造方法传入 创建引⽤对象时
外部传入 属性设置传入 设置对象状态时
外部传入 运行时做为参数传入 调用时
内部创建 属性中直接创建 创建引用对象时
内部创建 初始化方法创建 创建引用对象时
内部创建 运行时动态创建 调用时

上表可以看到, 引用一个对象可以在不同地点(其它引用者)、不同时间由不同的方法完成。如果B只是一个非常简单的对象 如直接new B(),怎样都不会觉得复杂,比如你从来不会觉得创建一个String 是一个件复杂的事情。但如果B 是一个有着复杂依赖的Service对象,这时在不同时机引用B将会变得很复杂。


image.png

⽆时⽆刻都要维护B的复杂依赖关系,试想B对象如果项⽬中有上百过,系统复杂度将会成陪 数增加。 IOC容器的出现正是为解决这⼀问题,其可以将对象的构建⽅式统⼀,并且⾃动维护对象的依 赖关系,从⽽降低系统的实现成本。前提是需要提前对⽬标对象基于XML进⾏声明。

2、实体Bean的构建

  • a. 基于Class构建
  • b. 构造⽅法构建
  • c. 静态⼯⼚⽅法创建
  • d. FactoryBean创建
1、基于ClassName构建
<bean class="com.kpioneer.springdemo.HelloSpring"></bean>

这是最常规的⽅法,其原理是在spring底层会基于class 属性 通过反射进⾏构建。

2、构造⽅法构建
<bean class="com.kpioneer.springdemo.HelloSpring"> 
  <constructor-arg name="name" type="java.lang.String" value="zhangsan"/> 
  <constructor-arg index="1" type="java.lang.String" value="sex" /> 
</bean>

如果需要基于参数进⾏构建,就采⽤构造⽅法构建,其对应属性如下:
name:构造⽅法参数变量名称
type:参数类型
index:参数索引,从0开始
value:参数值,spring 会⾃动转换成参数实际类型值
ref:引⽤容串的其它对象

3、静态⼯⼚⽅法创建
<!--    静态工厂方法构建-->
<bean class="com.kpioneer.springdemo.HelloSpring" factory-method="build">
    <constructor-arg name="type" value="A"/>
</bean>

如果你正在对⼀个对象进⾏A/B测试 ,就可以采⽤静态⼯⼚⽅法的⽅式创建,其于策略 创建不同的对像或填充不同的属性。 该模式下必须创建⼀个静态⼯⼚⽅法,并且⽅法返回该实例,spring 会调⽤该静态⽅法 创建对象。

    public static HelloSpring build(String type) {
        if("A".equals(type)){
            return new HelloSpring("Lucy",1);
        }else if("B".equals(type)){
            return new HelloSpring("Jack",0);
        }else {
            throw new IllegalArgumentException("参数不合法");
        }
    }
4、FactoryBean创建
   <bean id="driver" class="com.kpioneer.springdemo.DriverFactoryBean">
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306"/>
    </bean>

指定⼀个Bean⼯⼚来创建对象,对象构建初始化 完全交给该⼯⼚来实现。配置Bean时指定该 ⼯⼚类的类名。

public class DriverFactoryBean implements FactoryBean {
    private String jdbcUrl;

    @Override
    public Object getObject() throws Exception {
         return DriverManager.getDriver(jdbcUrl);

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

    }
    @Override
    public boolean isSingleton() {
         return true;

    }

    public String getJdbcUrl() {
         return jdbcUrl;

    }

    public void setJdbcUrl(String jdbcUrl) {
         this.jdbcUrl = jdbcUrl;

    }
}
public class SpringIocTest {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        System.out.println(context.getBean("driver").toString());
    }
}

输出结果

com.mysql.cj.jdbc.Driver@6eceb130

说明
通过Factorybean来配置bean的实例,通过class来指向Factorybean的全类名,property指的factory的属性,我们在配置bean的时候经常需要用的ioc容器里的其他bean,在Factorybean中处理你传入的其他bean以达到目的。

但实际返回的的是getObject方法返回的实例。

3、bean的基本特性

  • 作用范围
  • 生命周期
  • 装载机制
a、作用范围

很多时候Bean对象是无状态的 ,而有些又是有状态的 无状态的对象我们采用单例即可,而有状态则必须是多例的模式,通过scope 即可创建
scope=“prototype”
scope=“singleton”

<bean class="com.kpioneer.springdemo.HelloSpring" scope="prototype">
</bean>

如果一个Bean设置成 prototype 我们可以 通过BeanFactoryAware 获取 BeanFactory 对象即可每次获取的都是新对像。

b、生命周期

Bean对象的创建、初始化、销毁即是Bean的生命周期。通过 init-method、destroy-method 属性可以分别指定期构建方法与初始方法。

<bean class="com.kpioneer.springdemo.HelloSpring" init-method="init" destroy-method="destroy"></bean>

如果觉得麻烦,可以让Bean去实现 InitializingBean.afterPropertiesSet()、DisposableBean.destroy()方法。分别对应 初始和销毁方法

c、加载机制

指示Bean在何时进行加载。设置lazy-init 即可,其值如下:
true: 懒加载,即延迟加载
false:非懒加载,容器启动时即创建对象
default:默认,采用default-lazy-init 中指定值,如果default-lazy-init 没指定就是false

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
default-lazy-init="true">
什么时候使用懒加载?
懒加载会容器启动的更快,而非懒加载可以容器启动时更快的发现程序当中的错误 ,选择哪一个就看追求的是启动速度,还是希望更早的发现错误,一般我们会选择后者。

4、依赖注入

试想IOC中如果没有依赖注入,那这个框架就只能帮助我们构建一些简单的Bean,而之前所说的复杂Bean的构建问题将无法解决,spring这个框架不可能会像现在这样成功。 spring 中 ioc 如何依赖注入呢。有以下几种方式:

  1. set方法注入
  2. 构造方法注入
  3. 自动注入(byName、byType)
  4. 方法注入(lookup-method)
1、set方法注入
<bean class="com.tuling.spring.HelloSpring">
    <property name="fine" ref="fineSpring"/>
</bean>
2、构造方法注入
<bean class="com.tuling.spring.HelloSpring">
    <constructor-arg name="fine">
        <bean class="com.tuling.spring.FineSpring"/>
    </constructor-arg>
</bean>
3、自动注入(byName\byType\constructor)
<bean id="helloSpringAutowireConstructor" class="com.tuling.spring.HelloSpring" autowire="byName">
</bean>

byName:基于变量名与bean 名称相同作为依据插入
byType:基于变量类别与bean 名称作
constructor:基于IOC中bean 与构造方法进行匹配(语义模糊,不推荐)

4、依赖方法注入(lookup-method)

当一个单例的Bean,依赖于一个多例的Bean,用常规方法只会被注入一次,如果每次都想要获取一个全新实例就可以采用lookup-method 方法来实现。

public abstract class MethodInject {

    public void sayHello(){
        System.out.println("sayHello");
        getHi();
    }
    public abstract Hi getHi();
}

// 设定抽像方法实现

 <bean id="MethodInject" class="com.kpioneer.springdemo.MethodInject">
        <lookup-method name="getHi"></lookup-method>
    </bean>

该操作的原理是基于动态代理技术,重新生成一个继承至目标类,然后重写抽像方法到达注入目的。
前面说所单例Bean依赖多例Bean这种情况也可以通过实现 ApplicationContextAware 、BeanFactoryAware 接口来获取BeanFactory 实例,从而可以直接调用getBean方法获取新实例,推荐使用该方法,相比lookup-method语义逻辑更清楚一些。

特别感谢:

图灵学院

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,377评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,390评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,967评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,344评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,441评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,492评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,497评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,274评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,732评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,008评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,184评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,837评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,520评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,156评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,407评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,056评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,074评论 2 352