likes
comments
collection
share

代码生活处处是代理--静态代理+动态代理的实现

作者站长头像
站长
· 阅读数 15

你买房了吗?你买车了吗?你买啥啥啥了吗?现在这个社会除了物理物质我们离不开,还有一种角色也在潜移默化中渗透我们的生活。---中介

代理模式的思想是为了提供额外的处理或者不同的操作而在实际对象与调用者之间插入一个代理对象。这些额外的操作通常需要与实际对象进行通信。

接下来我们看看如何通过java来实现代理功能。

jdk动态代理

  • jdk动态代理是Java提供的一种方式,最大的特点是保留了静态代理的风格。jdk动态代理只能代理接口。这也是他和cglib的区别,也是他的缺点。jdk动态代理通过Proxy进行创建代理对象的。通过java.lang.reflect.InvocationHandler接口控制方法代理拦截的。

  • 接口类


public interface Developer {

    /**
     * 编码
     */
    void code();

    /**
     * 解决问题
     */
    void debug();
}

  • 真实类

public class JavaDeveloper implements Developer {
    @Override
    public void code() {
        System.out.println("java code");
    }

    @Override
    public void debug() {
        System.out.println("java debug");
    }
}

  • 代理类

public class JavaDynamicProxy {
    public static void main(String[] args) {
        JavaDeveloper jDeveloper = new JavaDeveloper();
        Developer developer = (Developer) Proxy.newProxyInstance(jDeveloper.getClass().getClassLoader(), jDeveloper.getClass().getInterfaces(), (proxy, method, params) -> {
            if (method.getName().equals("code")) {
                System.out.println("我是一个特殊的人,code之前先分析问题");
                return method.invoke(jDeveloper, params);
            }
            if (method.getName().equals("debug")) {
                System.out.println("我没有bug");

            }
            return null;
        });
        developer.code();
        developer.debug();
    }
}

  • 效果

代码生活处处是代理--静态代理+动态代理的实现

  • 解析

  • 首先定义一个接口包含code、bug方法。

  • 然后我们定义一个实现类是Java程序员的工作,对应的功能是java code 、 java bug

  • 然后我们不需要提供代理类,这里通过Proxy进行创建代理对象。但是我们需要一个方法拦截器。这个拦截器在Proxy.newProxyInstance方法中传入。这个方法有三个参数:

    • classLoader : 类加载器(通过接口获取)
    • interface : 接口
    • 拦截器 : 需要我们继承InvocationHandler , 上述代码直接通过lombad表达式书写的。
  • 我们可以看到在拦截器里我们就可以控制方法转发前后的节点了。

cglib动态代理

  • 有了jdk动态代理我们开发代理就很方便了。这个时候还有一个问题。我们平时开发中不可能每个类都有继承接口的。这个时候我们的普通类如果想实现代理改如何实现呢。我们看看spring中aop的类也是没有实现接口的。这个是如何实现的呢。下面我们用cglib告诉你

  • 接口


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

    final public String sayHello(String name) {
        System.out.println("HelloService:sayOthers>>"+name);
        return null;
    }

    public void sayHello() {
        System.out.println("HelloService:sayHello");
    }
}

  • 拦截器

public class MyMethodInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("======插入前置通知======");
        Object object = methodProxy.invokeSuper(o, objects);
        System.out.println("======插入后者通知======");
        return object;
    }
}

  • Test

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

  • cglib可以代理任何类。这是他的优点。他的创键也很简单。通过Enhancer将类与拦截器进行关联,我们的拦截器是实现net.sf.cglib.proxy.MethodInterceptor的。在intercept方法中我们可以通过methodProxy.invokeSuper进行转发方法。在转发前我们可以进行节点的控制。
    • object : 表示增强的对象,具体的实现类

    • method : 表示被拦截的方法

    • args : 参数

    • methodProxy : 父类的方法对象。 这里值得注意的是我们要通过methodProxy.invokeSuper.如果换成method调用将会一直递归拦截造成内存溢出。

总结

代理类对于我们使用这来说是无感知的。因为他和委托类继承同一个接口,所以我们在调用的时候方法都是一样的。只不过在代理类内部会在转发到委托类之前和之后进行相应的处理。代理分为静态代理和动态代理。而动态代理我们常见的有jdk动态代理、cglib动态代理。