代理设计模式

静态代理:

先画一个静态代理的类图。
在这里插入图片描述从上图我们可以看出,静态代理主要有3个部分实现。
首先,需要一个接口,这个接口拥有一个代理类与被代理类的共有的一个方法。然后需要一个被代理类,实现定义的接口。再定义一个代理类,实现接口并且依赖被代理的对象。这样一个静态代理的过程就实现了。当客户端调用的时候,调用的就是代理类的实例,调用的方法就是被代理类实例增强后的被代理类的方法。

SellCar接口:

public interface SellCar {//代理类与被代理类共同实现的接口
    void sellCar();
}

CarFactory被代理类:

public class CarFactory implements SellCar{
    @Override
    public void sellCar() {
        System.out.println("汽车生产商:组装车辆,并出售...");
    }
}

ProxyStore代理类:

public class ProxyStore implements SellCar{
    private CarFactory carFactory;//依赖一个被代理类的对象
    public ProxyStore(CarFactory carFactory){
        this.carFactory = carFactory;
    }
    @Override
    public void sellCar() {//对被代理类的方法进行增强
        System.out.println("代理商:向汽车工厂购买车辆...");
        carFactory.sellCar();
        System.out.println("代理商:代理销售汽车...");
    }
}

Custom客户端:

public class Custom {
    public static void main(String[] args) {
        ProxyStore proxyStore = new ProxyStore(new CarFactory());
        proxyStore.sellCar();
    }
}

动态代理:

通过上面的静态代理,虽然我们实现了对被代理类功能的增强,但是我们也可以很清晰的发现一个问题。所有的方法都已经写死在程序中了,当我们需要去增加或去修改方法时,对于程序的改动就会很大,这样就很容易出现问题。因此我们可以使用动态代理。动态代理分为2种:JDK代理和CGLIB代理。

JDK代理:

JDK的实现原理:
在JDK代理中,不需要代理类再去实现与被代理对象共有的接口方法。代理类依赖于JDK提供的Proxy类,使用该类中的newProxyInstance方法通过反射可以得到一个代理类的实例对象。代理类还需要实现InvocationHandler接口总的invoke方法,通过反射得到被代理对象的方法的具体信息对象,然后在invoke方法中对其进行增强。
JDK的实现:
在这里插入图片描述

SellCar接口:

public interface SellCar {//代理类与被代理类共同实现的接口
    void sellCar();
}

CarFactory被代理类:

public class CarFactory implements SellCar{
    @Override
    public void sellCar() {
        System.out.println("制造商:制造车辆...");
        System.out.println("制造商:出售车辆...");
    }
}
}

ProxyStore代理类:

public class ProxyStore {
    private CarFactory carFactory;
    public ProxyStore(CarFactory carFactory){
        this.carFactory = carFactory;
    }

    /**
     * @return 代理类的实例对象
     */
    public Object getProxyInstance(){
        /**
         * arg1:被代理类的类加载器,获取被代理类的具体信息
         * arg2:获取被代理类的所有接口
         * arg3:匿名内部类实现了InvocationHandler接口,返回的是被代理的方法执行后的返回值
         */
       return Proxy.newProxyInstance(carFactory.getClass().getClassLoader(), carFactory.getClass().getInterfaces(),
               new InvocationHandler() {
                   @Override
                   /**
                    * arg1:生成的被代理类的代理类的实例对象
                    * arg2:代理类的实例对象执行的方法,是对被代理类目标方法的增强
                    * arg3:代理类的实例对象执行的方法的参数列表
                    */
                   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                       System.out.println("代理商:向制造商购买汽车...");
                       Object invoke = method.invoke(carFactory, args);
                       System.out.println("代理商:代理出售...");
                       return invoke;
                   }
               });
    }
}

Custom客户端:

public class Custom {
    public static void main(String[] args) {
        ProxyStore proxyStore = new ProxyStore(new CarFactory());
        SellCar proxy = (SellCar) proxyStore.getProxyInstance();//自动生成代理类的对象,实现了SellCar接口
        proxy.sellCar();
    }
}

CGLIB代理

通过上述的JDK代理实现的描述,我们不难发现。JDK代理是自动生成一个类实现了与代理目标类共同的接口,如果没有目标类的接口类,就不能够使用JDK代理。为了解决这种问题,提出了CGLIB代理。
CGLIB代理原理:
生成的代理类是被代理类的子类覆盖了父类的方法。通过多态的性质,当子类覆盖了父类的方法时,创建子类对象强转为父类对象后,调用父类对象的方法时优先调用子类覆盖父类的方法,实现对于目标方法的增强。
CGLIB代理的实现:
要实现CGLIB我们先需要导入CGLIB的jar包(这里使用IDEA直接导入依赖)
在这里插入图片描述

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

ProxyStore生成代理类:

public class ProxyStore implements MethodInterceptor {
    Enhancer enhancer = new Enhancer();
    /**
     * @param clazz 被代理类的字节码文件
     * @return 获取被代理类的一个代理对象
     */
    public Object getProxyInstance(Class clazz){
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }
    /**
     * @param o 自动生成的被代理类的代理类的实例对象
     * @param method 被代理类执行的方法
     * @param objects 参数列表
     * @param methodProxy 代理类执行的方法对象
     * @return 被代理类的方法执行后的返回值
     * @throws Throwable
     */
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("代理商:向汽车厂商购买车辆...");
        Object invokeSuper = methodProxy.invokeSuper(o, objects);
        System.out.println("代理商:代理出售...");
        return invokeSuper;
    }
}

CarFactory被代理类:

public class CarFactory{
    public void sellCar() {
        System.out.println("制造商:制造车辆...");
        System.out.println("制造商:出售车辆...");
    }
}

Custom客户端:

public class Custom {
    public static void main(String[] args) {
        ProxyStore proxyStore = new ProxyStore();
        CarFactory proxy = (CarFactory) proxyStore.getProxyInstance(CarFactory.class);
        proxy.sellCar();
    }
}

CGLIB代理与JDK代理的区别:

JDK代理: 生成的代理类是实现了被代理类的接口。因此没有接口的被代理类不能使用JDK代理。
CGLIB代理: 生成的代理类继承了被代理类,是被代理类的子类。因此,被代理类不能被final修饰,需要被增强的方法也不能够被final修饰。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值