代理模式介绍
代理模式提供了对目标对象额外的访问方式, 即通过代理对象访问目标对象, 这样可以在不修改原目标对象的前提下, 提供额外的功能操作, 扩展目标对象的功能.
代理模式分为三类:
静态代理
动态代理
Cglib 代理
静态代理 (不推荐)
介绍
要求目标对象和代理对象实现同一个接口, 调用的时候调用代理对象的方法, 从而达到增强的效果
优点:
可以在不修改目标对象的前提下, 增强目标对象方法的功能 (所有代理模式都可以实现, 因此不推荐使用此方法)
缺点:
1 冗余. 目标对象和代理对象实现同一个接口, 会产生过多的代理类.
2 不易维护. 当接口方法增加, 目标对象与代理对象都要进行修改.
代码实现
场景: 厂家生产了商品, 但是没有足够的精力, 人力去销售, 这时候就需要一个代理商帮他售卖, 但是代理商需要从中抽取 20% 的利润.
公共接口
- public interface IProducer {
- void sale(float money);
- }
被代理对象
- public class Producer implements IProducer {
- @Override
- public void sale(float money) {
- System.out.println("卖出产品, 厂家获得" + money + "元");
- }
- }
代理对象
- public class ProxyProducer implements IProducer{
- private IProducer producer;
- public ProxyProducer(IProducer producer) {
- this.producer = producer;
- }
- @Override
- public void sale(float money) {
- producer.sale(money * 0.8f);
- }
- }
测试类
- public class Client {
- @Test
- public void test(){
- IProducer producer = new Producer();
- ProxyProducer proxyProducer = new ProxyProducer(producer);
- proxyProducer.sale(1000f);
- }
- }
运行结果
卖出产品, 厂家获得 800.0 元
动态代理
介绍
动态代理也称: JDK 代理, 接口代理, 需要目标对象实现接口, 否则不能用动态代理, 利用 JDK 的 API(java.lang.reflect.Proxy), 动态地在内存中构建代理对象.
静态代理和动态代理的区别:
静态代理在编译时就已经实现, 编译完后的代理类是一个实际的 class 文件
动态代理实在运行时动态生成的, 编译后没有实际的 class 文件, 而是在运行时动态的生成类字节码, 并加载到 JVM 中
代码实现
以静态代理的情景为例, 我们只需要修改代理对象的代码, 代理对象不需要实现公共接口了.
- public class ProxyProducer {
- /**
- * 维护一个目标对象
- */
- private Object target;
- public ProxyProducer(Object target) {
- this.target = target;
- }
- public Object getProxyInstance() {
- return Proxy.newProxyInstance(
- target.getClass().getClassLoader(),
- target.getClass().getInterfaces(),
- new InvocationHandler() {
- /**
- * 执行被代理对象的任何接口方法都会经过这里
- * @param proxy 代理对象的引用
- * @param method 当前执行的方法
- * @param args 当前执行方法的参数
- * @return 和被代理对象具有相同的返回值
- * @throws Throwable
- */
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- // 代理过程中执行一些方法
- float money = (float) args[0] * 0.8f;
- // 反射机制调用目标对象的方法
- Object invoke = method.invoke(target, money);
- return invoke;
- }
- });
- }
- }
Cglib 代理
介绍
Cglib 代理也叫子类代理, 目标对象不需要实现任何接口, 它是在内存中构建一个子类对象从而实现对目标对象功能的扩展.
Cglib 是一个强大的高性能的代码生成包, 它可以在运行期间扩展 Java 类与实现 Java 接口, 它广泛地被许多 AOP 的框架使用, 例如 Spring AOP, 用于实现方法拦截.
Cglib 包底层实通过使用字节码处理框架 ASM 来转换字节码并生成新的类.
在 AOP 编程中选择哪种代理模式?
目标对象需要实现接口, 用 JDK 代理
目标对象不需要实现接口, 用 Cglib 代理
代码实现
使用之前需要导入相关 jar 包, 可去 maven 仓库下载
被代理对象, 无需实现接口
- public class Producer {
- public void sale(float money) {
- System.out.println("卖出产品, 厂家获得" + money + "元");
- }
- }
代理对象
- public class ProxyProducer implements MethodInterceptor {
- /**
- * 维护一个目标对象
- */
- private Object target;
- public ProxyProducer(Object target) {
- this.target = target;
- }
- /**
- * 为目标对象生成代理对象
- */
- public Object getProxyInstance(){
- // 创建一个工具类
- Enhancer enhancer = new Enhancer();
- // 设置父类
- enhancer.setSuperclass(target.getClass());
- // 设置回调函数
- enhancer.setCallback(this);
- // 创建子类对象 (代理对象)
- return enhancer.create();
- }
- /**
- * 会拦截被代理对象的所有方法
- * @param obj 增强对象
- * @param method 被代理对象的方法
- * @param args 被代理对象方法的参数
- * @param methodProxy 代理对象
- */
- @Override
- public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
- System.out.println("obj:" + obj.getClass());
- Object returnValue = null;
- float money = (float) args[0] * 0.8f;
- if("sale".equals(method.getName())){
- returnValue = method.invoke(target, money);
- }
- return returnValue;
- }
- }
测试类
- public class Client {
- @Test
- public void test() {
- Producer producer = new Producer();
- Producer proxyInstance = (Producer) new ProxyProducer(producer).getProxyInstance();
- proxyInstance.sale(1000f);
- }
- }
来源: https://www.cnblogs.com/songjilong/p/12713689.html