一、基本介绍
二、静态代理
接口
//接口public interface ITeacherDao {void teach(); // 授课的方法}
被代理对象
public class TeacherDao implements ITeacherDao {@Overridepublic void teach() {// TODO Auto-generated method stubSystem.out.println(" 老师授课中 。。。。。");}}
代理对象
//代理对象,静态代理public class TeacherDaoProxy implements ITeacherDao{private ITeacherDao target; // 目标对象,通过接口来聚合//构造器public TeacherDaoProxy(ITeacherDao target) {this.target = target;}@Overridepublic void teach() {// TODO Auto-generated method stubSystem.out.println("开始代理 完成某些操作。。。。。 ");//方法target.teach();System.out.println("提交。。。。。");//方法}}
客户端测试
public class Client {public static void main(String[] args) {// TODO Auto-generated method stub//创建目标对象(被代理对象)TeacherDao teacherDao = new TeacherDao();//创建代理对象, 同时将被代理对象传递给代理对象TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(teacherDao);//通过代理对象,调用到被代理对象的方法//即:执行的是代理对象的方法,代理对象再去调用目标对象的方法teacherDaoProxy.teach();}}
三、动态代理
接口
//接口public interface ITeacherDao {void teach(); // 授课方法void sayHello(String name);}
被代理对象
public class TeacherDao implements ITeacherDao {@Overridepublic void teach() {// TODO Auto-generated method stubSystem.out.println(" 老师授课中.... ");}@Overridepublic void sayHello(String name) {// TODO Auto-generated method stubSystem.out.println("hello " + name);}}
代理对象(简单写法)
public class JDKProxy implements InvocationHandler {//需要代理的目标对象。//targetObject就是咱们的Rent接口public Object targetObject;//代理对象目标public void setTargetObject(Object targetObject) {this.targetObject = targetObject;}//生成得到代理类public Object getTargetObject(){/*** 返回代理对象* 参数一:指定当前目标对象使用的类加载器。* 参数二:目标对象实现的接口的类型。* 参数三:事件处理器。这里写的this是代表下边重写的invoke方法*/return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),targetObject.getClass().getInterfaces(),this);}/*** 实现InvocationHandler接口,就要重写invoke方法。* proxy,调用该方法的代理实例* method,要执行的目标对象的方法(利用反射的原理)* args,执行某方法需要的参数。*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {seeHouse();//看房//动态代理的本质,就是使用反射机制实现Object result = method.invoke(targetObject,args);hetong();//签合同fare();//收费return result;}public void seeHouse(){System.out.println("中介带你看房子");}public void hetong(){System.out.println("签订租赁合同");}public void fare(){System.out.println("收中介费");}}
代理对象(复杂写法)
public class ProxyFactory {//维护一个目标对象(即被代理的对象) , Objectprivate Object target;//构造器 , 对target 进行初始化public ProxyFactory(Object target) {this.target = target;}//给目标对象 生成一个代理对象public Object getProxyInstance() {//说明/* 方法原型:* public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)//1. ClassLoader loader : 指定当前目标对象使用的类加载器, 获取加载器的方法,固定//2. Class<?>[] interfaces: 目标对象实现的接口类型,使用泛型方法确认类型//3. InvocationHandler h : 事情处理,执行目标对象的方法时,会触发事情处理器方法, 会把当前执行的目标对象方法作为参数传入*/return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// TODO Auto-generated method stubSystem.out.println("JDK代理开始~~");//反射机制调用目标对象的方法Object returnVal = method.invoke(target, args);System.out.println("JDK代理提交");return returnVal;}});}}
客户端测试
public class Client {public static void main(String[] args) {// TODO Auto-generated method stub//创建目标对象ITeacherDao target = new TeacherDao();//给目标对象,创建代理对象, 可以转成 ITeacherDaoITeacherDao proxyInstance = (ITeacherDao)new ProxyFactory(target).getProxyInstance();// proxyInstance=class com.sun.proxy.$Proxy0 内存中动态生成了代理对象System.out.println("proxyInstance=" + proxyInstance.getClass());//通过代理对象,调用目标对象的方法//proxyInstance.teach();proxyInstance.sayHello(" tom ");}}
注意:
代理对象不用实现接口,但目标对象(房东host)一定要实现接口(Rent),否则不能使用JDK动态代理。
四、Cglib代理


- 上边的静态代理和JDK动态代理都需要目标对象实现一个接口(Host实现Rent),但有时候,目标对象就是一个对象,没有实现任何接口,就不能使用JDK动态代理。那这时候可以使用CGLib代理。
- CGLibb代理也叫子类代理,它是在内存中构建一个子类对象,从而实现对目标对象功能的扩展。
被代理对象
public class TeacherDao {public String teach() {System.out.println(" 老师授课中 , 我是cglib代理,不需要实现接口 ");return "hello";}}
代理对象
public class ProxyFactory implements MethodInterceptor {//维护一个目标对象private Object target;//构造器,传入一个被代理的对象public ProxyFactory(Object target) {this.target = target;}//返回一个代理对象: 是 target 对象的代理对象public Object getProxyInstance() {//1. 创建一个工具类Enhancer enhancer = new Enhancer();//2. 设置父类enhancer.setSuperclass(target.getClass());//3. 设置回调函数enhancer.setCallback(this);//4. 创建子类对象,即代理对象return enhancer.create();}//重写 intercept 方法,会调用目标对象的方法@Overridepublic Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable {// TODO Auto-generated method stubSystem.out.println("Cglib代理模式 ~~ 开始");Object returnVal = method.invoke(target, args);System.out.println("Cglib代理模式 ~~ 提交");return returnVal;}}
客户端测试
public class Client {public static void main(String[] args) {// TODO Auto-generated method stub//创建目标对象TeacherDao target = new TeacherDao();//获取到代理对象,并且将目标对象传递给代理对象TeacherDao proxyInstance = (TeacherDao)new ProxyFactory(target).getProxyInstance();//执行代理对象的方法,触发intecept 方法,从而实现 对目标对象的调用String res = proxyInstance.teach();System.out.println("res=" + res);}}
CGLib和JDK动态代理的区别:
- JDK动态代理是实现了被代理对象的接口,CGLib是继承了被代理对象。
- JDK和CGLib都是在运行期生成字节码,JDK是直接写Class字节码,CGLib使用ASM框架写Class字节码,CGLib代理实现更复杂,生成代理类比JDK效率低。
- JDK调用代理方法,是通过反射机制调用,CGLib是通过FastClass机制直接调用方法,CGLib执行效率更高。
五、几种变体

