spring框架核心容器 --- IOC

        IoC:Inverse of Control(控制反转)

        读作“反转控制”,更好理解,不是什么技术,而是一种设计思想,就是将原本在程序中手动创建对象的控制权,交由Spring框架来管理。
        正控:若要使用某个对象,需要自己去负责对象的创建
        反控:若要使用某个对象,只需要从 Spring 容器中获取需要使用的对象,不关心对象的创建过程,也就是把创建对象的控制权反转给了Spring框架
        好莱坞法则:Don’t call me ,I’ll call you

例子:

     比如 我现在饿了,想吃蛋炒饭,吃蛋炒饭让我不饿是我最终的目的。这样一来有两个解决办法:

           1. 拿两颗鸡蛋,再拿一点米饭,一起炒;我们自己去做了这个饭。

           2. 在美团上订,让饭店厨师给我一份蛋炒饭,外卖小哥再送到我手中。

     两个办法都能解决我们的问题,都能达到吃蛋炒饭的目的。但是这两个办法却代表完全不一样的权限控制。

    方法1是正控,即我们自己做了蛋炒饭,一切的行为都是我们自己完成的。

    方法2是反控,我们将做蛋炒饭这个权限交给了饭店厨师,由他来控制做蛋炒饭。我们的目的只需要得到一份蛋炒饭。


办法模拟:

    方法1:

package com.ico.food;

public class MakeFood {
    public void make(){
        System.out.println("放入鸡蛋!");
        System.out.println("放入饭翻炒!");
        System.out.println("我自己做的蛋炒饭做好了!");
    }
}

测试方法:

@Test
public void eatFood1(){
   MakeFood makeFood = new MakeFood();

   makeFood.make();

}

输出结果:

Spring框架个人理解 --- IOC(图1)


方法2:

创建实体类baen,即做蛋炒饭所需。

package com.ico.food;

public class Food {

    String egg;
    String rice;

    public String getEgg() {
        return egg;
    }

    public void setEgg(String egg) {
        this.egg = egg;
    }

    public String getRice() {
        return rice;
    }

    public void setRice(String rice) {
        this.rice = rice;
    }
}

这个Food实体类可以理解成,我们付的钱,饭店做蛋炒饭,我们付的钱一部分用于原料,一部分用于制作费。这个即是原料费;

创建制作对象

package com.ico.food;

public class MakeFoodIOC {
    Food food;

    public Food getFood() {
        return food;
    }

    public void setFood(Food food) {
        this.food = food;
    }

    public void make(){
        System.out.println("放入"+food.getEgg()+"!");
        System.out.println("放入"+food.getRice()+"翻炒!");
        System.out.println("IOC做的蛋炒饭做好了!");
    }
}

这个可以理解为做好的蛋炒饭,当然,加工费也在里面,就是 make()方法;


测试:

@Test
public void eatFood2(){
    ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
    //获得指定的 bean。这个方法使用 bean 的 ID 返回一个最终可以转换为实际对象的通用对象
    MakeFoodIOC makeFood =(MakeFoodIOC) applicationContext.getBean("makeFoodIOC");

    makeFood.make();

}

结果:

Spring框架个人理解 --- IOC(图2)


可以看见,上面两种方法,不同的地方;

   方法一,自己自己制作蛋炒饭,不需要其他东西,直接自己可以制作;

   方法二,提供好做蛋炒饭所需要的,即 鸡蛋,米饭,再付一些加工费,就可以让ioc给我们做一份蛋炒饭;


spring ioc使用:

首先创建一个maven工程,导入坐标

<!--单元测试-->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
</dependency>
<!--      Spring-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.7.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.7.RELEASE</version>
</dependency>

配置spring,约束千万不能导错,可以直接复制过去,可以看见里面有,这个配置文件是上面方法2,的配置,里面两个<bean>是将MakeFoodIOC和Food注入IOC容器,交给Spring来管理;

<?xml version="1.0" encoding="UTF-8"?>
<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">


    <bean id="makeFoodIOC" class="com.ico.food.MakeFoodIOC">

        <property name="food" ref="food"> </property>
    </bean>

    <bean id="food" class="com.ico.food.Food">
        <property name="egg" value="鸡蛋"></property>
        <property name="rice" value="米饭"></property>
    </bean>

</beans>

再看测试方法:

@Test
public void eatFood2(){
    ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml"); //加载spring的xml配置文件,创建IOC核心容器
    //获得指定的 bean。这个方法使用 bean 的 ID 返回一个最终可以转换为实际对象的通用对象
    MakeFoodIOC makeFood =(MakeFoodIOC) applicationContext.getBean("makeFoodIOC");

    makeFood.make();

}


spring ioc注入方法:

iox注入方式有两种,注解配置和XML文件配置,以下优缺点都是相对的.

  1. 通过XML配置文件注入,优点 :  便于后期维护,缺点: 代码量比较大

    XML文件配置,就像上面一样,


    <bean id="makeFoodIOC" class="com.ico.food.MakeFoodIOC">

        <property name="food" ref="food"> </property>
    </bean>

    <bean id="food" class="com.ico.food.Food">
        <property name="egg" value="鸡蛋"></property>
        <property name="rice" value="米饭"></property>
    </bean>

每一个bean里面都应该有  id(获取该对象是的依据)和class(指定将哪个对象注入),而bean下又有 <property>用于注入实体类时,所需一并注入要的参数,

   如果遇到基本类型 如 string,int,boolean,list,map等等,可以直接通过value注入,

   如果是复杂类型,如上面的Food,则需要将Food注入,然后再makeFoodIOC里面使用ref属性指向food.就可以将其注入了.


2.通过注解配置, 优点 : 代码简洁   缺点:不易维护

  使用注解配置需要在applicationContext.xml中添加 <context:annotation-config/>    来开启注解扫描,

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">


    <context:component-scan base-package="com.ico.food"/>  //扫描哪个包

</beans>

对于约束多了一行   xmlns:context="http://www.springframework.org/schema/context"     ,这是注解约束

那么Food代码在类上加上一个注解:  @Component("id名"),表示该类需要注入

package com.ico.food;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component("food")
public class Food {

    String egg;
    String rice;

    public String getEgg() {
        return egg;
    }

    public void setEgg(String egg) {
        this.egg = egg;
    }

    public String getRice() {
        return rice;
    }

    public void setRice(String rice) {
        this.rice = rice;
    }
}

MakeFoodIOC 也需要加入@Component("id名"),并且在成员 food上加入 @Autowired表示自动根据类型注入;但是需要提供set方法

package com.ico.food;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component("makeFoodIOC")
public class MakeFoodIOC {
    @Autowired
    Food food;

    public Food getFood() {
        return food;
    }

    public void setFood(Food food) {
        this.food = food;
    }

    public void make(){
        System.out.println("放入"+food.getEgg()+"!");
        System.out.println("放入"+food.getRice()+"翻炒!");
        System.out.println("IOC做的蛋炒饭做好了!");
    }
}


分析注解配置过程,Component注解表示该类需要被放入IOC容器中,

Autowired表示自动根据类型注入,他会去IOC容器中寻找是否有Food类型,如果有就注入,如果没有报错,如果有多个,也会报错,

那么刚刚的过程就是,两个类都被注入进了IOC中,而注入makeFoodIOC时,找到food,注入成功.


IOC注解:


1. 注册bean的注解(类级别)

1) @Component:通用注册bean的注解

2) @Service:注册service层的bean

3) @Repository:注册DAO层的bean

4) @Controller:注册控制层的bean

注意:上述四个注解可以给bean其名字,如果没有命名,则名字默认是类的名字的第一个字母小写

2. 注入bean的注解

1) @Autowired:自动注入bean,可以用在属性字段上,set方式上,构造器上

2) @Qualifier("bean名称"):和@Autowired配合使用,帮助@Autowired注入确定范围,可以用在方法的参数前

3) @Resource:这能用在set方法上,可以指定具体注册的bean名称 @Resource("bean名称")

3. 设置bean参数的注解

1) @Order(2):给相同类型的bean编序(类级别)

2) @Scope:设置bean的作用域,五个(类级别)

3) @PostConstruct:定义bean的初始化方法(方法级别)

4) @PreDestroy:定义bean的销毁方法(方法级别)

4. @bean注解

注册bean的注解(方法级别),和@Configuration配合使用(类级别)

//定义一个bean,名字自定义为stringStore,类型StringStore实现了Store 接口,初始化方法是init,结束方法是destroy

@Bean(name = "stringStore", initMethod="init", destroyMethod="destroy")

public Store stringStore() {

return new StringStore();

}

5. 获取外部文件数据的注解

1) @Configuration:配合下面一个注解使用(类级别)

2) @ImportResource("classpath:config.xml"):引入外部文件 config.xml(类级别)

3) @Value("${jdbc.username}"):将文件中的键值为jdbc.username的值注入成员变量中(字段级别)

6. 新注解

1) @Named:等价@Component+@Qualifier("bean名称"),可以在类上定义bean,还可以在字段和方法、参数上配合@Inject使用

2) @Inject:等价@Autowired

注意:收到spring的版本限制,需要引入javax.inject.jar包