学习动态代理之前需要了解静态代理 并且牢记静态代理的缺点
//首先被代理的类需要实现一个接口
public interface ProxyInterface {
public void say(String str);
}
//然后写一个实现类 也就是需要被代理的类
public class ProxyImpl implements ProxyInterface {
@Override
public void say(String str) {
System.out.println("ProxyImpl.say is " +str);
}
}
//然后写代理类
public class ProxyClass implements InvocationHandler {
Object o;
public void setTarget(Object o){
this.o = o;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("在调用方法之前执行的方法");
method.invoke(o,args);
System.out.println("在调用方法之后执行的操作");
return null;
}
}
//调用
// jdk动态代理
public static void main(String[] args) {
ProxyInterface proxyInterface = new ProxyImpl();
ProxyClass proxyClass = new ProxyClass();
proxyClass.setTarget(proxyInterface);
//传递被代理类的类加载器 接口 代理类 返回被代理类
ProxyInterface proxy = (ProxyInterface)Proxy.newProxyInstance(proxyInterface.getClass().getClassLoader(),proxyInterface.getClass().getInterfaces(),proxyClass);
System.out.println("------------------------------------------");
proxy.say("hello");
System.out.println(proxy.getClass().getName());
System.out.println(proxyInterface.getClass().getName());
}
在调用方法之前执行的方法
ProxyImpl.say is hello
在调用方法之后执行的操作
com.sun.proxy.$Proxy0 //这是jdk生成的代理类
com.test.Proxy.ProxyImpl //这是被代理的类
Process finished with exit code 0
说明:
代理类 ProxyClass 需要实现接口InvocationHandler 并重写里面的方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(“在调用方法之前执行的方法”);
method.invoke(o,args);
System.out.println(“在调用方法之后执行的操作”);
return null;
}
其中 method.invoke(o,args);
除第一个参数外剩下的是固定写法 第一个参数就是我们要代理的实现类
在method.invoke(o,args); 之前我们加的方法或者代码 都会在被代理的方法之前执行
在method.invoke(o,args); 之后我们加的方法或者代码 都会在被代理的方法之后执行
动态代理是为了解决静态代理的缺点而诞生的,所以我们要了解动态代理与静态代理的区别
区别:
动态代理不需要我们手写代理类,上述ProxyClass 我们说他是代理类 是因为写法不同 假设不写ProxyClass这个类 我们可以这样实现动态代理
public static void main(String[] args) {
ProxyInterface proxyInterface = new ProxyImpl();
ProxyInterface proxy = (ProxyInterface)Proxy.newProxyInstance(
proxyInterface.getClass().getClassLoader(),
proxyInterface.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("之前执行");
method.invoke(proxyInterface,args);
System.out.println("之后执行");
return null;
}
});
proxy.say("另一种实现");
}
//结果
之前执行
ProxyImpl.say is 另一种实现
之后执行
Process finished with exit code 0
第一种写法不过是把InvocationHandler接口的实现写写出来,第二种则是在用到时候在实现InvocationHandler接口
无论怎么写 我们以第一种写法为例:我们会发现两件事
我们的代理类实际上是在jdk中编译期间动态生成的,换句话说,我们的jdk在编译的时候,根据proxyInterface.getClass().getInterfaces()这个接口 动态创建了他的实现类,由于编译的时候才生成的实现类,所以接口必然不会改变了,而同时实现代理的时候,是传递需要代理类,的实现,无关接口 所以并不需要为每一种接口都写一个代理类了,
总结起来就是动态代理把静态代理需要预先人为写出代理类的步骤交给jdk在编译的时候生成,所以避免了静态代理的缺点