IoC与AOP的那点事儿
作者:SylvanasSun 原文:https://sylvanassun.github.io/2017/06/07/2017-06-07-IoC&AOP/
IoC
控制反转(Inversion of Control)是 OOP
中的一种设计原则,也是 Spring
框架的核心.大多数应用程序的业务逻辑代码都需要两个或多个类进行合作完成的,通过IoC则可以减少它们之间的耦合度.
实现方法
IoC
的主要实现方法有两种, 依赖注入
与 依赖查找
.
依赖注入 : 应用程序被动的接收对象, IoC
容器通过类型或名称等信息来判断将不同的对象注入到不同的属性中.
依赖注入主要有以下的方式:
- 基于
set
方法 : 实现特定属性的public set()方法,来让IoC
容器调用注入所依赖类型的对象. - 基于接口 : 实现特定接口以供
IoC
容器注入所依赖类型的对象. - 基于构造函数 : 实现特定参数的构造函数,在创建对象时来让
IoC
容器注入所依赖类型的对象. - 基于注解 : 通过
Java
的注解机制来让IoC
容器注入所依赖类型的对象,例如Spring
框架中的@Autowired
.
依赖查找 : 它相对于 依赖注入
而言是一种更为主动的方法,它会在需要的时候通过调用框架提供的方法来获取对象,获取时需要提供相关的配置文件路径、key等信息来确定获取对象的状态.
IoC的思想
在传统实现中,我们都是通过应用程序自己来管理依赖的创建,例如下代码.
public class Person {
// 由Person自己管理Food类的创建
public void eat() {
Food food = new Chicken();
System.out.println("I am eating " + food.getName() + "...");
}
}
而 IoC
则是通过一个第三方容器来管理并维护这些被依赖对象,应用程序只需要接收并使用IoC容器注入的对象而不需要关注其他事情.
public class Person {
private Food food;
// 通过set注入
public void setFood(Food food) {
this.food = food;
}
// Person不需要关注Food,只管使用即可
public void eat() {
System.out.println("I am eating " + this.food.getName() + "...");
}
}
通过以上的例子我们能够发现,控制反转其实就是对象控制权的转移,应用程序将对象的控制权转移给了第三方容器并通过它来管理这些被依赖对象,完成了应用程序与被依赖对象的解耦.
AOP
AOP(Aspect-OrientedProgramming)
即面向方面编程.它是一种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想.用于切入到指定类指定方法的代码片段叫做切面,而切入到哪些类中的哪些方法叫做切入点.
AOP
是 OOP
的有益补充, OOP
从横向上区分出了一个个类, AOP
则从纵向上向指定类的指定方法中动态地切入代码.它使 OOP
变得更加立体.
Java
中的动态代理或 CGLib
就是 AOP
的体现.
案例分析
在 OOP
中,我们使用封装的特性来将不同职责的代码抽象到不同的类中.但是在分散代码的同时,也增加了代码的重复性.
例如,我们需要在两个或多个类中的方法都记录日志或执行时间,可能这些代码是完全一致的,但因为类与类无法联系造成代码重复.
public class A {
public void something () {
// 业务逻辑...
recordLog();
}
private void recordLog() {
// 记录日志...
}
}
public class B {
public void something () {
// 业务逻辑...
recordLog();
}
private void recordLog() {
// 记录日志...
}
}
接下来,我们采取两种不同方案来改进这段代码.
将重复代码抽离到一个类中
public class A {
public void something () {
// 业务逻辑...
Report.recordLog();
}
}
public class B {
public void something () {
// 业务逻辑...
Report.recordLog();
}
}
public class Report {
public static void recordLog (String ...messages) {
// 记录日志...
}
}
这样看似解决了问题,但类之间已经耦合了.并且当这些外围业务代码(日志,权限校验等)越来越多时,它们的侵入(与核心业务代码混在一起)会使代码的整洁度变得混乱不堪.
使用AOP分离外围业务代码
我们使用 AspectJ
,它是一个 AOP
框架,扩展了Java语言,并定义了 AOP
语法(通过它实现的编译器).
使用 AspectJ
需要先安装并将lib中aspectjrt.jar添加进入classpath,下载地址.
public class Something {
public void say() {
System.out.println("Say something...");
}
public static void main(String[] args) {
Something something = new Something();
something.say();
}
}
public aspect SomethingAspect {
/**
* 切入点,切入到Something.say()
*/
pointcut recordLog():call(* com.sun.sylvanas.application.hello_aop.Something.say(..));
/**
* 在方法执行后执行
*/
after():recordLog() {
System.out.println("[AFTER] Record log...");
}
}
AOP
解决了代码的重复并将这些外围业务代码抽离到一个切面中,我们可以动态地将切面切入到切入点.
- Java 集合系列02之 Collection架构
- 开发者需要掌握的JS事件
- Java 集合系列03之 ArrayList详细介绍(源码解析)和使用示例
- Kosaraju算法、Tarjan算法分析及证明--强连通分量的线性算法
- 关于curl网站运维与开发的那些事
- 并查集Union-find及其在最小生成树中的应用
- go 语言的库文件放在哪里?如何通过nginx代理后还能正确获取远程地址
- 离线Tarjan算法-最近公共祖先问题
- Java文件上传下载实训
- 【网络编程系列】二:socket通信原理及实践
- textrank算法原理与提取关键词、自动提取摘要PYTHON
- 【网络编程系列】一:字节顺序的大端与小端表示法
- Linux下的make命令用法
- 增量数据丢失的原因分析(三)(r8笔记第91天)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Python爬虫之scrapy的入门使用
- 告别传统工业互联网,提高数字管控思维:三维组态分布式能源站
- 爱奇艺iOS移动端网络优化实践:请求成功率优化
- Java数据类型
- Python爬虫之scrapy构造并发送请求
- Python爬虫之scrapy模拟登陆
- Python爬虫之scrapy中间件的使用
- Python爬虫之scrapy_redis原理分析并实现断点续爬以及分布式爬虫
- Python爬虫之scrapy_splash组件的使用
- Python爬虫之scrapy的日志信息与配置
- Python爬虫之scrapyd部署scrapy项目
- 最近发现一个很有趣的随机小姐姐视频源码 分享给大家
- Codeforces Round #633 (Div. 2)C Powered Addition (贪心,二进制)
- Spring 整合 JUnit
- Java Stax解析XML示例