上一篇简单说了下动态代理的基础,大概怎么去创建一个动态代理实例。然后有什么好处:往往我们不愿意去修改一些接口方法,为了兼容旧版也不会轻易去删除增加参数啥的。这个时候往往我们开发新版本会这样做:
1.新增接口,重载方法
2. 如果只是在原来的基础上做细微的改动,比如增加统计,增加中间加密处理等,这个时候我们往往可以利用代理模式去动态创建一个代理实例对象,然后加入处理过程,这样提供一个新版接口供用户调用。
这样一来可以解决兼容性和重新开发的问题,做好维护就行。
既然涉及到代理,我们就看看代理模式的一些知识。正好可以过一遍设计模式中的一种,23种设计模式那本书或许我们平时只用到了两三种,只能说我们理解的太浅!而且是太肤浅!
开始吧
三种代理模式说下先:静态代理 动态代理(上一篇已经有所表述) cglib代理(这个相对要难理解一点)
静态代理比较好理解,就是创建一个类,通过该代理类去调用目标对象的方法,必须:该代理类和目标对象必须继承同一个接口(你可以不继承同一个对象,甚至代理类都可以不用继承同一个接口,调用方法也可以随意取,但那样就没什么意思了,对吧?)
1.建立一个吃饭的接口
package com.test.com.myapplicationexercisetwo;
/**
* Author:hl
* Time: 2018/6/5 11:15
* Des: This is Eat - 吃饭
*/
public interface Eat {
/**
* 吃米饭
*/
public void eatRice();
}
2.新增一个小孩吃饭的类,继承Eat接口
package com.test.com.myapplicationexercisetwo;
import android.util.Log;
/**
* 小孩子
*/
public class Children implements Eat {
private String TAG = "Children";
@Override
public void eatRice() {
Log.e(TAG, "很小的小孩自己吃米饭有点困难");
}
}
3.考虑到很小的小孩吃饭有困难,我们安排目前喂小孩,同时母亲还可以拍照留恋
package com.test.com.myapplicationexercisetwo;
import android.util.Log;
/**
* Author:hl
* Time: 2018/6/5 11:21
* Des: This is ChildrenProxy - 孩子的监护人喂小孩,还拍照留恋。母爱最伟大..
*/
public class ChildrenProxy implements Eat {
private static final String TAG = "ChildrenProxy";
private Eat eat;
public ChildrenProxy(Eat eat){
this.eat = eat;
}
@Override
public void eatRice() {
Log.e(TAG, "孩子, 妈妈拿勺子来喂你!");
eat.eatRice();
Log.e(TAG, "妈妈给你拍照留恋一下你小时候!");
}
}
4.我们来验证下结果
image静态代理大概就是这样一个套路,应该是还有更复杂的使用场景,我觉得随着深入以及工作的一些经验和项目的重构等,会逐渐的去认知这些东西。会越来越熟悉的。正在努力~~~
至于动态代理看上一篇就好了
至于Cglib我们先过一下概念吧,然后了解下就好。因为毕竟陌生,也见的少,几乎没用过,所以就看看先。
看段文字先(先知道,如果目标类,代理类没有继承接口的情况下,怎么去做代理):
上面的静态代理和动态代理模式都是要求目标对象是实现一个接口的目标对象,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式类实现代理,这种方法就叫做:Cglib代理
Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展.
JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口,如果想代理没有实现接口的类,就可以使用Cglib实现.
Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口.它广泛的被许多AOP的框架使用,例如Spring AOP和synaop,为他们提供方法的interception(拦截)
Cglib包的底层是通过使用一个小而块的字节码处理框架ASM来转换字节码并生成新的类.不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉.
Cglib子类代理实现方法:
1.需要引入cglib的jar文件,但是Spring的核心包中已经包括了Cglib功能,所以直接引入pring-core-3.2.5.jar即可.
2.引入功能包后,就可以在内存中动态构建子类
3.代理的类不能为final,否则报错
4.目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法.
怎么使用了?
1.引入cglib包
image2.然后代理类继承MethodInterceptor接口,实现intercept方法,同时提供一个创建代理对象的方法getProxyInstance(解释下:我们在没有继承接口的情况下,并不知道目标对象到底提供了什么方法;这个时候我们只能通过cglib去获取代理对象,然后当代理对象生成后去执行它自己的方法的时候就会运行我们的intercept回调,此时,我们就可以通过method.invoke去执行代理对象的方法了,同时插入自己的处理 - 其实这个机制和动态代理类似,区别就是创建动态代理对象上面)
package com.test.com.myapplicationexercisetwo;
import android.util.Log;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* Author:hl
* Time: 2018/6/5 11:21
* Des: This is ChildrenProxy - 孩子的监护人喂小孩,还拍照留恋。母爱最伟大..
*/
public class ChildrenProxy implements MethodInterceptor {
private static final String TAG = "ChildrenProxy";
private Object eat;
public ChildrenProxy(Object eat){
this.eat = eat;
}
public Object getProxyInstance(){
Enhancer en = new Enhancer();
en.setSuperclass(eat.getClass());
en.setCallback(this);
return en.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Log.e(TAG, "孩子, 妈妈拿勺子来喂你!");
Log.e(TAG, "妈妈给你拍照留恋一下你小时候!");
return method.invoke(eat, objects);
}
}
到这里就算是理解了下三种代理模式,后面慢慢深入吧。下一步我们就利用动态代理继续完善下Android自定义注解...每天能坚持一下也是好的!
网友评论