网站首页 > java教程 正文
IoC和DI简介
IoC(Inversion of Control)是“控制反转”的意思。如何理解“控制反转”这个词呢?
首先我们需要知道反转的是什么,是由谁来控制。在Spring框架没有出现之前,在Java面向对象的开发中,开发者通过new关键字完成对Object的创建。Spring框架诞生后,是通过Spring容器来管理对象的,因此Object的创建是通过Spring来完成的。最终得出结论:控制反转指的是由开发者来控制创建对象变成了由Spring容器来控制创建对象,创建对象和销毁对象的过程都由Spring来控制。以Spring框架为开发基础的应用尽量不要自己创建对象,应全部交由Spring容器管理。
DI(Dependency Injection)称为依赖注入。在Java程序中,类与类之间的耦合非常频繁,如Class A需要依赖Class B的对象b。而基于Spring框架的开发,在Class A中不需要显式地使用new关键字新建一个对象b,只需在对象b的声明之上加一行注解@Autowired,这样在Class A用到b时,Spring容器会主动完成对象b的创建和注入。这就是Class A依赖Spring容器的注入。通过上面的解释,我们可以发现IoC和DI其实是同一概念从不同角度的解释。
在Spring框架中,
org.springframework.context.ApplicationContext接口代表Spring IoC容器,它负责实例化、配置和组装Beans。容器通过读取元数据的配置来获取对象的实例化,以及配置和组装的描述信息。元数据可以用XML、Java注解或Java配置代码表示应用的对象及这些对象之间的内部依赖关系。
Spring框架提供了几个开箱即用的ApplicationContext接口的实现类,如
Class-PathXmlApplicationContext、
FileSystemXmlApplicationContext和AnnotationConfig ApplicationContext等。在独立应用程序中,通常创建一个
ClassPathXmlApplication-Context或
FileSystemXmlApplicationContext实例对象来获取XML的配置信息。
开发者也可以指示容器使用Java注解或Java配置作为元数据格式,通过
Annotation-ConfigApplicationContext来获取Java配置的Bean。
元数据配置
1. 基于XML的配置
Spring框架最早是通过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/bea
ns
https://www.springframework.org/schema/beans/spring
beans.xsd">
<!--定义UserService类 -->
<bean id="userService"
class="com.spring.boot.UserService">
<!--id属性 -->
<property name="id" value="1"/>
<!--name属性 -->
<property name="name" value="zhangsan"/>
</bean>
</beans>
在src/main/resources目录下新建spring.xml文件,内容如上面的代码所示,<bean>和</bean>标签用来描述Bean的元数据信息。在上面的代码中声明了一个UserService类,该类有两个属性,即id和name,通过<property>和</property>标签直接进行赋值。
UserService实体类的声明代码如下:
//声明UserService类
public class UserService {
private Integer id;
//用户ID
private String name;
//用户名称
//getter和setter方法
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//打印属性值
public void getUser() {
System.out.println("id:"+this.id);
System.out.println("name:"+this.name);
}
}
以上代码声明了一个UserService类,并实现了属性id和属性name的setter和getter方法,通过getUser()方法打印属性值。编写测试代码,展示通过Spring上下文获取UserService对象,具体代码如下:
//测试类
public class SpringXmlTest {
public static void main(String[] args) {
//通过spring.xml获取Spring应用上下文
ApplicationContext context = new
ClassPathXmlApplication
Context("spring.xml");
UserService userService =
context.getBean("userService",
UserService.class);
userService.getUser();
//打印结果
}
}
打印结果:
id:1
name:zhangsan
在上面的示例代码中,
ClassPathXmlApplicationContext可以通过spring.xml文件获取UserService类的配置元数据,通过Spring容器的组装和实例化UserService类,最终正确调用getUser()方法打印出定义的属性值。
2. 基于Java注解的配置
从Spring 2.5开始,支持以Java注解的方式来配置Bean,如@Scope、@Service、@Component、@Controller、@Repository、@Autowired和@Resource等注解。
@Scope注解可以设置Bean的作用域。Spring容器实例化的对象默认是单例的,如果想要修改作用域,可以通过@Scope注解进行修改。表1.1中列出了@Scope注解使用的一些作用域。
request、session、application和websocket作用域只在Web应用环境中使用。在普通的Spring IoC容器里只有singleton和prototype两种作用域,其他的设置会抛出异常。
下面改造基于XML配置元数据的例子,将其改成基于Java注解的方式来注入Bean,具体代码如下:
//注解的方式声明UserService
@Service
public class UserService {
private Integer id;
//用户ID
private String name;
//用户名称
//getter和setter方法
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//属性值打印
public void getUser() {
System.out.println("id:"+this.id);
System.out.println("name:"+this.name);
}
}
上面的代码在UserService类中加了一个@Service注解,spring.xml配置文件不再使用。下面增加一个注解类,添加@ComponentScan注解,代码如下:
//@ComponentScan注解用来扫描UserService类
@ComponentScan("com.spring.boot")
public class SpringAnnotationTest {
}
@ComponentScan注解的值是com.spring.boot,说明Spring容器可以自动扫描这个包路径下可管理的类,并对该类进行实例化。添加测试类代码如下:
@ComponentScan("com.spring.boot")
public class SpringAnnotationTest {
public static void main(String[] args) {
//通过注解类获取应用上下文
ApplicationContext context = new
AnnotationConfigApplication
Context(SpringAnnotationTest.class);
//获取UserService对象
UserService userService =
context.getBean(UserService.class);
userService.setId(1);
userService.setName("zhangsan");
userService.getUser();
//调用方法,打印属性值
}
}
打印结果:
id:1
name:zhangsan
通过
AnnotationConfigApplicationContext类可以获取被@Service注解的User-Service实例化对象,并正确打印属性值。通过Java注解的方式同样完成了实例的初始化,说明XML配置方式可以完全被替换。
3. 基于Java配置的示例
从Spring 3.0开始,Spring框架开始支持基于Java的方式来配置元数据,如@Configuration、@Bean、@Import和@Profile等注解。
@Configuration注解一般用来配置类,配置类中可以使用@Bean注解来声明某个类的初始化操作;@Import注解可以导入由@Configuration注解的配置类;@Profile注解可以根据不同环境生成不同的实例。
下面改造基于Java注解的案例,给出一个基于Java配置的示例。UserService类去掉@Service注解后,将变成普通的Bean。
UserService类的声明代码如下:
//声明UserService类
public class UserService {
private Integer id;
//用户ID
private String name;
//用户名称
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//属性值打印
public void getUser() {
System.out.println("id:"+this.id);
System.out.println("name:"+this.name);
}
}
新增配置类,代码如下:
//基于@Configuration注解生成UserService对象
@Configuration
public class SpringConfigTest {
@Bean
public UserService userService() {
return new UserService();
}
}
SpringConfigTest类由@Configuration注解,表明这个类是个配置类。由@Bean注解的userService()方法返回了UserService类的实例。添加测试类代码如下:
@Configuration
public class SpringConfigTest {
@Bean
public UserService userService() {
return new UserService();
}
public static void main(String[] args) {
//通过配置类获取Spring应用上下文
ApplicationContext context = new
AnnotationConfigApplication
Context(SpringConfigTest.class);
UserService userService =
context.getBean(UserService.class);
userService.setId(1);
userService.setName("zhangsan");
userService.getUser();
//打印属性值
}
}
打印结果:
id:1
name:zhangsan
从上面的例子看,基于Java配置实例化对象的方式不再需要对spring.xml的依赖。基于Java注解或Java配置来管理Bean的方式已经是当今编程的流行方式。后文介绍Spring Boot时,还会介绍一些新的注解或配置方式。
本文给大家讲解的内容是控制反转——Spring IoC容器的理念;
- 下篇文章给大家讲解的是Bean管理;
- 觉得文章不错的朋友可以转发此文关注小编;
- 感谢大家的支持!
- 上一篇: Java中如何将文件内容读取为字符串
- 下一篇: 解决idea配置自定义的maven失败的问题
猜你喜欢
- 2025-05-08 idea最新激活jetbrains-agent.jar包,亲测有效
- 2025-05-08 java高手排查问题精辟解说(java检查异常有哪些)
- 2025-05-08 Java开发者手把手教你配置数据库连接池
- 2025-05-08 解决idea配置自定义的maven失败的问题
- 2025-05-08 Java中如何将文件内容读取为字符串
- 2025-05-08 springboot的jar如何读取外部的yml配置文件
- 2025-05-08 Spring Boot中通过@PropertySource注解读取yaml或yml配置文件
- 2025-05-08 详细介绍一下使用@ConfigurationProperties读取复杂配置
- 2025-05-08 SpringBoot多模块配置文件读取(springboot多模块配置文件加载)
你 发表评论:
欢迎- 最近发表
-
- Java内存溢出紧急处理:10个必知的Linux命令快速定位OOM
- 面试常问的 25+ 个 Linux 命令(linux面试命令大全)
- Java堆外内存溢出紧急处理实战:Linux命令定位与Spring Boot解决
- java开发常用的Linux命令,高频的没你想象的多
- Java 应用 CPU 飙升?8 个 Linux 命令组合拳快速锁定异常线程
- Java 开发者线上问题排查常用的 15 个 Linux 命令
- Java程序员必备的Linux命令:让你的工作效率翻倍
- Java程序员必备的Linux命令全解析
- [超全整理] Java 程序员必备的 100 条 Linux 命令大全
- SAP ABAP资源导航(sap aatp)
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)