Spring学习之IOC和DI
首先我想明确它们之间的关系:
- IOC:控制反转,把创建对象的过程交给Spring去管理,自己不做任何关注。
- DI:依赖注入,向Bean里的属性进行设值。
- DI是不可以自己独立进行工作的,必须要在IOC的基础上完成工作,也可以理解为DI是IOC的一种实现。
什么是IOC?
- 首先我想谈一下我自己的想法
IOC全名是Inverse Of Control,意思是控制反转,那么这个控制反转到底是什么意思呢?通俗一点可以这样子理解:众所周知,在java程序中,完成每个业务逻辑必须至少需要两个或以上的对象来协助完成。在传统编程中,假设我的程序中存在两个对象A和B,当A需要B的一些帮助,我们必须去手动实例化这个对象(类似new object()这样子的语法),而IOC的思想是:我们可以把对象之间的引用关系交给Spring来管理,对象的创建、维护、销毁等生命周期的这些操作程序人员完全不用自己关注,全权交给Spring容器,其实这样就把控制权交给了Spring,所以就叫做控制反转。
- Bean的生命周期
在spring中,从BeanFactory或ApplicationContext取得的实例为Singleton,也就说每一个Bean的别名只能维持一个实例,而不是每次都产生一个新的对象。
- 注入的三种方式
- 基于XML的bean定义(需要提供setter方法)
首先定义Student和Teacher类。
package com.demo.ioc.Bean;
public class Student {
private String name;
private Teacher teacher;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
}
package com.demo.ioc.Bean;
public class Teacher {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
bean1.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="student" class="com.demo.ioc.Bean.Student">
<property name="name" value="张三"/>
<property name="teacher" ref="teacher"/>
</bean>
<bean id="teacher" class="com.demo.ioc.Bean.Teacher">
<property name="name" value="李四"/>
</bean>
</beans>
package com.demo.ioc.spring;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import com.demo.ioc.Bean.Student;
import com.demo.ioc.Bean.Teacher;
public class Main {
public static void main(String args[]) throws Exception{
FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("src/main/resources/bean1.xml");
Student student = (Student) context.getBean("student");
Teacher teacher = (Teacher) context.getBean("teacher");
System.out.println("学生的姓名:"+student.getName()+"。老师是"+student.getTeacher().getName());
System.out.println("老师的姓名:"+teacher.getName());
}
}
- 基于注解的bean定义(不需要提供setter方法)
package com.demo.ioc.Bean;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("student")
public class Student {
@Value("张三")
private String name;
@Resource
private Teacher teacher;
public String getName() {
return name;
}
// public void setName(String name) {
// this.name = name;
// }
public Teacher getTeacher() {
return teacher;
}
// public void setTeacher(Teacher teacher) {
// this.teacher = teacher;
// }
}
package com.demo.ioc.Bean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("teacher")
public class Teacher {
@Value("李四")
private String name;
public String getName() {
return name;
}
// public void setName(String name) {
// this.name = name;
// }
}
bean2.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"
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
http://www.springframework.org/schema/context/spring-context.xsd">
<!--扫描组件的包目录-->
<context:component-scan base-package="com.demo.ioc.Bean"/>
</beans>
package com.demo.ioc.spring;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import com.demo.ioc.Bean.Student;
import com.demo.ioc.Bean.Teacher;
public class Main {
public static void main(String args[]) throws Exception{
FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("src/main/resources/bean2.xml");
Student student = (Student) context.getBean("student");
Teacher teacher = (Teacher) context.getBean("teacher");
System.out.println("学生的姓名:"+student.getName()+"。老师是"+student.getTeacher().getName());
System.out.println("老师的姓名:"+teacher.getName());
}
}
- 基于JavaConfig定义(需要提供setter方法)
package com.demo.ioc.Bean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class BeansConfiguration {
@Bean
public Student student(){
Student student=new Student();
student.setName("张三");
student.setTeacher(teacher());
return student;
}
@Bean
public Teacher teacher(){
Teacher teacher=new Teacher();
teacher.setName("李四");
return teacher;
}
}
package com.demo.ioc.spring;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.demo.ioc.Bean.BeansConfiguration;
import com.demo.ioc.Bean.Student;
import com.demo.ioc.Bean.Teacher;
public class Main {
public static void main(String args[]) throws Exception{
AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(BeansConfiguration.class);
// FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("src/main/resources/bean2.xml");
Student student = (Student) context.getBean("student");
Teacher teacher = (Teacher) context.getBean("teacher");
System.out.println("学生的姓名:"+student.getName()+"。老师是"+student.getTeacher().getName());
System.out.println("老师的姓名:"+teacher.getName());
}
}
-
容器中Bean的作用域
-
当通过Spring容器创建一个Bean实例时,不仅可以完成Bean实例的实例化,还可以为Bean指定特定的作用域。Spring支持如下五种作用域:
- singleton: 单例模式,在整个Spring IoC容器中,singleton作用域的Bean将只生成一个实例。
- prototype: 每次通过容器的getBean()方法获取prototype作用域的Bean时,都将产生一个新的Bean实例。
- request:对于一次HTTP请求,request作用域的Bean将只生成一个实例,这意味着,在同一次HTTP请求内,程序每次请求该Bean,得到的总是同一个实例。只有在Web应用中使用Spring时,该作用域才真正有效。
- session:该作用域将 bean 的定义限制为 HTTP 会话。 只在web-aware Spring ApplicationContext的上下文中有效。
- global session: 每个全局的HTTP Session对应一个Bean实例。在典型的情况下,仅在使用portlet context的时候有效,同样只在Web应用中有效。
-
-
如何实现IOC
- Spring IOC的实现用到了设计模式:简单工厂模式+反射来实现IoC。
BeanFactory和ApplicationContext的区别
ApplicationContext接口,它由BeanFactory接口派生而来,因而提供BeanFactory所有的功能。ApplicationContext以一种更向面向框架的方式工作以及对上下文进行分层和实现继承,最主要的就是BeanFactory延迟加载,当使用到getBean的时候才会抛异常,而ApplicationContext在刚开始启动加载的时候就会抛出异常,这样有利于检查所依赖属性是否注入;所以通常情况下我们选择使用ApplicationContext。
什么是DI?
- 全称为Dependency Injection,意思自身对象中的内置对象是通过注入的方式进行创建。
- 它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,Spring就是通过反射来实现注入的。
- 其实我个人觉得IOC和DI是一个东西。
public static Object newInstance(String className) {
Class<?> cls = null;
Object obj = null;
try {
cls = Class.forName(className);
obj = cls.newInstance();
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
return obj;
}
为什么要使用IOC?
在IOC出现以前,组件之间的协调关系是由程序内部代码来控制的,或者说,以前我们使用New关键字来实现两组间之间的依赖关系的。这种方式就造成了组件之间的互相耦合。IoC(控制反转)就是来解决这个问题的,它将实现组件间的关系从程序内部提到外部容器来管理。也就是说,由容器在运行期将组件间的某种依赖关系动态的注入组件中。
推荐阅读
-
linux命令学习之10个网络命令和监控命令
-
Spring的IOC和DI(案例+解析)
-
Python ORM框架SQLAlchemy学习笔记之数据添加和事务回滚介绍
-
Python ORM框架SQLAlchemy学习笔记之安装和简单查询实例
-
Python ORM框架SQLAlchemy学习笔记之映射类使用实例和Session会话介绍
-
IOS开发之关于alloc 、init和new学习讲解
-
C#多线程学习之(三)生产者和消费者用法分析
-
vue.js学习笔记之绑定style样式和class列表
-
Android学习之Intent中显示意图和隐式意图的用法实例分析
-
Spring学习之Bean的装配多种方法