IOC是与AOP齐名,作为spring的重要特性之一,必知必会,如果你以前和我一样只是胡乱用过,现在,是时候展现真正的技术了,一起学习下:
一、如何理解
我们要来简要的看下spring官网对IOC的一些描述:
IoC is also known as dependency injection (DI). It is a process whereby objects define their dependencies (that is, the other objects they work with) only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then injects those dependencies when it creates the bean. This process is fundamentally the inverse (hence the name, Inversion of Control) of the bean itself controlling the instantiation or location of its dependencies by using direct construction of classes or a mechanism such as the Service Locator pattern.
IoC也称为依赖注入(DI)。在此过程中,对象仅通过构造函数参数,工厂方法的参数或在构造或从工厂方法返回后在对象实例上设置的属性来定义其依赖项(即,与它们一起使用的其他对象) 。然后,容器在创建bean时注入那些依赖项。此过程从根本上讲是通过使用类的直接构造或诸如服务定位器模式之类的控件来控制其依赖项的实例化或位置的bean本身的逆过程(因此称为Inversion of Control)。
The org.springframework.beans and org.springframework.context packages are the basis for Spring Framework’s IoC container. The BeanFactory interface provides an advanced configuration mechanism capable of managing any type of object. ApplicationContext is a sub-interface of BeanFactory. It adds:
- Easier integration with Spring’s AOP features
- Message resource handling (for use in internationalization)
- Event publication
- Application-layer specific contexts such as the WebApplicationContext for use in web applications.
org.springframework.beans和org.springframework.context包是Spring Framework的IoC容器的基础。 BeanFactory接口提供了一种高级配置机制,能够管理任何类型的对象。 ApplicationContext是BeanFactory的子接口。 它增加了:
- 与Spring的AOP功能轻松集成
- 消息资源处理(用于国际化)
- 活动发布
- 应用层特定的上下文,例如Web应用程序中使用的WebApplicationContext。
In short, the BeanFactory provides the configuration framework and basic functionality, and the ApplicationContext adds more enterprise-specific functionality. The ApplicationContext is a complete superset of the BeanFactory and is used exclusively in this chapter in descriptions of Spring’s IoC container. For more information on using the BeanFactory instead of the ApplicationContext, see The BeanFactory.
简而言之,BeanFactory提供了配置框架和基本功能,而ApplicationContext添加了更多企业特定的功能。 ApplicationContext是BeanFactory的完整超集,在本章中仅在Spring的IoC容器描述中使用。有关使用BeanFactory而不是ApplicationContext的更多信息,请参见BeanFactory。
In Spring, the objects that form the backbone of your application and that are managed by the Spring IoC container are called beans. A bean is an object that is instantiated, assembled, and otherwise managed by a Spring IoC container. Otherwise, a bean is simply one of many objects in your application. Beans, and the dependencies among them, are reflected in the configuration metadata used by a container.
在Spring中,构成应用程序主干并由Spring IoC容器管理的对象称为bean。 Bean是由Spring IoC容器实例化,组装和以其他方式管理的对象。否则,bean仅仅是应用程序中许多对象之一。 Bean及其之间的依赖关系反映在容器使用的配置元数据中。
是不是有点一脸懵。你可以把spring容器理解为你租房子的中介,或者…找对象的婚介所,核心就是:你把你需要的类型告诉spring容器,它给你提供你想要的对象。
二、一个栗子,理解spring ioc
首先,一个用来获取用户信息的dao接口:
package com.aran.parts.ioc.L1.dao;
/**
* @Author Aran
* @Date 2020/9/4 8:46 下午
*/
public interface UserDao {
void getUser();
}
实现这个接口,默认假设通过mysql数据库获取用户信息:
package com.aran.parts.ioc.L1.dao;
/**
* @Author Aran
* @Date 2020/9/4 8:47 下午
*/
public class UserDaoImpl implements UserDao {
@Override
public void getUser() {
System.out.println("默认获取用户的数据");
}
}
再来一个实现类,从oracle中获取用户数据:
package com.aran.parts.ioc.L1.dao;
/**
* @Author Aran
* @Date 2020/9/4 9:16 下午
*/
public class UserDaoOracleImpl implements UserDao {
@Override
public void getUser() {
System.out.println("获取Oracle中的数据");
}
}
service层,定义一个UserService接口:
package com.aran.parts.ioc.L1.service;
/**
* @Author Aran
* @Date 2020/9/4 8:49 下午
*/
public interface UserService {
void getUser();
}
service的实现类:
package com.aran.parts.ioc.L1.service;
import com.aran.parts.ioc.L1.dao.UserDao;
import com.aran.parts.ioc.L1.dao.UserDaoImpl;
import com.aran.parts.ioc.L1.dao.UserDaoOracleImpl;
/**
* @Author Aran
* @Date 2020/9/4 8:50 下午
*/
public class UserServiceImpl implements UserService {
/**
* 通过new的方式,每次改变都要修改
*/
private UserDao userDao = new UserDaoOracleImpl();
@Override
public void getUser() {
userDao.getUser();
}
}
测试类:
package com.aran.myTest;
import com.aran.parts.ioc.L1.dao.UserDaoOracleImpl;
import com.aran.parts.ioc.L1.service.UserService;
import com.aran.parts.ioc.L1.service.UserServiceImpl;
/**
* @Author Aran
* @Date 2020/9/4 8:53 下午
*/
public class UserTest {
public static void main(String[] args) {
//用户实际直接调用的是业务层,而不是dao层
UserService userService = new UserServiceImpl();
userService.getUser();
}
}
运行,得到结果:
获取Oracle中的数据
而如果我们此时,希望通过默认数据库获取用户数据,我们需要修改service实现类中的:
private UserDao userDao = new UserDaoOracleImpl();
为:
private UserDao userDao = new UserDaoImpl();
再次运行测试类,得到结果:
默认获取用户的数据
也就是说,每个业务层实现对应的Dao必须通过硬编码的方式写死在程序中,每次用户需求的变更都需要对代码进行修改,如果代码量较大的话,修改的成本便会十分昂贵。
于是,我们修改一下业务层的实现类:
package com.aran.parts.ioc.L1.service;
import com.aran.parts.ioc.L1.dao.UserDao;
import com.aran.parts.ioc.L1.dao.UserDaoImpl;
import com.aran.parts.ioc.L1.dao.UserDaoOracleImpl;
/**
* @Author Aran
* @Date 2020/9/4 8:50 下午
*/
public class UserServiceImpl implements UserService {
/**
* 通过new的方式,每次改变都要修改
*/
// private UserDao userDao = new UserDaoOracleImpl();
private UserDao userDao;
//通过set方法实现注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public UserDao getUserDao() {
return userDao;
}
@Override
public void getUser() {
userDao.getUser();
}
}
代码的变化主要在于,将原有的new方式引用Dao,改为set注入的方式,此时,我们的业务层由原有的主动新建对象,变为被动接收对象,灵活性更高。
测试类中作如下改动:
package com.aran.myTest;
import com.aran.parts.ioc.L1.dao.UserDaoImpl;
import com.aran.parts.ioc.L1.dao.UserDaoOracleImpl;
import com.aran.parts.ioc.L1.service.UserService;
import com.aran.parts.ioc.L1.service.UserServiceImpl;
/**
* @Author Aran
* @Date 2020/9/4 8:53 下午
*/
public class UserTest {
public static void main(String[] args) {
//用户实际直接调用的是业务层,而不是dao层
UserService userService = new UserServiceImpl();
((UserServiceImpl) userService).setUserDao(new UserDaoImpl());
userService.getUser();
}
}
注意这一行代码:
((UserServiceImpl) userService).setUserDao(new UserDaoImpl());
即,我们只需要将需要的对象传给setUserDao 即可。
运行程序,得到结果:
默认获取用户的数据
修改代码为:
((UserServiceImpl) userService).setUserDao(new UserDaoOracleImpl());
运行结果:
获取Oracle中的数据
上述示例只是为了理解spring ioc的思想,还并非真正意义上的ioc,以后的文章,我们会进一步学习ioc的配置方式,使用方式等内容。
代码地址:点我理解Spring IoC ^_^
刚刚好,看见你幸福的样子,于是幸福着你的幸福
——《国境以南,太阳以西》
本文深入解析Spring框架的IoC(Inversion of Control)容器概念,通过示例展示依赖注入的原理,以及BeanFactory和ApplicationContext的作用。

9528

被折叠的 条评论
为什么被折叠?



