静态代理
和代理设计模式比较接近, 写一个类, 将一个类, 或一个借口当做成员属性, 在增强的代码块中执行被代理类的方法即可.
缺点: 需要针对不同的被代理类编写不同的代理类.
动态代理
不用手写定义, 由虚拟机在运行时, 根据配置规则, 在环境中生成Class类, 来生成实例对象.
动态代理有两种方式, 一个是JDK的动态代理, 一个是cglib.
由于提倡的是面向接口编程, 因此jdk动态代理是针对接口实现类的代理, 代理类可以实现接口的各种实现, 比较符合抽象编码规则.
cglib则是会生成代理对象的继承类, 起到能够代理所有的方法的作用.
jdk动态代理
JDK提供了java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy类,这两个类相互配合,入口是Proxy.
Proxy.getProxyClass()会根据接口的Class, 获取一个代理类的Class.
接口是没有构造器的, 但是代理类是有的, 还是有参的构造器.
Class animalClazz = Proxy.getProxyClass(Animal.class.getClassLoader(), Animal.class);
System.out.println(animalClazz.getName());
System.out.println(Animal.class.getName());
接下来就是获取构造器, jdk提供了含参构造器, 参数是InvocationHandler. 它是代理类的一个属性, 会作为中介, 调用被代理类的方法.
InvocationHandler的invoke方法的结果, 会代替代理目标的方法.
Constructor constructor = animalClazz.getConstructor(InvocationHandler.class);
Animal animal = (Animal) constructor.newInstance(new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("method start...");
// 执行具体的业务逻辑
Object object = method.invoke(target, args);
System.out.println("method end...");
return object;
}
});
return animal;
不过实际编程中,一般不用getProxyClass(),而是使用Proxy类的另一个静态方法:Proxy.newProxyInstance(),直接返回代理实例
Object proxy = Proxy.newProxyInstance(
target.getClass().getClassLoader(),/*类加载器*/
target.getClass().getInterfaces(),/*让代理对象和目标对象实现相同接口*/
new InvocationHandler(){/*代理对象的方法最终都会被JVM导向它的invoke方法*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName() + "method start...");
Object result = method.invoke(target, args);
System.out.println(result);
System.out.println(method.getName() + "method end...");
return result;
}
}
);
return proxy;
可以输出代理类的代码来看看
byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Animal.class});
FileOutputStream fileInputStream = new FileOutputStream("hello.class");
fileInputStream.write(bytes);
fileInputStream.flush();
fileInputStream.close();
System.out.println("完毕");