2.IOC
2.1IOC理论推导
-
UseDao接口
public interface UserDao { void getUser(); }
-
UseDao接口实现
package dao; public class UserDaoImpl1 implements UserDao { public void getUser() { System.out.println("得到用户1...."); } }
-
Service接口
public interface UserService { void getUser(); }
-
Service接口实现
public class UserServiceImpl1 implements UserService { private UserDao userDao = new UserDaoImpl1(); public void getUser() { userDao.getUser(); } }
-
测试
public class IOCTest { public static void main(String[] args) { UserService userService = new UserServiceImpl1(); userService.getUser(); } }
在我们之前的业务中,用户的需求会影响我们原来的代码,我们需要根据饿需求去修改代码。如果代码量大,那么修改一次代码的代价很大。对上面而言,在每次创建一个UserDao接口实现后,如果用户需要的是其中的某个UserDao接口实现类,我们都在UserServiceImpl1这个类中的给userDao new一个不同的UserDao接口实现,这样如果很多这种的类的话,那么我们修改一次代码的代价就很大。
上面这种方式:使类与类之间有很大的耦合性。
那么我们可以通过以下方式降低耦合性
使用Set实现接口,构造器实现
public class UserServiceImpl1 implements UserService {
private UserDao userDao;
public UserServiceImpl1() {
}
public UserServiceImpl1(UserDao userDao) {
this.userDao = userDao;
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void getUser() {
userDao.getUser();
}
}
public class IOCTest {
public static void main(String[] args) {
//set方式解决耦合,依赖
UserServiceImpl1 serviceImpl1 = new UserServiceImpl1();
serviceImpl1.setUserDao(new UserDaoImpl1());
UserService userService = serviceImpl1;
userService.getUser();
//构造器方式解决耦合,依赖
UserService userService1 = new UserServiceImpl1(new UserDaoImpl1());
userService1.getUser();
}
}
- 类主动new一个对象
- 使用set注入后,该类的被动获得了一个对象
- 使用构造器注入后,该类的被动获得了一个对象
这个思想解决了这个问题,不用管对象的创建。系统耦合性大大降低了。只专注于业务的实现。这是IoC的原型
2.2IOC本质
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
Spring是如何实现IOC的呢?
官方:
理解:
每个bean中的依赖都由容器帮我们注入。但是该bean对应的类必须要有get&set方法,否则无法注入依赖。
2.3我的第一个Spring程序
- 创建Pojo
public class Hello {
private String str;
public Hello() {
System.out.println("构造器创建hello");
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
}
- 配置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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="hello" class="pojo.Hello">
<property name="str" value="hello"/>
</bean>
</beans>
- 创建Spring容器,获得bean
public class SpringTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("============");
Hello hello = (Hello) applicationContext.getBean("hello");
System.out.println(hello.getStr());
}
}
- 执行结果:
从结果分析,在创建Spring容器时,就已经把对应的Hello对象通过构造器创建了,并且放入容器中。
当我们去取的时候,就是把容器中已经创建好的Hello对象给获取出来而已。
在这个过程中Hello对象中有个str属性,是由Spring容器帮我们注入的。
我们在这整个过程中都没有new过任何一对象,都是Spring棒我们创建的。Spring帮我们控制bean的创建和bean中属性的注入(实现控制反转IOC)
Spring创建Bean的方式
Spring在创建bean的时候默认时使用无参构造的。
如果要用有参构造创建,这需要在xml中配置
<bean id="hello" class="pojo.Hello">
<constructor-arg value="hello" name="str"/>
</bean>
此时已给该对象中的属性注入值。
如果我们需要对该值进行修改,通过配置xml:
<bean id="hello" class="pojo.Hello">
<constructor-arg value="hello" name="str"/>
<property name="str" value="hello2"/>
</bean>
上述的方式会覆盖有参构造器初始的值。
思考问题?
-
Hello 对象是谁创建的 ?
hello 对象是由Spring创建的
-
Hello 对象的属性是怎么设置的 ?
hello 对象的属性是由Spring容器设置的
这个过程就叫控制反转 :
- 控制 : 谁来控制对象的创建 , 传统应用程序的对象是由程序本身控制创建的 , 使用Spring后 , 对象是由Spring来创建的
- 反转 : 程序本身不创建对象 , 而变成被动的接收对象 .
依赖注入 : 就是利用set方法来进行注入的.
IOC是一种编程思想,由主动的编程变成被动的接收
可以通过newClassPathXmlApplicationContext去浏览一下底层源码 .