序言
在看Retrofit源码时,我们会发现里面是使用了Java的动态代理的。 以前也接触过动态代理,平常不用,时间就久了就会慢慢淡忘。所以平常多总结,任何知识点也是如此。
作用
- 为其他的对象提供一种代理来控制这个对象的访问。
- 增强目标对象的功能
静态代理
开发者接口
public interface IDeveloper {
void writeCode();
}
Android开发者
public class AndroidDeveloper implements IDeveloper {
@Override
public void writeCode() {
System.out.println("Write Android Code");
}
}
测试
public class DevelopTest {
public static void main(String arg[]){
IDeveloper developer=new AndroidDeveloper();
developer.writeCode();
}
}
运行结果:
Write Android Code
现在麻烦的是,如果以后上级领导说,写代码前必须写注释写文档。 那我们就需要修改AndroidDeveloper这个类,这就不符合 “开闭原则”(对扩展开放,对修改关闭)。 所以我们可以创建个代理类,以不修改原始类中的代码来实现增强。
代理类
public class DeveloperProxy implements IDeveloper {
private IDeveloper developer;
public DeveloperProxy(IDeveloper developer){
this.developer=developer;
}
@Override
public void writeCode() {
System.out.println("write Document or Note");
developer.writeCode();
}
}
测试
public class DevelopTest {
public static void main(String arg[]){
IDeveloper developer=new AndroidDeveloper();
DeveloperProxy proxy=new DeveloperProxy(developer);
proxy.writeCode();
}
}
运行结果:
write Document or Note
Write Android Code
可以看到我们在没有修改AndroidDevelop这个类,通过代理类来实现增强。
总结:
- 被代理的类(AndroidDeveloper)和代理类(DeveloperProxy)实现了同一个接口,然后在代理类中引入AndroidDeveloper对象的引用。
- 可以不改变被代理的类,来增强功能。
优点:
- 代理使客户端不需操作 被代理的类(AndroidDeveloper), 只需要操作代理类(DeveloperProxy)就行了(解耦合)。
缺点:
- 代理类跟被代理的类需要实现同样的接口,代理类跟被代理的类也实现了相同的方法,这样就出现大量的重复代码,接口增加一个方法,代理和被代理类就同时实现这个方法,增加代码维护的复杂度。
- 代理类只能代理一种类型(IDeveloper)的对象 ,如果代理多种类型的对象,那肯定为每一种对象进行代理, 这种的情况静态代理就做不了了。
即静态代理类只能为特定的接口服务,如果为多个接口服务,那必须建立多个代理类。
动态代理
开发者接口(需要动态代理的接口)
public interface IDeveloper {
void writeCode();
}
Android开发者(动态代理的实际对象)
public class AndroidDeveloper implements IDeveloper {
@Override
public void writeCode() {
System.out.println("Write Android Code");
}
}
代理方法被调用前后执行的操作 抽象出来。
public interface Before {
public void before();
}
public interface After {
void after();
}
创建自己的调用处理器,统一来处理和过滤一些消息。
public class InvocationHandlerImpl implements InvocationHandler {
private Object targetObject; //需要代理的对象
Before before;
After after;
public Before getBefore() {
return before;
}
public void setBefore(Before before) {
this.before = before;
}
public After getAfter() {
return after;
}
public void setAfter(After after) {
this.after = after;
}
public InvocationHandlerImpl(Object targetObject){
this.targetObject=targetObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/* 代理方法执行前 执行其他的操作*/
if (before!=null){
before.before();
}
Object result=method.invoke(targetObject,args);
/* 代理方法执行后 执行其他的操作*/
if (after!=null){
after.after();
}
return result;
}
}
测试
public class DevelopTest {
public static void main(String arg[]){
final IDeveloper p=new AndroidDeveloper();//需要代理的对象
InvocationHandlerImpl invocationHandler=new InvocationHandlerImpl(p);
invocationHandler.setBefore(new Before() {
@Override
public void before() {
System.out.println("write Document or Note ");
}
});
invocationHandler.setAfter(new After() {
@Override
public void after() {
System.out.println("Review Code ");
}
});
IDeveloper proxy= (IDeveloper) Proxy.newProxyInstance(p.getClass().getClassLoader(), new Class[]{IDeveloper.class},invocationHandler);
proxy.writeCode();
}
}
运行结果:
write Document or Note
Write Android Code
Review Code
说明:
- 当 proxy.writeCode()执行时, 会回调到这个InvocationHandlerImpl中的invoke方法。
- InvocationHandler中的invode方法中的三个参数 1: 代理对象(proxy) 2: 方法对象(writeCode) 3:方法参数
- newProxyInstance方法中的三个参数 1: 类加载器 2: 代理所实现的接口 3: 表示的是当动态代理对象调用方法时,会关联到这个对象上
JDK动态代理实现的步骤:
- 创建被代理的类和以及实现的接口;
- 创建一个实现接口InvocationHandler的类。 实现invoke方法;
- 调用Proxy的newProxyInstance 静态方法,动态生成代理类;
- 通过代理对象调用目标方法, 然后会转发到invoke方法;
总结:
- 动态代理类在程序运行时动态生成,不需要写代理类源代码;
- 被代理的类必须实现接口,代理的类没有实现接口的就不行(原因是Java不能进行多继承,只能实现多接口);
- 基于Java内部的反射机制来实现;
Cglib 代理
Android开发者(动态代理的实际对象 不需实现任何接口)
public class AndroidDeveloperr {
public void writeCode() {
System.out.println("Write Android Code");
}
}
代理方法被调用前后执行的操作 抽象出来。
public interface Before {
public void before();
}
public interface After {
void after();
}
创建自己的方法拦截器,统一来处理和过滤一些消息。
public class MethodInterceptorImpl implements MethodInterceptor {
Before before;
After after;
public Before getBefore() {
return before;
}
public void setBefore(Before before) {
this.before = before;
}
public After getAfter() {
return after;
}
public void setAfter(After after) {
this.after = after;
}
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
if (before!=null){
before.before();
}
Object result=methodProxy.invokeSuper(o,args);
if (after!=null){
after.after();
}
return result;
}
}
测试
public class DevelopTest {
public static void main(String arg[]){
MethodInterceptorImpl methodInterceptor=new MethodInterceptorImpl();
methodInterceptor.setBefore(new Before() {
@Override
public void before() {
System.out.println("write Document or Note ");
}
});
methodInterceptor.setAfter(new After() {
@Override
public void after() {
System.out.println("Review Code ");
}
});
Enhancer enhancer=new Enhancer();//创建增强类
enhancer.setSuperclass(AndroidDeveloper.class);//设置继承被代理类
enhancer.setCallback(methodInterceptor);//设置回调
AndroidDeveloper androidDeveloper= (AndroidDeveloper) enhancer.create();//生成代理对象
androidDeveloper.writeCode();//在调用代理方法时,会回调到我们设置的方法拦截器上所拦截
}
}
运行结果:
write Document or Note
Write Android Code
Review Code
说明:
- MethodInterceptor中intercept 四个参数的含义 1:cglib生成的代理对象 2: 被代理的对象的方法对象 3: 方法的参数 4: 代理方法对 象
总结 :
- 可以对类进行代理,不用基于接口代理;
- 不能对final修饰的类和final方法进行代理(原因是final修饰的 不能被继承)
JDK和Cglib 区别
- JDK原生动态代理不需要引入任何的依赖,但是它是基于接口来进行代理;
- Cglib 是通过继承的方法来进行代理,不管目标对象有没有实现接口都能进行代理,但是无法代理final的情况。还有就是需要引入相应的依赖;