问题:
动态代理是基于什么原理?
知识点:
- Java是静态的强类型语言,但是因为提供了类似反射等机制,也具备了部分动态类型的语言能力。
- 代理模式:
定义:给某个对象提供一个代理对象,并由代理对象控制对于原对象的访问,即客户不直接操控原对象,而是通过代理对象间接地操控原对象。(类似在上海这边经常看到的房屋中介)
静态代理模式代码:
public class ProxyDemo {
public static void main(String args[]){
RealSubject subject = new RealSubject();
Proxy p = new Proxy(subject);
p.request();
}
}
interface Subject{
void request();
}
class RealSubject implements Subject{
public void request(){
System.out.println("request");
}
}
class Proxy implements Subject{
private Subject subject;
public Proxy(Subject subject){
this.subject = subject;
}
public void request(){
System.out.println("PreProcess");
subject.request();
System.out.println("PostProcess");
}
}
- 反射:
Java 反射机制在程序运行时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。这种 动态的获取信息 以及 动态调用对象的方法 的功能称为 java 的反射机制。
反射机制很重要的一点就是“运行时”,其使得我们可以在程序运行时加载、探索以及使用编译期间完全未知的 .class 文件。换句话说,Java 程序可以加载一个运行时才得知名称的 .class 文件,然后获悉其完整构造,并生成其对象实体、或对其 fields(变量)设值、或调用其 methods(方法)。具体可以参考:Java 反射由浅入深 | 进阶必备
运行时注解利用反射会影响性能,编译时候注解不会影响性能。
通过注解方式声明订阅方法,速度相比2.x会变慢,通过引入注解处理器(annotation processor),在编译期间建立订阅方法的索引,性能有明显提升。
根据官方说明,注解的引入让EventBus 3.0相比2.x性能变差3-5倍,但是引入索引,3.0相比2.x性能提高至少3倍。
详细了解请参考:EventBus 3.0 最佳实践和原理浅析
- 动态代理:
为其他对象提供一种代理以控制对这个对象的访问。某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以再两者之间起到中介作用。运行阶段才指定代理哪个对象。
组成元素:- 抽象类接口
- 被代理类(具体实现抽象类接口的类)
- 动态代理类,实际调用被代理类的方法和属性
实现方式
- [x] JDK 自身提供的动态代理,就是主要利用了反射机制
//retrofit2.Retrofit源码中就使用到了
public <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();
@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);
}
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
其他实现方式:利用字节码操作机制,类似ASM、GGLB(基于ASM)、Javassist等
回答问题:
这里不作回答了,自己根据上面知识点进行总结吧。在APM功能开发的时候,动态代理使用场景及其广泛,以及在我们针对不同机型适配的时候,反射使用场景次数较多。
/**
* 隐藏系统键盘
*/
public void hintSystemSoftKeyboard() {
if (getWindowToken() != null) {
((InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(getWindowToken(), 2);
}
if (Build.VERSION.SDK_INT >= 11) {
try {
//以下是本章重点内容,请仔细体会
Class[] arrayOfClass = new Class[1];
arrayOfClass[0] = Boolean.TYPE;
Method localMethod = null;
if (Build.VERSION.SDK_INT < 17) {
localMethod = EditText.class.getMethod("setSoftInputShownOnFocus", arrayOfClass);
} else {
localMethod = EditText.class.getMethod("setShowSoftInputOnFocus", arrayOfClass);
}
localMethod.setAccessible(true);
Object[] arrayOfObject = new Object[1];
arrayOfObject[0] = Boolean.valueOf(false);
localMethod.invoke(this, arrayOfObject);
return;
} catch (SecurityException localSecurityException) {
localSecurityException.printStackTrace();
return;
} catch (NoSuchMethodException localNoSuchMethodException) {
localNoSuchMethodException.printStackTrace();
return;
} catch (Exception localException) {
localException.printStackTrace();
return;
}
}
setInputType(0);
}
参考:
- 代理模式及Java实现动态代理
- Java 反射由浅入深 | 进阶必备
- EventBus 3.0 最佳实践和原理浅析
- Retrofit部分源码
- 极客时间APP核心技术第六讲|动态代理是基于什么原理?
- 自己项目中部分代码
声明:此为原创,转载请联系作者
作者:微信公众号添加公众号-遛狗的程序员 ,或者可以扫描以下二维码关注相关技术文章。
qrcode_for_gh_1ba0785324d6_430.jpg当然喜爱技术,乐于分享的你也可以可以添加作者微信号:
WXCD.jpeg
网友评论