一、耦合
1、什么是耦合?
通过代码来理解
1 package com.justnow.demo01.service; 2 3 import com.justnow.demo01.dao.UserDao; 4 5 public class UserService { 6 private UserDao userDao = new UserDao(); 7 8 public void updateById(int id){ 9 userDao.updateById(id); 10 } 11 }
UserService类能够编译运行成功的前提是UserDao这个类不出问题,也就是说,UserService依赖UserDao这个类。这种依赖性的高低可以用耦合来表示。
在软件工程中, 耦合指的就是就是对象之间的依赖性。对象之间的耦合越高,维护成本越高。因此对象的设计应使类和构件之间的耦合最小。
总结:
耦合是影响软件复杂程度和设计质量的一个重要因素,在设计上我们应采用以下原则:如果模块间必须存在耦合,就尽量使用数据耦合,少用控制耦合,限制公共耦合的范围,尽量避免使用内容耦合。
2、解决程序耦合的思路
(1) 反射
如,可以使用以下方法注册jdbc驱动,
1 Class.forName("com.mysql.jdbc.Driver");
好处就是,我们的类中不再依赖具体的驱动类。
(2) 工厂模式解耦
创建一个工厂类UserDaoFactory,使用反射技术,实例化UserDao
1 package com.justnow.demo01.factory; 2 3 import static java.lang.Class.forName; 4 public class DaoFactory { 5 public static Object getUserDao(){ 6 Object obj = null; 7 try { 8 obj = Class.forName("com.justnow.demo01.dao.UserDao").newInstance(); 9 } catch (InstantiationException e) { 10 e.printStackTrace(); 11 } catch (IllegalAccessException e) { 12 e.printStackTrace(); 13 } catch (ClassNotFoundException e) { 14 e.printStackTrace(); 15 } 16 return obj; 17 } 18 }
然后修改UserService中的代码:
1 package com.justnow.demo01.service; 2 3 import com.justnow.demo01.dao.UserDao; 4 import com.justnow.demo01.factory.DaoFactory; 5 6 public class UserService { 7 private UserDao userDao = (UserDao) DaoFactory.getUserDao();// 使用反射的方法进行 8 9 10 public void updateById(int id){ 11 userDao.updateById(id); 12 } 13 }
也就是,这样便可以达到解耦的作用!
(3) 控制反转
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。——百度百科
① 传统的Java SE程序设计过程中,如果一个类依赖与另一个类的话,需要通new 进行创建对象,这个过程是程序主动去创建依赖对象;而IoC是通过一个容器创建这些对象,即有Ioc容器来控制对象的创建。即IoC容器控制了对象
② 正常的方法是主动控制获取依赖对象,这个正传;而反转是由容器来创建以及注入依赖对象,这个就是反转!
上述过程可以,用下图来表示
传统程序设计过程:
使用IoC容器后,在客户端类中不再主动去创建这些对象了。如下图所示
谈谈对Spring IOC的理解 - TD李的文章 - 知乎 https://zhuanlan.zhihu.com/p/47649591
③ 依赖注入Dependency Injection(DI)
依赖注入:组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建了一个灵活、可扩展的平台。
通过依赖注入方法,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
- 应用程序依赖于IoC容器
- 应用程序需要IoC容器来提供对象需要的外部资源
- IoC容器注入应用程序依赖的对象
- 外部资源包括:对象、资源和常用数据
二、Spring中的控制反转(IoC)
1、Spring中的容器
在基于Spring的应用中,应用对像生存于Spring容器中。Spring容器创建对象,装配它们,配置它们。管理它们的生命周期,从生存到死亡(或者创建到销毁)。Spring容器使用依赖注入管理构成应用的组件,她会创建相互协作的组件之间的关联。
也就是说,Spring容器在其框架中充当了控制反转的调控系统。
Spring中的容器可以归纳为两种不同的类型,一个是Bean工厂,另一个是引用上下文(application)。其中,应用上下文的使用更加广泛。
2、Spring中的bean
简而言之,Spring bean是Spring框架在运行时管理的对象。Spring bean是任何Spring应用程序的基本构建。Spring bean的管理包括:
(1) 创建一个对象
(2) 提供依赖项(例如其他bean,配置属性)
(3) 拦截对象的方法调用以提供额外的框架功能
(4) 销毁一个对象
Spring bean详细介绍 - Java架构的文章 - 知乎 https://zhuanlan.zhihu.com/p/60256169
三、在Spring中使用IoC初体验
第一步:在pom.xml中添加坐标
- spring-core
- spring-beans
- spring-expression
- spring-context
具体如下:
1 <properties> 2 <spring.version>5.0.2.RELEASE</spring.version> 3 </properties> 4 5 <!-- 依赖 --> 6 <dependencies> 7 <!--spring--> 8 <dependency> 9 <groupId>org.springframework</groupId> 10 <artifactId>spring-context</artifactId> 11 <version>${spring.version}</version> 12 </dependency> 13 14 <dependency> 15 <groupId>org.springframework</groupId> 16 <artifactId>spring-beans</artifactId> 17 <version>${spring.version}</version> 18 </dependency> 19 20 <dependency> 21 <groupId>org.springframework</groupId> 22 <artifactId>spring-core</artifactId> 23 <version>${spring.version}</version> 24 </dependency> 25 26 <dependency> 27 <groupId>org.springframework</groupId> 28 <artifactId>spring-expression</artifactId> 29 <version>${spring.version}</version> 30 </dependency> 31 <dependency> 32 <groupId>junit</groupId> 33 <artifactId>junit</artifactId> 34 <version>4.12</version> 35 <scope>test</scope> 36 </dependency> 37 </dependencies>
第二步:创建IUserDao接口和它的实现类
IUserDao接口
1 package com.justnow.dao; 2 3 public interface IUserDao { 4 public void updateById(int id); 5 }
UserDaoImpl 实现类
1 package com.justnow.service.impl; 2 3 import com.justnow.dao.IUserDao; 4 import com.justnow.service.IUserService; 5 6 public class UserServiceImpl implements IUserService { 7 8 private IUserDao userDao; 9 10 public IUserDao getUserDao() { 11 return userDao; 12 } 13 14 public void setUserDao(IUserDao userDao) { 15 this.userDao = userDao; 16 } 17 18 @Override 19 public void updateById(int id) { 20 userDao.updateById(10); 21 } 22 }
其中,在实现类中添加了userDao这个属性的get和set方法。
第三步:编写spring框架的配置文件,applicationContext.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans.xsd"> 6 <!--配置 service --> 7 <bean id="userService" class="com.justnow.service.impl.UserServiceImpl"> 8 <property name="userDao" ref="userDao" /> 9 </bean> 10 <!--配置 dao --> 11 <bean id="userDao" class="com.justnow.dao.impl.UserDaoImpl" /> 12 13 </beans>
<bean id="userService" class="com.justnow.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao" />
</bean>
意思是:这个bean的id为"userService",对应的类是com.justnow.service.impl.UserServiceImpl,有一个属性的名字为userDao。ref="userDao",表示这个属性引用的bean的id为userDao。
第四步:编写测试类
1 package com.justnow.test; 2 3 import com.justnow.dao.IUserDao; 4 import com.justnow.service.IUserService; 5 import org.junit.Test; 6 import org.springframework.context.support.ClassPathXmlApplicationContext; 7 8 public class TestDemo1 { 9 10 @Test 11 public void testBean(){ 12 //1. 使用ApplicationContext接口,就是在获取spring容器 13 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); 14 //2. 根据Bean的id值,从容器总获取对象 15 IUserService userService = (IUserService) context.getBean("userService"); 16 //3. 调用userService这个对像中的updateById的方法 17 userService.updateById(10); 18 } 19 20 }
最终的结果:
本章代码:https://github.com/justn0w/javawebdemo/tree/master/spring/Spring_Demo1
总结:
使用Spring的IoC容器,可以避免传统方法对象和对象之间关系复杂,达到的解耦的作用,接下来,还会介绍一些更加神奇的方法,咱们拭目以待!
参考:
Spring bean详细介绍 - Java架构的文章 - 知乎 https://zhuanlan.zhihu.com/p/60256169
谈谈对Spring IOC的理解 - TD李的文章 - 知乎 https://zhuanlan.zhihu.com/p/47649591