目录
1.概述
2. 静态代理模式
2.1基于接口的静态代理
2.2基于继承的静态代理
2.3优缺点
3.动态代理模式
3.1JDK 动态代理
3.2 CGlib 动态代理
3.3优缺点
- 代理模式指: 为一个对象提供一个替身,以控制对这个对象的访问。既通过代理对象访问目标对象,这样做的好处是: 可以在目标对象实现的基础上,增加额外的功能操作,即扩展目标对象的功能。
- 代理模式分为: 静态代理模式和动态代理模式(JDK 和CGLIB)。
- 概述: 静态代理由开发者对抽象主题编写相关代理类实现,编译之后生成代理类的class.
- 使用: 静态代理在使用时,需要定义接口或者父类, 目标对象与代理对象一起实现接口或者继承共同的父类。
- 实例: 以外卖骑手为例,骑手代理顾客执行购买,等待,取餐的操作
- Foodie 品尝接口(抽象主题)
/*** 美食家---> 抽象主题: 静态代理*/
public interface Foodie {/*** 品尝美食*/void eat();
}
- RealFoodie 真实品尝类(真实主题)
/*** 真实美食家---> 真实主题: 静态代理*/
public class RealFoodie implements Foodie{@Overridepublic void eat() {System.out.println("开始品尝美食....");}
}
- ProxyFactory 代理工厂
/*** 重写Foodie接口的方法*/@Overridepublic void eat() {//增加扩展功能System.out.println("开始购买...");System.out.println("开始等待...");System.out.println("开始配送");//调用目标对象方法foodie.eat();}
- Test 测试类
public class Test {public static void main(String[] args) {//1.静态代理---> 基于接口RealFoodie realFoodie=new RealFoodie();//填入目标对象Foodie foodie=new ProxyFactory(realFoodie);foodie.eat();}
}
- 输出结果
开始购买....
开始等待....
开始配送....
开始品尝....
总结 : 以上代码可以看出: ProxyFactory代理工厂替目标对象扩展了骑手配送的功能。目标对象没有作任何更改,因此目标对象和扩展功能互不影响,职责分明。
注意 : 目标对象和代理工厂都要实现抽象主题, 这是基于接口的一种方式。
- 使用场景: 在代理工厂不想实现接口去扩展功能时,就可以使用继承的方式(即继承和真实主题共有的父类或直接继承真实主题)。
- Foodie 抽象主题(和上面一样没做任何改动)
- RealFoodie 真实主题(和上面一样没做任何改动)
- ProxyFactory 代理工厂
/*** 代理工厂直接继承真实主题--->即目标对象*/
public class ProxyFactory extends RealFoodie{/*** 重写父类的方法*/@Overridepublic void eat() {//扩展功能System.out.println("开始购买....");System.out.println("开始等待....");System.out.println("开始配送....");//调用父类(即目标对象)的方法super.eat();}
}
优点:
- 可以在不修改目标对象的前提下,能通过代理对象对目标功能进行扩展。
- 目标对象和代理的扩展功能职责清晰不会产生耦合。
缺点:
- 因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类。
- 一旦接口增加方法,目标对象与代理对象都要维护。
- 概述: 动态代理是在运行时动态生成的,通过反射动态生成代理类字节码。
- 分类: 动态代理模式可分为JDK动态代理(基于接口),CGlib(继承方式)。
- 实现:目标对象实现抽象接口,代理方法逻辑类实现InvocationHandler调用处理器接口。
- Foodie 抽象主题
/*** 美食家--->抽象主题: JDK动态代理*/
public interface Foodie{void eat();
}
- RealFoodie 真实主题
/*** 真实主题---> JDK动态代理*/
public class RealFoodie implements Foodie{/*** 品尝美食*/@Overridepublic void eat() {System.out.println("开始品尝....");}
}
- MethodInvocationHandler 方法逻辑调用处理类
该类用于处理代理方法逻辑及或利用反射创建代理对象:
/*** 实现代理方法逻辑类----> JDK 动态代理*/
public class MethodInvocationHandler implements InvocationHandler {//定义未知目标对象private Object target;public MethodInvocationHandler(Object target) {this.target = target;}/** 创建代理工厂**/public Object getInstance(){/*** ClassLoader loader, 目标对象的类加载器* Class>[] interfaces, 目标对象所实现的所有接口* InvocationHandler h 代理的方法逻辑自动调用重写的invoke*/return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new MethodInvocationHandler(target));}/** 处理代理的方法逻辑*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//扩展新功能System.out.println("开始购买...");System.out.println("开始等待...");System.out.println("开始送餐...");//调用目标对象的方法Object invoke = method.invoke(target, args);return invoke;}
}
- Test测试类
public class Test {public static void main(String[] args) {//创建真实主题RealFoodie realFoodie=new RealFoodie();//创建代理方法逻辑MethodInvocationHandler methodInvocationHandler=new MethodInvocationHandler(realFoodie);//创建代理对象--->填入目标对象Foodie foodie= (Foodie) new MethodInvocationHandler(realFoodie).getInstance();foodie.eat();}
}
- 前置操作: 引入CGlib的jar包。
- 使用场景:目标对象不想实现接口时,CGlib使用继承来实现。
- 实现: 代理方法拦截类实现MethodInterceptor 即方法拦截接口。
- MethodInterceptor 代理方法拦截类
该类用于创建代理对象并处理代理方法逻辑(对目标对象方法进行拦截) :
/*** 代理方法拦截类---> CGlib动态代理*/
public class MethodInterceptor implements net.sf.cglib.proxy.MethodInterceptor {//目标对象private Object target;public MethodInterceptor(Object target) {this.target = target;}/*** 创建代理对象*/public Object createInstance(){//1.设置工具类Enhancer enhancer=new Enhancer();//2.设置父类enhancer.setSuperclass(target.getClass());//3.设置回调函数enhancer.setCallback(this);//4.创建代理对象Object o = enhancer.create();return o;}/*** 写入拦截扩展代码* @param o 目标对象* @param method 所扩展目标对象的方法* @param objects 方法参数* @param methodProxy 代理对象* @return* @throws Throwable*/@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {//扩展功能System.out.println("开始购买...");System.out.println("开始等待...");System.out.println("开始送餐...");//调用父类指定方法(拦截目标对象的方法)Object invoke =methodProxy.invokeSuper(o,objects);return invoke;}
}
- RealFoodie 真实主题类
/*** 真实主题---->CGlib动态代理*/
public class RealFoodie {void eat(){System.out.println("开始品尝...");}
}
- Test测试类
public class Test {public static void main(String[] args) {//创建真实主题RealFoodie realFoodie = new RealFoodie();//创建代理方法拦截器并创建代理对象RealFoodie realFoodie1 = (RealFoodie) new MethodInterceptor(realFoodie).createInstance();realFoodie1.eat();}
}
优点:
- 如扩展功能类似时,代理工厂类对象是未知的,就可以使用一个代理对象完成扩展功能,使用时指定不同目标对象即可。
- 代理工厂无需实现抽象接口的方法,因为是利用反射在运行时创建的代理对象。
缺点:
- CGlib : 通过继承的方式进行代理,无法处理被final修饰类的情况。
- JDK: 只能基于接口处理。