spring专题系列之IOC的理解和分析

70 篇文章 1 订阅
  • 什么是IOC?如何使用案例来理解?
  • IOC有哪几种实现方式?
  • IOC的底层实现过程是什么?

根据这几个角度,开始今天的故事,

1 什么是IOC?

对于IOC的理解,主要是停留在概念和几种注入的方式上,虽然知道其生命周期,但是对整个bean管理的宏观角度,理解的不够深刻。

IOC:控制反转(Inversion of Control)容器,它是一种设计思想。意味着将你设计好的对象交给容器控制。

1.1 什么是依赖注入

这个概念的理解,我准备使用一个案例来表示。如果a类中包含了b类,就说明a类对b类产生了依赖。如一个人需要车,这就说人对车产生了依赖。

class User{ 
  Car car; 
  public User(){ 
    car=new Car(); 
  } 
}

上面这个案例,可以看到,在User类中,包含了Car类,也就说User类对Car类产生了依赖。

按照传统的方式,User类如果想要使用Car基本上就是在内部new一个新对象即可。但是这样做缺点很大,new的方式也就意味着User和Car产生了紧耦合。不利于大规模使用。于是使用了另外一种方式可以代替。那就是什么时候用到Car,从外部直接传递过来就好。这样的话,耦合性就大大降低了。再看下面这种形式是不是就好很多了。

class User{ 
  Car car; 
  public User(Car car){ 
    this.car=car; 
  } 
}

像这样的方式就是依赖注入,也就是把依赖Car注入到了User中。

1.2 什么是控制反转

有了上面依赖注入的概念,再理解控制反转就比较简单了。

  • 谁控制谁:传统方式User是在内部new,现在我们通过依赖注入的方式注入依赖对象Car。现在spring出现了,发明了IOC,IOC里面有一个容器,这些依赖对象全部交给容器去管理。也就是说这些依赖对象的控制权交给了容器。
  • 如何反转:传统方式User是主动去new,这种方式是正转。反转是由容器来帮忙创建及注入依赖对象;

2 依赖注入的几种形式

目前主要有五种注入方式:SET注入,构造器注入,静态工厂,实例工厂。

下面看几种依赖注入的几种实现方式。

2.1 set注入

直接上代码:

package com.jie;

/**
 * Created by jie on 2022/1/13.
 */
public class HelloStr {
    private HelloService helloService;

    // setter方式注入Bean
    public void setHelloService(HelloService helloService) {
        this.helloService = helloService;
    }

    public void selfIntroduction() {
        // 向大家打招呼
        helloService.sayHello("大家好! 这是setter注入方式");
    }
}
<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
">
    <!--
       Bean声明:
         该bean类似于javaConfig中的@Bean注解;
         用于创建bean的类通过class属性来指定,并且需要使用全限定的类名。
         通过id指定bean的ID。如果不显示指定,默认使用class的全限定名进行命名。
         eg:

         用来区分相同类型的其他bean。
         使用自动化命名很方便,但是没有多少实际用处,还是建议自己给bean显示设定ID。
     -->
    <bean id="helloService" class="com.jie.HelloService"/>

    <!-- setter注入bean -->
    <bean id="helloStr" class="com.jie.HelloStr">
        <property name="helloService" ref="helloService"/>
    </bean>
    <!-- 构造器注入bean -->
    <bean id="helloStrForConstruction" class="com.jie.HelloStrForConstruction">
        <constructor-arg><ref bean="helloService"/></constructor-arg>
    </bean>

    <!-- P标签注入bean -->
    <bean id="helloStrForP" class="com.jie.HelloStrForP" p:name="明明" p:age="24" p:helloService-ref="helloService">
    </bean>

    <bean id="collection" class="com.jie.ALLCollection">
        <property name="listElement">
            <list>
                <value>list苹果</value>
                <value>list香蕉</value>
            </list>
        </property>
        <property name="setElement">
            <set>
                <value>set苹果</value>
                <value>set香蕉</value>
            </set>
        </property>
        <property name="mapElement">
            <map>
                <entry>
                    <key><value>map1</value></key>
                    <value>map苹果</value>
                </entry>
                <entry>
                    <key><value>map2</value></key>
                    <value>map香蕉</value>
                </entry>
            </map>
        </property>
        <property name="propsElement">
            <props>
                <prop key="prop1">prop苹果</prop>
                <prop key="porp2">prop香蕉</prop>
            </props>
        </property>
    </bean>
</beans>

这个xml的配置下面几种方式的都包含在内

import com.jie.HelloStr;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created by jie on 2022/1/13.
 */
public class MyTestSetter {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        HelloStr hello = (HelloStr) context.getBean("helloStr",HelloStr.class);

        hello.selfIntroduction();

        System.out.println("ok");
    }
}

这种方式简单易操作。

2.2 构造器注入

直接上代码

package com.jie;

/**
 * Created by jie on 2022/1/13.
 */
public class HelloStrForConstruction {
    private  HelloService helloService;

    public HelloStrForConstruction(HelloService helloService)
    {
        this.helloService = helloService;
    }
    public void selfIntroduction() {
        // 向大家打招呼
        helloService.sayHello("大家好! 这是构造器注入方式");
    }
}
import com.jie.HelloStrForConstruction;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created by jie on 2022/1/13.
 */
public class MyTestConstruction {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        HelloStrForConstruction hello = (HelloStrForConstruction) context.getBean("helloStrForConstruction",HelloStrForConstruction.class);

        hello.selfIntroduction();
        System.out.println("ok");
    }
}

P标签方式注入

package com.jie;

/**
 * Created by jie on 2022/1/13.
 */
public class HelloStrForP {
    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    private String name;

    private  HelloService helloService;

    public void setHelloService(HelloService helloService) {
        this.helloService = helloService;
    }


    @Override
    public String toString() {
        return "HelloStrForP{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", helloService=" + helloService +
                '}';
    }

    public void selfIntroduction() {
        // 向大家打招呼
        helloService.sayHello("大家好! 这是P标签注入方式");
        System.out.println(toString());
    }
}
import com.jie.HelloStrForConstruction;
import com.jie.HelloStrForP;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created by jie on 2022/1/13.
 */
public class MyTestP {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        HelloStrForP hello = (HelloStrForP) context.getBean("helloStrForP",HelloStrForP.class);

        hello.selfIntroduction();
        System.out.println("ok");
    }
}

2.3 静态工厂注入

第一步:XML配置

<?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="userDao01" class="com.xxx.demo.StaticFactory" factory-method="createuserDao"></bean>
 <bean id="userService01" class="com.xxx.demo.UserService">
  <property name="userDao" ref="userDao01"></property>
 </bean>
</beans>

第二步:定义静态工厂

public class StaticFactory {
 public static UserDao createuserDao(){
  return new UserDao();
 }
}

第三部:静态工厂注入

public class UserService {
 private UserDao userDao;
 public void userlogin() {
  String res=userDao.userLogin();
  System.out.println(res);
 }
 public void setUserDao(UserDao userDao) {
  this.userDao = userDao;
 }
}

2.4 实例化工厂

第一步:XML配置

<?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="instanceFactory" class="com.xxx.demo.InstanceFactory"></bean>
 <bean id="userDao3" factory-bean="instanceFactory" factory-method="createUserDao"></bean>
 <bean id="userService02" class="com.xxx.demo.UserService">
  <property name="userDao" ref="userDao3"></property>
 </bean>
</beans>

第二步:工厂注入

public class InstanceFactory {
 public UserDao createUserDao(){
  return new UserDao();
 }
}

以上就是几种常见的注入方式。在开发中比较常用。知道了IOC的概念和几种实现方式之后,下面主要探讨IOC的底层实现原理。

3 IOC底层实现过程

以上的几种注入方式,可能有个疑问,那就是bean是如何从xml,再到注入类中的呢?看下面这张图

Spring IOC容器初始化的核心过程主要有四个步骤(还有一些如:后置加载器,国际化,事件广播器等一些过程不展开):

  1. Bean定义的定位,Bean 可能定义在XML中,或者一个注解,或者其他形式。这些都被用Resource来定位,读取Resource获取BeanDefinition 注册到 Bean定义注册表中。
  2. 第一次向容器getBean操作会触发Bean的创建过程,实列化一个Bean时 ,根据BeanDefinition中类信息等实列化Bean。
  3. 将实列化的Bean放到单列Bean缓存内。
  4. 此后再次获取向容器getBean就会从缓存中获取。

这张图是核心的过程。这个过程是已经简化了,具体的实现方式要设计到bean的生命周期的管理。安排到下一章节了。 spring的核心内容就是aop和ioc,知道了这俩是如何实现的之后,就是核心bean管理的核心实现,最后对配置文件进行介绍。

上面的部分代码可下载: helloIoc.zipspringioc控制反转简单测试代码-Java文档类资源-CSDN下载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值