1 动态代理
1.1 目的
增强原有方法
代理对象,一个假的对象(实现原有对象的方法并加强)
1.2 问题
需求1-日志:在程序执行期间追踪正在发生的活动
需求2-验证:希望计算器只能处理正数的运算
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
@Override
public int add(int i, int j) {
System.out.println("这个方法 add 开始于 ["+ i+ ","+j+"]");
int result = i + j;
System.out.println("这个方法 add 结束于 "+ result);
return result;
}
@Override
public int sub(int i, int j) {
System.out.println("这个方法 sub 开始于 ["+ i+ ","+j+"]");
int result = i - j;
System.out.println("这个方法 sub 结束于 "+ result);
return result;
}
@Override
public int mul(int i, int j) {
System.out.println("这个方法 mul 开始于 ["+ i+ ","+j+"]");
int result = i * j;
System.out.println("这个方法 sub 结束于 "+ result);
return result;
}
@Override
public int div(int i, int j) {
System.out.println("这个方法 div 开始于 ["+ i+ ","+j+"]");
int result = i / j;
System.out.println("这个方法 div 结束于 "+ result);
return result;
}
}
代码混乱:越来越多的非业务需求(日志和验证等)加入后, 原有的业务方法急剧膨胀. 每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点.
代码分散: 以日志需求为例, 只是为了满足这个单一需求, 就不得不在多个模块(方法)里多次重复相同的日志代码. 如果日志需求发生变化, 必须修改所有模块.
1.3 使用动态代理解决上述问题
代理设计模式的原理: 使用一个代理将对象包装起来, 然后用该代理对象取代原始对象. 任何对原始对象的调用都要通过代理. 代理对象决定是否以及何时将方法调用转到原始对象上.
ArithmeticCalculatorImpl
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
@Override
public int add(int i, int j) {
int result = i + j;
return result;
}
@Override
public int sub(int i, int j) {
int result = i - j;
return result;
}
@Override
public int mul(int i, int j) {
int result = i * j;
return result;
}
@Override
public int div(int i, int j) {
int result = i / j;
return result;
}
}
LoggingProxy:
public class LoggingProxy {
//要代理的对象
private ArithmeticCalculator target;
public LoggingProxy(ArithmeticCalculator target) {
super();
this.target = target;
}
public ArithmeticCalculator getLoggingProxy(){
ArithmeticCalculator proxy = null;
//代理对象由哪个类加载器负责加载
ClassLoader loader = target.getClass().getClassLoader();
//代理对象的类型,即其中有哪些方法
Class [] interfaces = newClass[]{ArithmeticCalculator.class};
//当调用代理对象其中方法时,执行该代码
InvocationHandler h = newInvocationHandler() {
/**
* proxy:正在返回的那个代理对象,一般情况下,在 invoke 方法都不使用该对象
* method:正在被调用的方法
* args:调用方法时,传入的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
String methodName = method.getName();
//日志
System.out.println("此方法" + methodName + "开始于" + Arrays.asList(args));
//执行方法
Object result = method.invoke(target, args);
//日志
System.out.println("此方法" + methodName + "结束于" + result);
return result;
}
};
proxy =(ArithmeticCalculator) Proxy.newProxyInstance(loader, interfaces, h);
return proxy;
}
}
2 AOP
2.1 概念
是一种新的方法论, 是对传统 OOP(面向对象编程) 的补充.
Aop(AspectOriented Programing):面向切面(方面)编程,用来封装横切关注点,扩展功能不修改源代码实现
2.2 原理
AOP是面向切面编程,是通过动态代理的方式为程序添加统一功能,集中解决一些公共问题。
2.3 主要编程对象
AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码
AOP的主要编程对象是切面(aspect), 而切面模块化横切关注点.
在应用 AOP 编程时, 仍然需要定义公共功能, 但可以明确的定义这个功能在哪里, 以什么方式应用, 并且不必修改受影响的类. 这样一来横切关注点就被模块化到特殊的对象(切面)里.
2.4 好处:
1.各个步骤之间的良好隔离性耦合性大大降低
2.源代码无关性,再扩展功能的同时不对源码进行修改操作。
3 AOP原理—解决动态代理
画图分析原理
aop底层使用动态代理实现
(1)第一种情况,有接口情况,使用动态代理创建接口实现类代理对象
(2)第二种情况,没有接口情况,使用动态代理创建类的子类代理对象
4 AOP操作术语