java设计模式之动态代理(通俗易懂)

今天重新看了下动态代理,也参考了一些网上的文章,自己总结一下动态代理的理解

动态代理离不开java反射机制,动态+代理。动态是指在在运行时生成的代理类,现在很多框架都是利用类似机制来提供灵活性的扩展性,比如用来包装 RPC 调用,面向切面编程(AOP)等。动态代理最大用处就是解耦,对所定义的一些接口做些增加的作用,像事物,统一日志等.

AOP 思想: 基于代理思想,对原来目标对象,创建代理对象,在不修改原对象代码情况下,通过代理对象,调用增强功能的代码,从而对原有业务方法进行增强 !

  • JDK 动态代理,被代理对象必须实现接口,利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理;
  • 字节码实现(比如说cglib/asm等),得用ASM开源包,将代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

现在举个简单的例子:比如有一个工厂,需要销售,销售的话会找到代理商去销售,这里我把商店定义为代理商,去做销售操作

我们循序渐进来讲,先说静态代理

定义一个工厂类

package com.vincent.JDK.DynamicProxyNew;

public interface Factory {

    
    public void sell(String produceName);


}

定义一个食品处理厂

package com.vincent.JDK.DynamicProxyNew;

public class FoodFactory implements  Factory{


    @Override
    public void sell(String produceName) {
        System.out.println("开始销售"+produceName+"咯");
    }
}

定义一个商店

package com.vincent.JDK.DynamicProxyNew;

public class Store implements  Factory {
    private  FoodFactory foodFactory;

    Store(FoodFactory foodFactory){
        this.foodFactory=foodFactory;
    }

    @Override
    public void sell(String produceName) {
        leaflet();
        this.foodFactory.sell(produceName);
    }

    public  void leaflet(){
        System.out.println("开始派发传单,今天新到的西瓜只要4元一斤");
    }

}

测试类

package com.vincent.JDK.DynamicProxyNew;

public class SimpleTest {
    public static void main(String[] args) {
        FoodFactory foodFactory=new FoodFactory();

        Store store=new Store(foodFactory);

        store.sell("西瓜");
        System.out.println("纳入税务局税收统计");
    }
}

运行后如图

开始派发传单,今天新到的西瓜只要4元一斤
开始销售西瓜咯
纳入税务局税收统计

因为每次销售后,都要打税,纳入税务局进行统计,所以我如果有N个商店是不是写调用N次打税接口,而且每个商店都有自己的行为,例如打广告,搞活动什么的,那每个商场都要写很多实现,岂不是爆炸了?所以我们现在需要写一个动态代理的操作,来简化这些操作,对于程序来说,代码实现就是强化的作用

我再编写一个handler类实现InvocationHandler接口,重写它的invoke方法

package com.vincent.JDK.DynamicProxyNew;

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

public class StoreProxy implements InvocationHandler {
    private  Object object;

    StoreProxy(Object object){
        this.object=object;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //参数:代理对象,接口
        //内部实现原理通过java反射机制找到具体类,然后带入参数,再执行
        //里面代码较为复杂,阅读能力强的同志可以自行查看
        System.out.println("税务员进驻商场");
        method.invoke(this.object,args);
        //代理代码增加操作
        System.out.println("纳入税务局税收统计");
        return null;
    }
}

编写一个动态代理测试类

package com.vincent.JDK.DynamicProxyNew;

import java.lang.reflect.Proxy;

public class ProxyTest {
    public static void main(String[] args) {
        FoodFactory foodFactory=new FoodFactory();

        StoreProxy store=new StoreProxy(foodFactory);
        //传入类读取器,实现类的接口,以及代理对象
        Factory factory=(Factory) Proxy.newProxyInstance(
                foodFactory.getClass().getClassLoader(), foodFactory.getClass().getInterfaces(), store);

        factory.sell("西瓜");
    }
}

测试结果如下

税务员进驻商场
开始销售西瓜咯
纳入税务局税收统计

这里顺便更新一下CGLIB动态代理的实现,也很简单,类似jdk动态代理,也是需要做一个对MethodInterceptor拦截器类进行继承重载的操作

package com.vincent.JDK.CGLIB;

public class HelloService{
        public HelloService() {
            System.out.println("HelloService构造");
        }

        /**
         * 该方法不能被子类覆盖,Cglib是无法代理final修饰的方法的
         */
        final public String sayOthers(String name) {
            System.out.println("HelloService:sayOthers>>"+name);
            return null;
        }

        public void sayHello() {
            System.out.println("HelloService:sayHello");
        }
}
package com.vincent.JDK.CGLIB;

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.invoke.MethodHandleInfo;
import java.lang.reflect.Method;

public class MyMethodInterceptor implements MethodInterceptor {
    //1)obj表示增强的对象,即实现这个接口类的一个对象;
    //
    //2)method表示要被拦截的方法;
    //
    //3)args表示要被拦截方法的参数;
    //
    //4)Proxy表示要触发父类的方法对象;
    @Override
    public Object intercept(Object obj, Method method, Object[] objects, MethodProxy Proxy) throws Throwable {
        System.out.println("======插入前置通知======");
        Object object = Proxy.invokeSuper(obj, objects);
        System.out.println("======插入后者通知======");
        return object;

    }
}
  public static void main(String[] args) {
        // 代理类class文件存入本地磁盘方便我们反编译查看源码
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\code");
        // 通过CGLIB动态代理获取代理对象的过程
        Enhancer enhancer = new Enhancer();
        // 设置enhancer对象的父类
        enhancer.setSuperclass(HelloService.class);
        // 设置enhancer的回调对象
        enhancer.setCallback(new MyMethodInterceptor());
        // 创建代理对象
        HelloService proxy= (HelloService)enhancer.create();
        // 通过代理对象调用目标方法
        proxy.sayHello();
    }

运行效果

CGLIB debugging enabled, writing to 'D:\code'
HelloService构造
======插入前置通知======
HelloService:sayHello
======插入后者通知======

可以在d盘的code下面找到那个新生成的动态代理类

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值