前端 后端 移动端AOP的实现
2021-02-02 本文已影响0人
_铁马冰河_
AOP概念
- 一种程序设计范式
- 不是OOP的替代品,只是对OOP的一种补充
- 从主业务中脱离出来横向切面关注点,降低与业务耦合
前端实现(js)
由于语言特性,JavaScript本身就具有运行时动态插入逻辑的特性。函数可以接受一切形式函数,保存函数在利用call或者apply,即操作原型就可以。利用 Function.prototype
实现,具体代码如下:
<script type="text/javascript">
var viewWillAppear = function () {
console.log("页面即将展示");
}
Function.prototype.before = function (fn) {
var self = this;
return function(){
fn.apply(self,arguments);
return self.apply(this,arguments);
}
}
Function.prototype.after = function (fn) {
var self = this;
return function(){
var result = self.apply(this, arguments);
fn.apply(this,arguments)
return result;
}
}
var viewWillAppear = viewWillAppear.before(function () {
console.log("页面展示之前")
}).after(function(){
console.log("页面展示之后")
})
</script>
//使用
<input type="button" onclick="viewWillAppear()" value="展示页面">
在不改动原有业务代码的情况下,继续调用viewWillAppear函数。但是调用前后已经插入业务之外的代码了。
后端实现(java without spring)
模拟原有业务代码
DoAction doAction = new DoActionImpl();
AOPHandler aopHandler = new AOPHandler(doAction);
doAction.viewWillAppear();
使用代理模式实现AOP,新建AOPHandler类并实现InvocationHandler接口
public class AOPHandler implements InvocationHandler {
private Object object;
public AOPHandler(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("viewWillAppear执行前");
Object ret = method.invoke(object,args);
System.out.println("viewWillAppear执行后");
return null;
}
}
实现代理类之后只需在原有调用方法加入代理类如下:
DoAction doAction = new DoActionImpl();
AOPHandler aopHandler = new AOPHandler(doAction);
doAction = (DoAction)
Proxy.newProxyInstance(DoActionImpl.class.getClassLoader(),
new Class[] { DoAction.class },
aopHandler);
doAction.viewWillAppear();
即在原有执行代码前后加入了业务代码
移动端实现 (iOS)
利用runtime 交换系统与自己定义方法的IMP,代码如下
SEL systemSel = @selector(viewWillAppear:);
SEL swizzSel = @selector(swiz_viewWillAppear:);
Method systemMethod = class_getInstanceMethod([self class], systemSel);
Method swizzMethod = class_getInstanceMethod([self class], swizzSel);
- (void)swiz_viewWillAppear:(BOOL)animated{
//IMP已经被替换了
NSLog(@"++viewwillappear之前")
[self swiz_viewWillAppear:animated];
NSLog(@"++viewwillappear之后")
}
不改变原有业务代码的情况下,系统调用viewwillappear的时候,已经加入业务之外的代码了。
总结
- 隔离业务之外的代码,降低耦合
- hook原有方法,侵入性小。C函数的hook可以使用fishhook
- 减少开发量,方便复用
- 代码不集中,可能会散落在项目各个位置