一.什么是动态代理
动态代理就是为了生成一个代理对象,来代理真实对象,从而来控制真实对象的访问。比如,一家软件公司,有商务负责接待客户,软件工程师负责制作软件。当客户来谈业务时,找的是商务,客户就认为商务代表公司,但是真正完成客户需求的是工程师。这时可以认为商务就是代理对象,来代理工程师,起的是客户与工程师之间的中介作用。
当一个代理对象想代理真实对象时,需要两步,一是要和真实对象建立代理关系,二是要实现代理对象的代理逻辑方法。二者缺一不可。
Java中有很多动态代理技术,但常用的只有JDK,CGLIB。
二.JDK动态代理
JDK动态代理是java.lang.reflect.*包提供,它有一个大前提,必须借助一个接口才能实现代理对象。所以先定义接口。
package 动态代理;
public interface Hello {
public void sayHello();
}
然后有实现类来实现接口
package 动态代理;
public class HelloImpl implements Hello {
@Override
public void sayHello() {
// TODO Auto-generated method stub
System.out.println("Hello World!");
}
}
有了接口和实现类,满足了JDK动态代理的大前提,现在可以开始动态代理了。我们之前说了,要有两步,一建立代理对象与真实对象的关系,二实现代理逻辑
在JDK动态代理中,实现代理逻辑类必须实现java.lang.reflect.InvocationHandler接口,它有一个Invoke方法需要实现。
package 动态代理;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKProxyExample implements InvocationHandler {
//真是对象
private Object target=null;
public Object bind(Object target){
this.target=target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
System.out.println("进入代理逻辑方法");
System.out.println("在调用真实对象前的服务");
Object obj = method.invoke(target, args);
System.out.println("在调用真实对象后的服务");
return obj;
}
}
首先建立代理对象与真实对象的关系。代码中通过bind方法完成,首先用类的属性target来保存了真实的需要代理的对象,然后通过下列代码建立并生成代理对象。
Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
Proxy.newProxyInstance()方法来生成代理对象,需要传递三个参数
第一个:类加载器
第二个:把生成对象挂在了哪些接口下,写目标类(被代理类)实现的接口即可
第三个:定义实现代理逻辑的代理类,该类需要实现InvocationHandler接口的Invoke方法,所以我们传入当前对象this。
完成了代理对象与真实对象关系的建立,下一步需要实现代理的逻辑方法,代理的逻辑方法在invoke方法中完成。有代码所示,invoke方法自动传入三个参数
第一个:proxy代理对象,就是上面bind方法生成的代理对象。
第二个:当前调度的方法
第三个:调度的方法的参数
当进入方法中后,它会进入invoke方法里调用真实对象(被代理对象)的方法,只是是通过反射实现。
测试类:
package 动态代理;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
JDKProxyExample jdk =new JDKProxyExample();
Hello proxy = (Hello) jdk.bind(new HelloImpl());
proxy.sayHello();
}
}
可以通过打断点调试的方式,更好的理解整个流程,一定要掌握好