Java基础-动态代理

1、什么是代理

生活中的代理

1、房产中介,租户不能直接对接房主,要通过中介。中介就是代理,同时中介提供价格调整、房屋维修等增强功能。
2、商家店铺,用户不能直接去厂家买东西,要通过商家。商家就是代理,同时商家提供商品价格调整、举办优惠活动等增强功能。

由上面的例子可以看出,代理和目标都实现了同一种功能,只不过代理在原功能的基础上进行了功能增强。(中介和房主都提供房屋出租的功能,中介只不过是在原功能的基础上进行了价格调整、房屋装修等额外功能)

2、代理的特点

  1. 功能增强(在原功能的基础上封装其他功能)
  2. 访问控制(某些情况下,不允许用户直接访问目标地址,必须通过中间代理)

3、静态代理

一个代理类就专门处理一个目标类,代码简单,但是不具备通用性。

package proxy.staticproxy;

/**
 * 售卖主方法
 *
 * @author zhao.hualuo
 * Create at 2022/4/28
 */
public class ShopMain {

    public static void main(String[] args) {
        KingStaticProxyImpl proxy = new KingStaticProxyImpl();
        System.out.println("买10个");
        System.out.println(proxy.sell(10));

        System.out.println();
        System.out.println("买110个");
        System.out.println(proxy.sell(110));
    }
}
package proxy.staticproxy;

/**
 * U盘售卖接口
 *
 * @author zhao.hualuo
 * Create at 2022/4/28
 */
public interface UsbSellService {

    /**
     * 销售
     *
     * @param amount 数量
     * @return 金额
     */
    double sell(int amount);
}
package proxy.staticproxy;

/**
 * 金士顿厂家
 *
 * @author zhao.hualuo
 * Create at 2022/4/28
 */
public class KingFactoryImpl implements UsbSellService {

    @Override
    public double sell(int amount) {
        //厂家,一个U盘卖50
        return 50 * amount;
    }
}
package proxy.staticproxy;

/**
 * 金士顿静态代理
 *
 * @author zhao.hualuo
 * Create at 2022/4/28
 */
public class KingStaticProxyImpl implements UsbSellService {

    /** 厂家的实例 */
    UsbSellService service = new KingFactoryImpl();

    @Override
    public double sell(int amount) {
        //若一次购买超过100个,赠送10元优惠券一张
        if (amount > 100) {
            System.out.println("赠送10元优惠券一张");
        }
        //在原有价格基础上,加价10%
        return service.sell(amount) * 1.1;
    }
}

4、动态代理

1、动态代理是指代理类对象在程序运行时由JVM根据反射机制动态生成的。动态代理不需要定义代理类的java源文件。
2、动态代理其实就是:在jdk运行期间动态创建class字节码并加载到JVM。
3、动态代理的实现方式常用的有两种:jdk动态代理、cglib动态代理

jdk动态代理和cglib动态代理(保证代理类和目标类有同名方法
1、jdk动态代理是基于接口的方式,即代理类和目标类都实现同一个接口。
2、cglib动态代理是代理类继承目标类,然后重写其中目标类的方法。

4.1 jdk动态代理

1、使用java反射包中的类和接口实现动态代理的功能,会使用到反射包java.lang.reflect里面的3个类:InvocationHandler、Method、Proxy
2、jdk动态代理需要实现类通过接口定义业务方法,所以必须有接口。

  • InvocationHandler接口

1、需要创建一个类,实现InvocationHandler接口,再重写invoke方法。
2、InvocationHandler接口中只有一个方法invoke(),代理对象的增强代码需要写在这个方法中。(实现原来静态代理类中的功能)

  • Method类

method.invoke()就是执行目标类中的方法的。method.invoke(目标对象, 方法参数)

  • Proxy类

创建代理对象,不再使用new方法创建代理对象,而是使用Proxy类的方法。

还是使用上面的例子展示一下jdk动态代理:

package proxy.dynamicproxy;

import java.lang.reflect.Proxy;

/**
 * 售卖主方法
 *
 * @author zhao.hualuo
 * Create at 2022/4/28
 */
public class ShopMain {

    public static void main(String[] args) {
        //创建目标对象
        KingFactoryImpl target = new KingFactoryImpl();

        //创建InvocationHandler对象
        MyInvocationHandler handler = new MyInvocationHandler(target);

        //使用Proxy创建代理
        UsbSellService sellService = (UsbSellService)Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                handler);

        //通过代理执行方法,会调用handler中的invoke方法
        System.out.println("买10个");
        System.out.println(sellService.sell(10));

        System.out.println();
        System.out.println("买110个");
        System.out.println(sellService.sell(110));
    }
}
package proxy.dynamicproxy;

/**
 * U盘售卖接口
 *
 * @author zhao.hualuo
 * Create at 2022/4/28
 */
public interface UsbSellService {

    /**
     * 销售
     *
     * @param amount 数量
     * @return 金额
     */
    double sell(int amount);
}
package proxy.dynamicproxy;

/**
 * 金士顿厂家
 *
 * @author zhao.hualuo
 * Create at 2022/4/28
 */
public class KingFactoryImpl implements UsbSellService {

    @Override
    public double sell(int amount) {
        //厂家,一个U盘卖50
        return 50 * amount;
    }
}
package proxy.dynamicproxy;

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

/**
 * 实现InvocationHandler接口,实现代理功能
 *
 * @author zhao.hualuo
 * Create at 2022/4/28
 */
public class MyInvocationHandler implements InvocationHandler {

    /** 目标对象 */
    private Object object;

    public MyInvocationHandler(Object object) {
        this.object = object;
    }

    /**
     * 通过代理对象执行方法时,会调用执行这个invoke方法
     *
     * @param proxy 代理类实例
     * @param method 被代理的方法
     * @param args 方法参数
     * @return 方法执行结果
     * @throws Throwable 异常
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("进入了MyInvocationHandler的invoke方法");
        System.out.println("method.getName():" + method.getName());
        Object res = method.invoke(object, args);
        if ((int)args[0] > 100) {
            System.out.println("赠送10元优惠券一张");
        }
        return res;
    }
}

4.2 cglib动态代理

1、cglib是第三方的工具库,创建代理对象
2、cglib的原理是继承,重写方法,所以要求目标类不能是final的、方法也不能是final的。
3、cglib的要求目标类比较宽松,只要能继承就可以。
4、cglib非jdk功能,需要额外导入java包。

cglib动态代理需要先引入cglib的包

implementation("cglib:cglib:3.3.0")

下面依然使用之前的U盘举例:

package proxy.cglib;

import net.sf.cglib.proxy.Enhancer;

/**
 * 售卖主方法
 * 
 * @author zhao.hualuo
 * Create at 2022/4/28
 */
public class ShopMain {

    public static void main(String[] args) {
        //创建Enhancer对象,类似于JDK动态代理中的Proxy
        Enhancer enhancer = new Enhancer();
        //设置目标类
        enhancer.setSuperclass(KingFactoryImpl.class);
        //设置回调函数
        enhancer.setCallback(new MyMethodInterceptor());
        //正式创建代理类
        KingFactoryImpl proxy = (KingFactoryImpl)enhancer.create();

        //通过代理执行方法,会调用proxy中的intercept方法
        System.out.println("买10个");
        System.out.println(proxy.sell(10));

        System.out.println();
        System.out.println("买110个");
        System.out.println(proxy.sell(110));
    }
}
package proxy.cglib;

/**
 * 金士顿厂家
 *
 * @author zhao.hualuo
 * Create at 2022/4/28
 */
public class KingFactoryImpl {

    public double sell(int amount) {
        //厂家,一个U盘卖50
        return 50 * amount;
    }
}
package proxy.cglib;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * 实现MethodInterceptor接口,实现代理功能
 *
 * @author zhao.hualuo
 * Create at 2022/4/28
 */
public class MyMethodInterceptor implements MethodInterceptor {

    /**
     * cglib拦截方法
     *
     * @param obj cglib生产的代理对象
     * @param method 被代理对象的方法
     * @param args 方法参数
     * @param proxy 代理方法
     * @return 返回值
     * @throws Throwable 异常
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        if ((int)args[0] > 100) {
            System.out.println("赠送10元优惠券一张");
        }
        Object object = proxy.invokeSuper(obj, args);
        return (double)object * 1.1;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值