您的位置:首页 > 编程语言

我的控制反转,依赖注入和面向切面编程的理解

2016-10-11 11:04 246 查看
感谢http://blog.xiaohansong.com/2015/10/21/IoC-and-DI/
的供图

1.什么是控制? 如下图所示,我们看到了 软件系统中 对象的
高耦合现象。全体齿轮的转动由一个对象来控制,如类B。



2.什么是 控制反转? 是用来对对象进行解耦借助第三方实现具有依赖关系的的对象之间的解耦。这个第三方就是 ioc 容器。引入了 ioc
容器后,对象 A、B、C、D 之间没有了依赖关系全体齿轮转动的控制权交给 容器。这时候齿轮转动控制权不属于任何对象,而属于ioc 容器,所以控制权反转了,从 某个对象 转到了 ioc 容器。



3. 什么是依赖注入?
3.1 什么是依赖?依赖就是指一种关系,如果 在类A中 创建了 类B的实例,我们说 类A 依赖 类B。
3.2 看个荔枝:
public class class A{
B b;
public A(){
b = new B();
}
void func(){
b.func();
}
}

出现的问题(problems):

问题1:如果现在要改变 类 B 生成方式,如需要用new B(String name)初始化 B,需要修改 类A中的源代码;
问题2:如果想测试不同 B 对象对 A 的影响很困难,因为 B 的初始化被写死在了 A 的构造函数中;
问题3:如果要对类B的实例进行调试时,就必须在类A中对类B的实例进行测试,增加了测试难度和复杂度;因为当出现问题时,不知道 是 类A的问题 还是 类B的问题;

解决方法:
public class class A{
B b;
public A(B b){
this.b = b;
}
void func(){
b.func();
}
}

3.3)依赖注入定义: 将B对象实例 作为类A的构造器参数进行传入,在调用类A 构造器之前,类B实例已经被初始化好了。像这种非自己主动初始化依赖,而通过外部传入依赖对象的方式,我们就称为依赖注入

4.依赖反转
4.1 根据依赖注入的定义: 被依赖者对象并不是依赖者自己主动初始化,而是通过外部传入被依赖者的方式,那么被依赖者对象类型 可以是 其 本身,也可以使其实现类或继承子类;
4.2 所以,经过分析,被依赖者的对象类型 并不是 依赖者自身可以决定的,(当然传统的程序设计方式是依赖者 决定的),而是由外部创建者决定的,所以 被依赖者类型的决定权反转了。对于spirng来说 ,就是由 spring容器决定的;

4.3 依赖反转定义:被依赖者的 对象类型 并不是由依赖者自身可以决定的,而是由 外部创建者决定的,外部传入什么类型的对象 就是 什么类型的对象 , 依赖者对其一无所知;

=======================================================================================
【AOP】

转自:http://docs.jboss.org/aop/1.0/aspect-framework/userguide/en/html/what.html
【1】What is it? 面向切面编程是什么?
1)切面定义:一个切面是通常指散布在方法,类,对象层次结构或甚至整个对象模型中的共同特征。 它是看起来和气味的行为差不多,它应该有结构,但你不能用代码在传统的面向对象技术中表示这种结构。
2)切面荔枝:例如,度量(时间,用于度量运行某个代码片需要花费多长时间)是一个常见切面。 要从应用程序生成有用的日志,您必须(通常自由地)在代码中散布信息性消息。 然而,度量是你的类或对象模型真正不应该关注的东西。 毕竟,度量与您的实际应用无关:它不代表客户或帐户,并且不实现业务规则。
它只是正交。
3)横切关注点定义:在AOP中,像度量这样的特征称为横切关注点,因为它是一种“截断”对象模型中多个点但仍然截然不同的行为。作为一种开发方法,AOP建议您抽象和封装横切关注点。
4)横切关注点荔枝:例如,假设您想要向应用程序添加代码以测量调用特定方法所需的时间。 在纯Java中,代码看起来像下面这样。
public class BankAccountDAO {
public void withdraw(double amount)  {
long startTime = System.currentTimeMillis();
try {
// Actual method body...
}
finally {
long endTime = System.currentTimeMillis() - startTime;
System.out.println("withdraw took: " + endTime);
}
}
}

代码分析)虽然这段代码工作,这个方法有一些问题:

打开和关闭指标是非常困难的,因为您必须手动将try> / finally块中的代码添加到要基准的每个方法或构造函数。
分析代码真的不属于你的应用程序代码。 它使你的代码膨胀和更难读,因为你必须在一个try / finally块中包含时间。
如果要扩展此功能以包括方法或失败计数,或者甚至将这些统计信息注册到更复杂的报告机制,则必须再次修改许多不同的文件。
这种度量方法很难维护,扩展和扩展,因为它分散在整个代码库中。 这只是一个很小的例子! 在许多情况下,OOP可能不总是向类添加指标的最佳方法。
面向方面的编程提供了一种封装这种类型的行为功能的方法。 它允许您添加行为,如度量“围绕”您的代码。 例如,AOP为您提供了程序控制,以指定您希望在执行代码的实际主体之前调用BankAccountDAO来执行度量方面。

【2】在JBoss 切面编程中创建切面
1)简而言之,所有AOP框架定义了两个东西:一种实现横切关注点的方法,以及一个编程语言或一组标签 -以指定如何应用这些代码片段。(一种是 定义横切关注点的方法,二是指定该横切关注点在何处使用)
2)让我们来看看JBoss AOP,它的横切关注点,以及如何在JBoss中实现一个度量方面。
在JBoss AOP中创建度量方面的第一步是将度量特性封装在自己的Java类中。 清单二将清单One的BankAccountDAO.withdraw()方法中的try / finally块提取为Metrics,这是一个JBoss AOP拦截器类的实现。
清单二:在JBoss AOP拦截器中实现度量
public class Metrics implements org.jboss.aop.Interceptor
03.   public Object invoke(Invocation invocation) throws Throwable {
05.     long startTime = System.currentTimeMillis();
06.     try {
08.       return invocation.invokeNext();
09.     }
10.     finally {
12.       long endTime = System.currentTimeMillis() - startTime;
13.       java.lang.reflect.Method m = ((MethodInvocation)invocation).method;
14.       System.out.println("method " + m.toString() + " time: " + endTime + "ms");
15.     }
16.   }
17. }

对以上代码的分析:

在JBoss AOP下,Metrics类包装withdraw():当调用代码调用withdraw()时,AOP框架将方法调用分解为其部分,并将这些部分封装到一个调用对象中。 然后框架调用位于调用代码和实际方法体之间的任何方面。
当AOP框架解析方法调用时,它在第3行调用Metric的invoke方法。第8行包装并委托给实际的方法,并使用一个封闭的try / finally块来执行定时。 第13行从调用对象获取有关方法调用的上下文信息,而第14行显示方法名称和计算的度量。
将度量代码放在其自己的对象中允许我们以后轻松扩展和捕获额外的测量。现在,度量被封装到一个方面,让我们看看如何应用它。
【3】JBoss AOP中切面的应用
要应用一个方面,您定义何时执行方面代码。 这些执行点被称为切入点。 类似于切入点是一个正则表达式。 正则表达式匹配字符串时,切入点表达式匹配应用程序中的事件/点。 例如,有效的切入点定义将是“对于JDBC方法executeQuery()的所有调用,调用验证SQL语法的方面”。

我的总结(AOP)
1)切面的抽象型定义:切面是散布在 方法,类,对象层次结构或 整个对象模型中的共同特征;(是一组特征)
2)切面荔枝:如 我们要对某方法的执行时间进行统计,代码如下:
public class BankAccountDAO {
public void withdraw(double amount)  {
long startTime = System.currentTimeMillis();
try {
// Actual method body...
}
finally {
long endTime = System.currentTimeMillis() - startTime;
System.out.println("withdraw took: " + endTime);
}
}
}

其中 有关于统计时间的都是特征,它们的共性都是因为要统计时间而 添加到 方法中的代码块;那所以这些代码块就组成了 切面;
3)以上代码块出现了问题
问题1)代码重用率低:必须手动将该 切面代码添加到 要统计方法执行时间的方法中;
问题2)代码膨胀和可读性低:计时代码真的不用你去关心,这些切面代码只会让你的代码更加 膨胀和难读,因为你必须在一个try / finally块中包含时间, 但这个时间与我们 方法的执行没有任何关系;
问题3)不利于代码扩展(代码耦合性高):如果要扩展此功能以包括方法或失败计数,或者甚至将这些统计信息注册到更复杂的报告机制,则必须再次修改许多不同的文件;
最后的最后:这种时间度量方法很难维护,扩展和扩展,因为它分散在整个代码库中;
4)aop 是干什么的?
4.1)intro:面向切面编程提供了一种封装切面行为的方法。AOP提供了程序控制,以指定您希望在执行代码的实际主体之前调用 时间统计方法 来执行执行时间度量。
4.2)所有AOP框架定义了两个东西:一种实现横切关注点的方法,以及一个编程语言或一组标签 -以指定如何应用这些代码片段。(一种是 定义横切关注点的方法,二是指定该横切关注点在何时何处使用)

5)如何定义aop中横切关注点的方法 和 指定该横切关注点的应用地点
5.1)定义横切关注点:将切面代码度量特性封装在自己的Java类中
public class Metrics implements org.jboss.aop.Interceptor
public Object invoke(Invocation invocation) throws Throwable {
long startTime = System.currentTimeMillis();
try {
return invocation.invokeNext(); // 调用真正的实体方法
}
finally {
long endTime = System.currentTimeMillis() - startTime;
java.lang.reflect.Method m = ((MethodInvocation)invocation).method;
System.out.println("method " + m.toString() + " time: " + endTime + "ms");
}
}
}

5.2)横切关注点在何时何地使用?
要应用一个切面,您定义何时执行切面代码。 这些执行点被称为切入点。切入点类似于是一个正则表达式。 正则表达式匹配字符串时,切入点表达式匹配应用程序中的事件/点。
看个 切入点的定义: @Before("execution(** concert.Performance.perform(..))")
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: