[Java]代理

代理

Java中有一个经典的设计模式叫做代理模式(Proxy),在我们平时开发和框架源码中无处不在。

在这里插入图片描述
这里可以看到,代理模式并没有改变对象A,而是换了一种方式访问对象A的方法,通过代理对象ProxyA来访问对象A,这样做的好处是——在A的基础上拓展,实现它的额外附加功能。

静态代理

创建一个接口ICar,里面有一个run方法,然后定义宝马的实现类来实现它:
在这里插入图片描述

public interface ICar {
    void run();
}

public class BmwCar implements ICar {
    @Override
    public void run() {
        System.out.println("宝马车跑起来了。");
    }
}

因为汽车需要启动才能跑,跑完以后需要熄火,毕竟油价挺贵的。新建一个CarProxy类:

/**
* 静态代理,与目标对象实现相同的接口或继承相同的父类
**/

public class CarProxy implements ICar {

    /**
     * 目标对象
     */
    private ICar target;

    public CarProxy(ICar target) {
        this.target = target;
    }

    @Override
    public void run() {
        System.out.println("汽车启动。。。");
        target.run();
        System.out.println("汽车熄火。。。");
    }
}

测试一下:

public class CarApp {
    public static void main(String[] args) {
        CarProxy carProxy = new CarProxy(new BmwCar());
        carProxy.run();
    }
}

运行结果如下图所示:
在这里插入图片描述
静态代理虽然在学习中经常会看到,但是在框架和实际编码中却不经常使用:
1.优点: 不修改目标对象的代码, 完成了目标对象的扩展。
2.缺点: 代理对象会随着目标对象的修改需要相应的修改。比如在ICar中加了接口,代理也需要做相应代码的修改。

静态代理的缺点过于明显了,有没有什么办法规避呢?
有,动态代理。

动态代理

JDK动态代理

代理类Proxy所在包:java.lang.reflect。核心方法是:

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

调用调用该方法即可对目标对象生成对应的代理对象。
这里需要传入三个参数:

  • ClassLoader loader: 目标对象使用的类加载器,target.getClass().getClassLoader()
  • Class<?>[] interfaces: 目标对象实现接口类型,使用泛型方式类型,target.getClass().getInterfaces()
  • InvocationHandler h: 当执行目标对象的方法时,会先调用InvocationHandlerinvoke方法,
    同时把当前执行目标对象的方法作为参数传入。

ICarPro:

public interface ICarPro {
    /**
     * 汽车加油
     */
    void refueling();

    /**
     * 汽车运行
     */
    void run();
}

BenzProCar:

public class BenzProCar implements ICarPro {
    @Override
    public void refueling() {
        System.out.println("给我的大奔加油!");
    }

    @Override
    public void run() {
        System.out.println("大奔跑起来了。");
    }
}

CarProFactory:

public class CarProFactory {

    private ICarPro target;

    public CarProFactory(ICarPro target) {
        this.target = target;
    }

    //对目标对象包装成代理对象
    public Object genProxyBean() {
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("--操作前");
                        Object returnValue = method.invoke(target, args);
                        System.out.println("--操作后");
                        return returnValue;  //返回已经扩展后的代理对象
                    }
                }
        );
    }
}

测试运行:

public class CarApp {
    public static void main(String[] args) {
        CarProFactory carProFactory = new CarProFactory(new BenzProCar());
        ICarPro benz = (ICarPro)carProFactory.genProxyBean();
        benz.refueling();
        benz.run();
    }
}

运行结果:
在这里插入图片描述
JDK动态代理对象生成的类:

// $proxy0代理对象已经继承了jdk的Proxy, 所以JDK动态代理只能以实现ICarPro接口的方式完成
public class $proxy0 extends Proxy implements ICarPro

Cglib动态代理

无论是静态代理还是JDK动态代理,其本质是目标对象一定要实现一个接口。有时候我们写业务代码就是一个类,没有实现接口,这时候可以使用Cglib动态代理。
pom文件依赖引入:

<dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
        </dependency>

建立CGLIB动态工厂类CarProxyFactoryByCglib

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

import java.lang.reflect.Method;

public class CarProxyFactoryByCglib implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println(method.getName()+"方法调用...");
        Object obj = methodProxy.invokeSuper(o, objects);
        System.out.println(method.getName()+"方法调用结束...");
        return obj;
    }
}

测试:

public class CarApp {
    public static void main(String[] args) {
        CarProxyFactoryByCglib cglibProxy = new CarProxyFactoryByCglib();
        Enhancer enhancer = new Enhancer();
        // 设置父类
        enhancer.setSuperclass(BenzProCar.class);
        // 设置回调对象
        enhancer.setCallback(cglibProxy);
        BenzProCar proxy = (BenzProCar) enhancer.create();
        proxy.refueling();
        System.out.println("1.加油完成");
        proxy.run();
        System.out.println("2.运行完成");
    }
}

运行结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值