简述:代理模式(Proxy),为其他对象提供一种代理以控制对这个对象的访问。
需求:现在需要实现加减乘除功能。
interface ICal{
int add(int a,int b);
int sub(int a,int b);
int mul(int a,int b);
int div(int a,int b);
}
class CalImlp implements ICal{
@Override
public int add(int a, int b) {
return a+b;
}
@Override
public int sub(int a, int b) {
return a-b;
}
@Override
public int mul(int a, int b) {
return a*b;
}
@Override
public int div(int a, int b) {
return a/b;
}
}
/*===================客户端=============*/
public class negtive {
public static void main(String[] args) {
Calculator c = new MyCalculator();
System.out.println(c.add(2, 3));
System.out.println(c.sub(10, 3));
System.out.println(c.mul(8, 3));
System.out.println(c.div(99, 3));
}
}
看起来十分简单
但是,变化来了,想要给每个方法加入一些输出提示
难道要每个方法都加上输出提示???
那如果需求又变了,输出提示显示为英文,又要全部改一遍???
No!!!
此时我们就需要引入动态代理
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
- 第1个参数:ClassLoader(动态代理的对象的类加载器)
我们都知道,要实例化一个对象,是需要调用类的构造器的,在程序运行期间第一次调用构造器时,就会引起类的加载,加载类的时候,就是jvm拿着ClassLoader去加载类的字节码的,只有字节码被加载到了内存中,才能进一步去实例化出类的对象。
简单来说,就是只要涉及实例化类的对象,就一定要加载类的字节码,而加载字节码就必须使用类加载器!下面我们使用的是动态代理的api来创建一个类的对象,这是一种不常用的实例化类对象的方式,尽管不常用,但毕竟涉及实例化类的对象,那就一定也需要加载类的字节码,也就一定需要类加载器,所以我们手动把类加载器传入!
-
第2个参数:Class[](需要调用其方法的接口) 我们已经知道,下面的代码,是用来实例化一个对象的,实例化对象,就一定是实例化某一个类的对象,问题是,到底是哪个类呢?类在哪里?字节码又在哪里?这个类,其实并不在硬盘上,而是在内存中!是由动态代理在内存中"f动态生成的!要知道,这个在内存中直接生成的字节码,会去自动实现下面方法中的第2个参数中,所指定的接口!所以,利用动态代理生成的代理对象,就能转成Calculator接口类型!那么这个代理对象就拥有add、 sub、 mul 、div方法!
-
第3个参数:InvocationHandler(调用方法时的处理程序) 我们已经知道,下面的代理对象porxy所属的类,实现了Calculator接口,所以,这个代理对象就拥有add、 sub、 mul 、div方法!我们就可以通过代理对象调用add、 sub、 mul 、div方法!注意,每次对代理对象任何方法的调用,都不会进入真正的实现方法中。而是统统进入第3个参数的invoke方法中!
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
Object proxy 代理对象
Method代理对象调用的方法
Object[] args调用方法的参数
实现
public class MyHandler implements InvocationHandler {
private Calculator calculator ;
public MyHandler(Calculator c){
this.calculator = c;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("调用"+method.getName()+", 参数是"+ Arrays.toString(args));
int res = (int) method.invoke(calculator, args);
System.out.println("结果是 "+res);
return res;
}
}
//先把InvocationHandler的实现类设计好。在实现类的内部关联Calculator,用于调用Calculator的方法。
Copy
public class postive {
public static void main(String[] args) {
Calculator c = new MyCalculator();
ClassLoader loader = postive.class.getClassLoader();
Calculator proxy = (Calculator)Proxy.newProxyInstance(loader, new Class[]{Calculator.class}, new MyHandler(c));
proxy.add(22,33);
proxy.sub(55,22);
proxy.div(10,2);
proxy.mul(50,5);
}
}
总结 代理模式是代理对象通过在其内部关联被代理对象,对被代理对象的方法实施扩展。