首先上一个自己的结论,带着结论看文章可能更好理解~
总结:动态代理最终生成的代理类会实现你传入的所有接口,并在每一个实现的接口方法中调用InvocationHandler的invoke方法,在这个方法中需要我们将自己所需要的逻辑加入进去,这样就给你每一个实现的方法都套用上了相同的逻辑,达到减少代码松耦合的效果。
当一个或多个接口的实现方法中都需要套用上相同的逻辑就可以直接使用动态代理模式,达到减少代码松耦合的效果。
1. 静态代理
常规的代理模式有以下三个部分组成:
- 功能接口
interface IFunction {
void doAThing();
}
- 功能提供者(接口的实现类)
class FunctionProvider implement IFunction {
@Override
public void doAThing {
System.out.print("do A");
}
}
- 功能代理者
public class Proxy implements IFunction {
private IFunction provider;
Proxy(IFunction provider) {
this.provider = provider;
}
@Override
public void doAThing() {
//在这里可以添加自己需要给每个功能提供者都代理上的公用逻辑
doSomeThing();
provider.doAThing();
}
private void doSomeThing() {
System.out.println("This Time:" + (System.currentTimeMillis()));
}
}
运行一下看最终结果
public class MyClass {
public static void main(String args[]) {
IFunction iFunction = new FunctionProvider(); //新建具体实现类
Proxy proxy = new Proxy(iFunction); //放入代理类
proxy.doAThing(); //执行最终的逻辑,给方法套用相同的逻辑
}
}
可以看到如果使用静态代理,随着接口的增多,每新增或修改接口都需要改变代理类,这无疑是很不方便的。
2.动态代理
实现动态代理包括三步:
- 新建委托类;
- 实现
InvocationHandler
接口,这是负责连接代理类和委托类的中间类必须实现的接口; - 通过
Proxy
类新建代理类对象。
新建委托类
public interface IFunctionProxy {
void doAThing();
void doBThing();
void doCThing();
}
public class IFunctionProxyImpl implements IFunctionProxy {
@Override
public void doAThing() {
System.out.println("I am handle doAThing Method ");
}
@Override
public void doBThing() {
System.out.println("I am handle doBThing Method ");
}
@Override
public void doCThing() {
System.out.println("I am handle doCThing Method ");
}
}
实现InvocationHandler
并且通过Proxy
类新建代理类对象。
public class MyClass {
public static void main(String args[]) {
final IFunctionProxyImpl functionProxy = new IFunctionProxyImpl();
Object proxyInstance = java.lang.reflect.Proxy.newProxyInstance(functionProxy.getClass().getClassLoader(), new Class[]{IFunctionProxy.class}, new InvocationHandler() {
@Override
public Object invoke(Object obj, Method method, Object[] objects) throws Throwable {
//method表示代理对象被调用的方法。
//objects表示代理对象被调用的方法的参数。
// if (method.getName().equals("doAThing")) {
// System.out.print("do A:" + System.currentTimeMillis());
// }
System.out.println("Start:" + System.currentTimeMillis());
method.invoke(functionProxy, objects); //主动调用方法
System.out.println("End:" + System.currentTimeMillis());
return obj;
}
});
IFunctionProxy iFunctionProxy = (IFunctionProxy) proxyInstance;
iFunctionProxy.doAThing();
iFunctionProxy.doBThing();
iFunctionProxy.doCThing();
}
}
看下运行的结果:
当然你还可以直接传入接口而不传入委托类去生成代理对象,但这样的话就无法在invoke方法中调用method.invoke了(因为没有具体的实现方法)
,Retrofit框架用的就是这种生成代理对象的方法.
Object proxyInstance = java.lang.reflect.Proxy.newProxyInstance(IFunctionP.class.getClassLoader(), new Class[]{IFunctionP.class, IFunctionProxy.class}, new InvocationHandler() {
@Override
public Object invoke(Object obj, Method method, Object[] objects) throws Throwable {
System.out.println("Start:" + System.currentTimeMillis());
System.out.println("End:" + System.currentTimeMillis());
return obj;
}
});
IFunctionProxy iFunctionProxy = (IFunctionProxy) proxyInstance;
iFunctionProxy.doAThing();
iFunctionProxy.doBThing();
iFunctionProxy.doCThing();
IFunctionP iFunctionProxy1 = (IFunctionP) proxyInstance;
iFunctionProxy1.doIFunctionP();
可能看到此处还是一脸懵逼,下面让我用一下伪代码实现最终的类,以上方接口为例子
public class Proxy implements IFunctionP, IFunctionProxy {
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
System.out.println("Start:" + System.currentTimeMillis());
System.out.println("End:" + System.currentTimeMillis());
return null;
}
};
@Override
public String doIFunctionP() {
try {
Method method = IFunctionP.class.getMethod("doIFunctionP");
return (String) invocationHandler.invoke(this, method, null);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return null;
}
@Override
public void doAThing() {
try {
Method method = IFunctionProxy.class.getMethod("doAThing");
invocationHandler.invoke(this, method, null);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
@Override
public void doBThing() {
try {
Method method = IFunctionProxy.class.getMethod("doBThing");
invocationHandler.invoke(this, method, null);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
@Override
public void doCThing() {
try {
Method method = IFunctionProxy.class.getMethod("doCThing");
invocationHandler.invoke(this, method, null);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
}
可以看到最终生成的代理类会实现你传入的所有接口,并在每一个实现的接口方法中调用InvocationHandler的invoke方法
,这个方法中需要我们自己将自己所需要的逻辑加入进去,这样就给你每一个实现的方法都套用上了相同的逻辑,这样就达到减少代码,松耦合的效果。
使用场景
一个或多个接口的实现方法中都需要套用上相同的逻辑就可以直接使用动态代理模式去生成对象,达到减少代码松耦合的效果。
- 使用动态代理前伪代码如下:
Dao {
insert() {
判断是否有保存的权限;
开启事务;
插入;
提交事务;
}
delete() {
判断是否有删除的权限;
开启事务;
删除;
提交事务;
}
}
使用动态代理的伪代码如下:
// 使用动态代理,组合每个切面的函数,而每个切面只需要关注自己的逻辑就行,达到减少代码,松耦合的效果
invoke(Object proxy, Method method, Object[] args)
throws Throwable {
判断是否有权限;
开启事务;
Object ob = method.invoke(dao, args);
提交事务;
return ob;
}
- Retrofit框架
ublic <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
要注意的是Retrofit并没有委托类
,它只是很巧妙的运用了动态代理可以给所有执行的方法都套用上相同逻辑的特性,以此生成最终的Call类。