什么是IoC?
Ioc全称Inversion of Control,把创建对象的权利交给容器,对象的实例不再由调用者来创建,而是由容器来创建,容器会负责控制程序之间的关系,而不是由调用者的程序代码直接控制。这样,控制权由应用代码转移带了容器,控制权发生了反转,这就是控制反转。它是spring框架的核心思想之一。
控制反转的作用
削减计算机程序的耦合(接触我们代码中的依赖关系)。
举例说明
需求描述: 每个用户有自己的一辆车。用户(User)类中有姓名、车属性;车(Car)类中有品牌、车主属性。
用户类
package com.test.pojo;
public class User {
private String name;
private Car car;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
}
车类
package com.test.pojo;
public class Car {
private String brand;
private User user;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
(1)没有用ioc时
// 不使用ioc的方式
@Test
public void test1(){
User user = new User();
Car car = new Car();
user.setName("张三");
user.setCar(car);
car.setBrand("兰博基尼");
car.setUser(user);
System.out.println("用户 "+user.getName()+" 的车是:"+user.getCar().getBrand());
}
- 程序中我们是用new关键字来创建对象的,它是在编译的时候把一切都写定,这是所谓的硬编码,是一种应该减少和避免的方式。
(2)用ioc时
导入maven依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
创建spring配置文件applicationContext.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="user" class="com.test.pojo.User">
<property name="name" value="张三"/>
<property name="car" ref="car"/>
</bean>
<bean id="car" class="com.test.pojo.Car">
<property name="brand" value="兰博基尼"/>
<property name="user" ref="user"/>
</bean>
</beans>
开始测试
// 使用ioc的方式
@Test
public void test2(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) context.getBean("user");
Car car = context.getBean(Car.class);
System.out.println("用户 "+user.getName()+" 的车是:"+user.getCar().getBrand());
}
测试结果
可以看到结果是一样的,User和Car类需要用到对象是,不是直接通过new来创建,而是在spring容器中取得的,这种方式大大削弱了代码中的依赖性,减少硬代码,需要修改时直接修改配置文件即可,大大提高代码的可维护性。
而spring底层帮我们创建对象主要是通过反射机制来创建的,只要给出需要生成的Bean对象的路径、需要注入的属性名、方法名就可以返回一个对象,类似于下面代码。而"com.test.pojo.User" 、属性名、方法名这部分可以抽出来独立一个properties文件,无需写死在代码中,User user也可改为Object obj,需要的时候再转换类型即可。
// 反射创建对象
@Test
public void test3() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
User user = (User) Class.forName("com.test.pojo.User").newInstance();
Car car = (Car) Class.forName("com.test.pojo.Car").newInstance();
Field field1 = Class.forName("com.test.pojo.User").getDeclaredField("name");
field1.setAccessible(true);
field1.set(user,"张三");
Field field2 = Class.forName("com.test.pojo.User").getDeclaredField("car");
field2.setAccessible(true);
field2.set(user,car);
Field field3 = Class.forName("com.test.pojo.Car").getDeclaredField("brand");
field3.setAccessible(true);
field3.set(car,"兰博基尼");
Field field4 = Class.forName("com.test.pojo.Car").getDeclaredField("user");
field4.setAccessible(true);
field4.set(car,user);
System.out.println("用户 "+user.getName()+" 的车是:"+user.getCar().getBrand());
}
同样得出结果