java中的动态代理和反射 反向代理

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朱,好形象啊,侵删
此图来自知乎Tom朱
反向代理为何叫反向代理? - 班长他姐夫的回答 - 知乎
https://www.zhihu.com/question/24723688/answer/148017358
下面这句话来自知乎班长他姐夫,侵删

精辟,正向代理隐藏真实客户端,反向代理隐藏真实服务端,一下就懂了,很有帮助

反射应用

https://blog.csdn.net/briblue/article/details/73824058
注解
操作数据库通用代码,比如把查询的filed封装成一个类的实例,类时泛型

  • 11
    点赞
  • 70
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值