java的动态代理是用反射实现的。
什么是反射?
java的反射机制,是说在运行时刻,对于任何一个类,都能够知道它的所有属性和方法;对任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用方法的功能称为java的反射机制。
java
通过java.lang.Class
类实现反射机制。
Class类的getDeclaredMethod可以根据方法名字返回一个方法:
// 返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。
Method getDeclaredMethod(String name, Class<?>... parameterTypes)
Method的invoke方法可以执行这个方法:
// 对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。
Object invoke(Object obj, Object... args)
举个简单例子:
(参考:https://www.cnblogs.com/haodawang/p/5967185.html)
package com.bike;
import java.lang.reflect.*;
public class Main {
public static void main(String[] args) throws Exception{
//返回A的构造方法
Constructor c = A.class.getConstructor();
//返回A类的所有为public 声明的构造方法
Constructor[] cons = A.class.getConstructors();
//返回A类所有的构造方法,包括private
Constructor[] cons2 = A.class.getDeclaredConstructors();
//返回A类的第一个public 方法
Method m = A.class.getMethod("say");
//执行
m.invoke(A.class.newInstance(), null);
//返回A类所有的public 方法
Method[] ms = A.class.getMethods();
//返回A类所有的方法,包括private
Method[] allMs = A.class.getDeclaredMethods();
//返回A类的public字段
Field field = A.class.getField("i");
System.out.println(field.get(A.class.newInstance()));
//返回A类的static 字段
System.out.println(field.get(null));
}
}
class A{
public int i = 1;
public static int b = 2;
public A(){
System.out.println("无参构造");
}
private A(String s){
System.out.println("有参构造"+s);
}
public void say(){
System.out.println("say");
}
}
上面例子是反射,但这个例子没有用,这样用反射没有意义。反射怎么用呢?
上面例子中的类A
,在本地,用的是本地类加载器(有待细究),如果A不在本地,而在另一个机器上,通过网络类加载器,加载到本地虚拟机。那就感觉有点用了,实现在服务器,在客户端通过方法名称和参数,调用方法实现,这就是远程方法调用。
(参考:java api java.lang.ClassLoader
)
静态代理
什么是静态代理呢?
很简单,代理类和实现类实现同一个接口,代理类有一个实现类的引用,客户调用代理类的方法时,代理类就调用实现类的方法。称为静态,是因为代理类和实现类是写死的,就是在编译阶段就确定的。
// 接口
interface A {
public void f();
}
// 实现类
class AImpl implements A {
public void f() {
System.out.println("A.f()");
}
}
// 代理类
class AProxy implements A {
A a;
public AProxy(A a) {
this.a = a;
}
public void f() {
// do something else
a.f();
// do something else
}
}
// Client
public static void main() {
A aImpl = new AImpl();
AProxy aProxy = new AProxy(aImpl);
aProxy.f();
}
这个例子好像也没什么用,不过可以在代理类的f()方法调用实现类的方法前后加上一些代码;在构造方法中也可以通过网络类加载器加载别的机器上的类,这样本地调用时,感觉不到远程机器,就像调用本地代码一样。
如果有好多类要代理,就要写好几个代理类,这样比较麻烦,这时动态代理就有用了,动态代理的本质就是用户提供类名、方法名、参数,代理类执行方法,返回结果。
用类加载器可以将类加载到虚拟机,用Class clazz
表示,有这个对象,就可以执行它的方法。(这就是反射)
这就实现了动态代理。
具体实现:
动态代理类并不是程序员写的,而是根据传入的参数,由Proxy类在运行时生成的,所以可以传入不同的参数,这样就可以在运行时产生不同的代理类,所以是动态的。
// InvocationHandler实现类,里面有一个object对象,指向真正的实现类
InvocationHandler handler = new MyInvocationHandler();
// 代理类,是有Proxy生成的,根据这点代码,已知的是,它实现了被代理类的接口,而且它有个参数为InvocationHandler作为参数的构造函数
Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
Foo f = (Foo)proxyClass.getConstructor(InvocationHandler.class).newInstance(handler);
使用时,一般按下面的写法:
Foo f = (Foo)Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class<?>[]{Foo.class}, handler);
再多写一句,spring的AOP(面向切面编程)就是用的动态代理实现的,可以用于日志,权限控制,缓存等,可以在InvocationHandler中的invoke方法内部调用实际方法前后加上一些有用的代码。
反向代理
来源:https://www.zhihu.com/question/24723688
反向代理为何叫反向代理? - Tom朱的回答 - 知乎
https://www.zhihu.com/question/24723688/answer/68675168
下图来自知乎Tom朱,好形象啊,侵删
反向代理为何叫反向代理? - 班长他姐夫的回答 - 知乎
https://www.zhihu.com/question/24723688/answer/148017358
下面这句话来自知乎班长他姐夫,侵删
精辟,正向代理隐藏真实客户端,反向代理隐藏真实服务端,一下就懂了,很有帮助
反射应用
https://blog.csdn.net/briblue/article/details/73824058
注解
操作数据库通用代码,比如把查询的filed封装成一个类的实例,类时泛型