IOC理论推导与简单的使用


Spring框架两大核心:IoC和DI

概念

  • IoC(Inversion of Control)简单来说就是将对象Object的创建的权力及对象的生命周期的管理过程交由Spring框架来处理,从此在开发过程中不在需要关注对象的创建和生命周期的管理,而是在需要的时候由Spring框架提供,这个由Spring框架管理对象创建和生命周期的机制称之为控制反转。
  • 在创建对象的过程中Spring可以依据对象的关系,自动把其它对象注入(无需创建对象,直接拿着使用)进来,这个过程称之为DI(Dependency Injection)依赖注入。

总结下Spring核心就干了两件事:

  • 创建对象
  • 设置对象的关联关系

IoC

IOC(Inversion of Control),控制反转。

就是指将对象的创建,对象的存储(map),对象的管理(依赖查找,依赖注入)交给了spring容器。
在这里插入图片描述

DI

DI(Dependency Injection)依赖注入 。

相对于IoC而言,依赖注入(DI)更加准确地描述了IoC的设计理念。所谓依赖注入,即组件之间的依赖关系由容器在应用系统运行期来决定,也就是由容器动态地将某种依赖关系的目标对象实例注入到应用系统中的各个关联的组件之中。
在这里插入图片描述

IOC理论推导

1、 IOC基础

建一个空白的maven项目

分析实现

我们先用我们原来的方式写一段代码 .

1、先写一个UserDao接口

   public interface UserDao {
       public void getUser();
    }

2、再去写Dao的实现类

   public class UserDaoImpl implements UserDao {
       @Override
       public void getUser() {
           System.out.println("获取用户数据");
      }
    }

3、然后去写UserService的接口

public interface UserService {
   public void getUser();
}

4、最后写Service的实现类

 public class UserServiceImpl implements UserService {
       private UserDao userDao = new UserDaoImpl();
    
       @Override
       public void getUser() {
           userDao.getUser();
      }
    }

5、测试一下

  @Test
    public void test(){
        // 用户实际调用的是业务层,dao层他们不需要接触
       UserService service = new UserServiceImpl();
       service.getUser();
    }

这是我们原来的方式 , 开始大家也都是这么去写的对吧 . 那我们现在修改一下 .

把Userdao的实现类增加一个 .

  public class UserDaoMySqlImpl implements UserDao {
       @Override
       public void getUser() {
           System.out.println("MySql获取用户数据");
      }
    }

紧接着我们要去使用MySql的话 , 我们就需要去service实现类里面修改对应的实现

  public class UserServiceImpl implements UserService {
       private UserDao userDao = new UserDaoMySqlImpl();
    
       @Override
       public void getUser() {
           userDao.getUser();
      }
    }

在假设, 我们再增加一个Userdao的实现类 .

public class UserDaoOracleImpl implements UserDao {   
		@Override  
 		public void getUser(){       
 		System.out.println("Oracle获取用户数据");  
 		}
 	}

那么我们要使用Oracle , 又需要去service实现类里面修改对应的实现 . 假设我们的这种需求非常大 , 这种方式就根本不适用了, 甚至反人类对吧 , 每次变动 , 都需要修改大量代码 . 这种设计的耦合性太高了, 牵一发而动全身 .
在这里插入图片描述

那我们如何去解决呢 ?

我们可以在需要用到他的地方 , 不去实现它 , 而是留出一个接口 , 利用set , 我们去代码里修改下 .在Service层的实现类(UserServiceImpl)增加一个Set()方法

public class UserServiceImpl implements UserService {
   private UserDao userDao;
// 利用set动态实现值的注入!
   public void setUserDao(UserDao userDao) {
       this.userDao = userDao;
  }

   @Override
   public void getUser() {
       userDao.getUser();
  }
}

set() 方法实际上是动态改变了 UserDao userDao 的初始化部分(new UserDaoImpl())

现在去我们的测试类里 , 进行测试 ;

  @Test
public void test(){
   UserServiceImpl service = new UserServiceImpl();
   service.setUserDao( new UserDaoMySqlImpl() );
   service.getUser();
   //那我们现在又想用Oracle去实现呢
   service.setUserDao( new UserDaoOracleImpl() );
   service.getUser();
}

我们还可以通过创建一个配置类来实现。【/resource/bean.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="mysqlImpl" class="com.zhu.dao.UserDaoMySqlImpl"/>
    <bean id="oracleImpl" class="com.zhu.dao.UserDaoOracleImpl"/>
    <bean id="daoImpl" class="com.zhu.dao.UserDaoImpl"/>
    <bean id="ServiceImpl" class="com.zhu.service.UserServiceImpl">
        <property name="userDao" ref="daoImpl"/>
    </bean>
</beans>

接着修改测试类

public class MyTest {
    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        UserServiceImpl serviceImpl = (UserServiceImpl) context.getBean("ServiceImpl");
        serviceImpl.getUser();
    }
}

区别:

  • 仔细去思考一下 , 以前所有东西都是由程序去进行控制创建 , 而现在是由我们自行控制创建对象 , 把主动权交给了调用者 . 程序不用去管怎么创建,怎么实现了 . 它只负责提供一个接口 .

这种思想 , 从本质上解决了问题 , 我们程序员不再去管理对象的创建了 , 更多的去关注业务的实现 . 耦合性大大降低 . 这也就是IOC的原型 !

2、 IOC本质

IOC本质

控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了

在这里插入图片描述

IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。

Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。

在这里插入图片描述

采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。

控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。

3、HelloSpring

第一个Spring IOC实例

导入Jar包

注 : spring 需要导入commons-logging进行日志记录 . 我们利用maven , 他会自动下载对应的依赖项 .

<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>5.1.10.RELEASE</version>
</dependency>

编写代码

1、编写一个Hello实体类

public class Hello {
    private String str;
    public String getStr() {
        return str;
    }
    public void setStr(String str) {
        this.str = str;
    }
    @Override
    public String toString() {
        return "Hello{" +
                "str='" + str + '\'' +
                '}';
    }
}

2、编写我们的spring文件 , 这里我们命名为beans.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">

<!--使用spring来创建对象,在spring这些都称为Bean
    bean就是java对象 , 由Spring创建和管理
-->
<!--使用Spring来创建对象,在spring这些都称为Bean
    类型  变量名  = new 类型();
    Hello   hello = new Hello();

    id = 变量名
    class = new 的对象
    property 相当于给对象中的属性设置一个值!
    -->
    <bean id="hello" class="com.zhu.pojo.Hello">
        <property name="str" value="Spring"/>
    </bean>
</beans>

3、我们可以去进行测试了 .

import com.zhu.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        //获取spring的上下文对象
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        //我们的对象现在都在Spring中的管理了,我们要使用,直接去里面取出来就可以!
        Hello hello = (Hello) context.getBean("hello");
        System.out.println(hello.toString());
    }
}

思考

  • Hello 对象是谁创建的 ?
    • 【hello 对象是由Spring创建的】
  • Hello 对象的属性是怎么设置的 ?
    • hello 对象的属性是由Spring容器设置的
    • 这个过程就叫控制反转 :
  • 控制 : 谁来控制对象的创建 ,
    • 传统应用程序的对象是由程序本身控制创建的 , 使用Spring后 , 对象是由Spring来创建的
  • 反转 : 程序本身不创建对象 , 而变成被动的接收对象 .

依赖注入 : 就是利用set方法来进行注入的.

IOC是一种编程思想,由主动的编程变成被动的接收

可以通过new ClassPathXmlApplicationContext去浏览一下底层源码 .

OK , 到了现在 , 我们彻底不用再程序中去改动了 , 要实现不同的操作 , 只需要在xml配置文件中进行修改 , 所谓的IoC,一句话搞定 :对象由Spring 来创建 , 管理 , 装配 !

修改第一个module

新增一个Spring配置文件beans.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="MysqlImpl" class="com.zhu.dao.UserDaoMySqlImpl"/>
   <bean id="OracleImpl"class="com.zhu.dao.UserDaoOracleImpl"/>
   <bean id="ServiceImpl"class="com.zhu.service.UserServiceImpl">
       <!--注意: 这里的name并不是属性 , 而是set方法后面的那部分 , 首字母小写-->
       <!--引用另外一个bean , 不是用value 而是用 ref-->
        <!--ref引用spring中已经创建很好的对象-->
        <!--value是一个具体的值,基本数据类型-->
       <property name="userDao" ref="OracleImpl"/>
   </bean>
</beans>

测试!

@Test
public void test2(){
//获取ApplicationContext:拿到spring的容器
   ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
   //需要什么就,get什么
   UserServiceImpl serviceImpl = (UserServiceImpl) context.getBean("ServiceImpl");
   serviceImpl.getUser();
}

总结:

所有的类都要装配的beans.xml 里面;

所有的bean 都要通过容器去取;

容器里面取得的bean,拿出来就是一个对象,用对象调用方法即可;

IOC的使用

1、IOC的注解方式

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>cn.tedu</groupId>
	<artifactId>spring</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<!-- 集中定义依赖版本号 -->
	<properties>
		<junit.version>4.10</junit.version>
		<spring.version>4.1.3.RELEASE</spring.version>
	</properties>

	<dependencies>
		<!-- 单元测试 -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>${junit.version}</version>
			<scope>test</scope>
		</dependency>

		<!-- Spring -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
		</dependency>

	</dependencies>
</project>

Hello.java

package spring;

import org.springframework.stereotype.Component;

@Component//让spring容器认识
public class Hello {
	public void hi() {
		System.out.println("Hello Spring.");
	}
}

applicationContext.xml

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	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-4.0.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
	http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">


	
<!-- 包扫描, 用注解的方式,配置bean 
		会扫描 指定包下,带@Component注解的类
		并注入spring容器中,key是类名小写,value是类的对象
	-->
	<context:component-scan base-package="cn.tedu" />
</beans>

TestIoC.java

package spring;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestIoC {
	@Test
	public void bean() {
		ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
		//根据id获取bean,beanname就是类名,首字母变小写
        Hello hello = (Hello) ac.getBean("hello");
		System.out.println(hello);
		hello.hi();
	}
}

2、IoC的XML方式

创建Hello.java

package spring;

public class Hello {
	public void hi() {
		System.out.println("Hello Spring.");
	}
}

创建applicationContext.xml
在这里插入图片描述
创建TestIoC.java

package spring;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestIoC {
	@Test
	public void bean() {
		ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
		Hello h1 = new Hello();
		System.out.println(h1);
		h1.hi();
		//根据id获取bean
        //Spring就是一个大工厂(容器)专门生成bean,bean就是对象
		Hello hello = (Hello)ac.getBean("Hello");
		System.out.println(hello);
		hello.hi();
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值