java动态代理
前几天面试,被问到java动态代理,当时支支吾吾回答了,用到了字节码生成技术,proxy,Method类。动态代理用到了反射,在面试中经常被问到,自己也有断断续续学习,这方面的知识。但是一直都不是太明白。看了一些博客后,现在将自己的理解整理如下:
首先写了一个car接口类,里面只有一个接口run
package proxy; public interface Car{ public void run(); }
接着写一个car接口的实现类,
package proxy; public class BMWCar implements Car { @Override public void run() { System.out.println("BMW car is running!"); } }
然后是编写Invoke类,我认为这个类并不是必须的,即没有这个类,一样可以实现动态代理,即在代理类中直接通过obj.run()一样可以实现动态代理。但是由于,java中的代理是动态的,是自动生成的,我们无法直接在动态代理类 加入新的功能。
所以,只能通过反射技术,间接调用被代理对象中的方法。
package proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class Invoke implements InvocationHandler { public Object obj; public Invoke(Object obj) { this.obj=obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("进入了invoke方法"); Object re=method.invoke(obj, args); System.out.println("结束了invoke方法"); return re; } }
然后加入main类,测试我们的动态代理是否成功。
package proxy;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Main {
public static void main(String[] args) {
Car car=new BMWCar();
Invoke in=new Invoke(car);
Method me=null;
try {
Car carProxy=(Car)Proxy.newProxyInstance(car.getClass().getClassLoader(), car.getClass().getInterfaces(), in);
carProxy.run();
} catch (Throwable e) {
e.printStackTrace();
}
}
}
看了其他资料后,我发现java动态代理会生成一个$proxy.class的代理类,我没有找到这个类,难不成它不放在磁盘文件中?
现在我推测$proxy.class类的代码是这样的:
package proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class $Proxy extends Proxy implements Car { //Proxy类中有protected修饰的invokeHandler对象,当前类可以使用 private static Method m1=null; static { try{ m1=Class.forName("proxy.Car").getMethod("run", new Class[0]); } catch (NoSuchMethodException | SecurityException | ClassNotFoundException e) { e.printStackTrace(); } } protected $Proxy(InvocationHandler h) { super(h); } @Override public void run() { try { super.h.invoke(this, m1, null); } catch (ClassNotFoundException e1) { e1.printStackTrace(); } catch (Throwable e) { e.printStackTrace(); } } }