静态代理与JDK动态代理

静态代理与JDK动态代理

目录

1.静态代理

1.1.创建Service

1.2.创建对象的实现类

1.3.创建代理类

1.4.测试类

1.5.测试结果

2.JDK动态代理

2.1.创建一个Service

2.2.创建实现类

2.3.验证Method

2.4.实现InvocationHandler

2.5.Proxy代理对象的创建

2.6.验证结果

1.静态代理

静态代理就是已知的代理类,对其进行代理。

首先创建普通的项目

1.1.创建Service

//创建Pen服务类
//这里指代的是买钢笔的服务类
public interface PenService {
    public float sellPen(int num);
}

1.2.创建对象的实现类

package edu.wan.service.serviceImpl;
import edu.wan.service.PenService;

//晨光铅笔的供应商,不为个人提供钢笔的买卖信息,直接为代理提供
public class CgPenServiceImpl implements PenService {
    @Override
    public float sellPen(int num) {
        return 5.0f;
    }
}

 

package edu.wan.service.serviceImpl;
import edu.wan.service.PenService;

//英雄钢笔的服务类
//这个服务也不对外进行开放,只能通过代理的形式才能进行购买
public class HeroPenServiceImpl implements PenService {
    @Override
    public float sellPen(int num) {
        return 25.0f;
    }
}

1.3.创建代理类

package edu.wan.service.agentImpl;

import edu.wan.service.PenService;
import edu.wan.service.serviceImpl.CgPenServiceImpl;
import edu.wan.service.serviceImpl.HeroPenServiceImpl;

//中间的代理商,用户可以从这里进行购物
//个人理解,这个代理的本质就是我是没有Pen的实物的,我只是代理其他公司的东西,
// 但是我通过代理可以增加我的实现逻辑
public class TaobaoPenService implements PenService {
    private CgPenServiceImpl cgPenServiceImpl = new CgPenServiceImpl();
    private HeroPenServiceImpl heroPenServiceImpl = new HeroPenServiceImpl();

    //该方法是静态代理的方法,首先我们还是代用、具体实现的方法
    // 具体实现方法就是 cgPenServiceImpl.sellPen 、  heroPenServiceImpl.sellPen
    // 而代理做的就是从具体实现的方法之后,进行行为的增强
    // ps:加收额为的费用,增加运费等功能的增强
    @Override
    public float sellPen(int num) {
        Float aFloat = cgPenServiceImpl.sellPen(1);
        aFloat += aFloat +2.0f;
        System.out.println("如果购买晨光的钢笔总共花费:"+aFloat+"而且我们是面运费的!");

        Float aFloat1 = heroPenServiceImpl.sellPen(1);
        aFloat1 += aFloat1 +1.5f;
        System.out.println("如果购买晨光的钢笔总共花费:"+aFloat1 +"但是还需要加收0.5的运费!");
        return aFloat+aFloat1;
    }
}

1.4.测试类

package edu.wan.service;
import edu.wan.service.agentImpl.TaobaoPenService;

public class Test {
    public static void main(String[] args) {
        TaobaoPenService taobaoPenService = new TaobaoPenService();
        Float aFloat = taobaoPenService.sellPen(1);
        System.out.println("购买钢笔总共花费: "+aFloat);
    }
}

1.5.测试结果

2.JDK动态代理

想要了解JDK的动态代理,需要了解Method 、InvocationHandler 、Proxy

验证需要创建一个普通项目。

2.1.创建一个Service

package edu.wan.jdk.service;

public interface PenService {
    public float sellPen(int num);
}

2.2.创建实现类

package edu.wan.jdk.serviceImpl;
import edu.wan.jdk.service.PenService;

//晨光铅笔的供应商,不为个人提供钢笔的买卖信息,直接为代理提供
public class CgPenServiceImpl implements PenService {
    @Override
    public float sellPen(int num) {
        return 5.0f;
    }
}

 

package edu.wan.jdk.serviceImpl;
import edu.wan.jdk.service.PenService;

//英雄钢笔的服务类
//这个服务也不对外进行开放,只能通过代理的形式才能进行购买
public class HeroPenServiceImpl implements PenService {
    @Override
    public float sellPen(int num) {
        return 25.0f;
    }
}

2.3.验证Method

    // Method 方法
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        PenService penService = new  HeroPenServiceImpl();
        PenService penService2 = new CgPenServiceImpl();
        // 获取方法,通过方法的名字和方法的参数列表
        // 委托模式支持penService2的调用,代理模式就不支持penService2的调用
//      Method method = PenService.class.getMethod("sellPen", int.class);//委托模式
        Method method = penService.getClass().getMethod("sellPen", int.class);//代理模式
        /** method.invoke 参数讲解:  public Object invoke(Object obj, Object... args)
            1) Object obj :指的是要被代理的对象
            2) Object... args:指的是代用method方法所需要的参数 因为参数是未知的所以用 ...表示
          */
        //动态的调用HeroPenServiceImpl的sellpen的方法
        //本质上method只是对应的sellPen方法的对象,需要传入代理的类,用于实现代理类的sellPen的实现
        Float aFloat = (float) method.invoke(penService2, 1);
        System.out.println("购买一支英雄钢笔的价格:"+aFloat);
    }

在这里出现一个问题,在我使用代理模式的时候,我会用(float) method.invoke(penService2, 1)进行动态代理的时候会抛出一个问题。

问题如下:

经过源码查看:

public Object invoke(Object obj, Object... args)
    throws IllegalAccessException, IllegalArgumentException,
       InvocationTargetException
{
    if (!override) {
        if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
            Class<?> caller = Reflection.getCallerClass();
            checkAccess(caller, clazz, obj, modifiers);
        }
    }
    MethodAccessor ma = methodAccessor;             // read volatile
    if (ma == null) {
        ma = acquireMethodAccessor();
    }
    return ma.invoke(obj, args);
}

远程在验证完之后判断是否有MethodAccessor,如果没有的话就调用acquireMethodAccessor

在acquireMethodAccessor类中有三个方法分别是:

acquireMethodAccessor()
setMethodAccessor()
copy()

Method实例对象维护了一个root引用,当调用Method.copy()进行方法拷贝时,root指向了被拷贝的对象。

Method被多次拷贝后,调用一次setMethodAccessor()方法,就会将root引用所指向的Method的methodAccessor变量同样赋值。

ps:a-> b -> c -> d 
当c对象调用setMethodAccessor,b和a也会传播赋值methodAccessor,但是d的methodAccessor还是null
当d调用setMethodAccessor,d就会和abc一样。

所以这样就导致了使用代理模式的时候,调用method.invoke(penService2, 1)报错,

但是我使用委托模式的时候,就没有问题。

注:这块是我自己的理解和网上的参考,如有不对的地方,请帮忙指出,感谢!!!!

2.4.实现InvocationHandler

package edu.wan.jdk.Handle;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

//必须实现InvocationHandler接口,该实现类实现了两个功能
// 1.调用了目标的方法
// 2.功能增强
public class MyInvocationHandle implements InvocationHandler {

    private Object targer = null;

    //targer指代是要被代理的对象
    public MyInvocationHandle(Object targer){
        this.targer = targer;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object invoke = method.invoke(targer, args); // 执行代理类的目标方法
        // 以下属于功能增强的方法
        System.out.println("我的地盘听我的");
        System.out.println("调用过来了来 撒花.........");
        return invoke;
    }
}

2.5.Proxy代理对象的创建

//public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h)
//newProxyInstance 主要的作用就是不用使用new 就可以创建对象,
// 创建了接口的代理对象
/**
 loader :类加载器
 interfaces:接口
 h: 自己定义的 Handler 实现功能的曾想
 */
public static void main(String[] args) {
    PenService penService = new  HeroPenServiceImpl();
    PenService penService2 = new CgPenServiceImpl();
    InvocationHandler myInvocationHandle = new MyInvocationHandle(penService2);
    PenService penService1 = (PenService) Proxy.newProxyInstance(penService.getClass().getClassLoader(),
            penService.getClass().getInterfaces(), myInvocationHandle);
    System.out.println(penService1.sellPen(1));

2.6.验证结果

源码地址:https://gitee.com/Wanbogo/csdnblogs.git 中的agent文件夹。

动态代理在mybatis、Spring中都有所应用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值