JDK动态代理的简单使用

动态代理在java中很常用,比如aop就是通过动态代理实现的。通常我们有JDK和CGLIB两种方式,这次我们先来看看JDK动态代理的实现。

这里简单说一下为什么我们通常都不使用静态代理,因为静态代理的类需要实现接口的所有方法,很显然在方法很多的时候我们会非常累。而动态代理是jvm在运行的时候动态帮我们生成的,不需要实现接口中所有的方法。

首先我们要知道,JDK的动态代理只能代理接口,所以必须先定义一个接口。

public interface IAnimal {
    void say();
}

之后我们用Cat来实现这个接口。

public class Cat implements IAnimal {
    @Override
    public void say() {
        System.out.println("喵");
    }
}

现在,我们想使用代理对Cat进行增强。

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

public class AnimalHandler implements InvocationHandler {

    private IAnimal target;

    public AnimalHandler(IAnimal target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("有动物开始叫.");
        Object obj = method.invoke(target, args);
        System.out.println("动物叫声停止.");
        return obj;
    }
}

从代码可以看到,我们实现了InvocationHandler的invoke方法,在invoke中对代理类进行了增强。这里就是写业务代码中需要被增强的内容。

那么我们怎么得到这个代理类呢?这里由于可能还会有其他的动物,比如Dog,所以我们使用简单工厂来创建Animal。

import java.lang.reflect.Proxy;

public class AnimalFactory {
    public static IAnimal getAnimal(String name) {
        IAnimal animal = null;
        if ("dog".equals(name)) {
            animal = new Dog();
        } else if ("cat".equals(name)) {
            animal = new Cat();
        }
        AnimalHandler handler = new AnimalHandler(animal);
        IAnimal proxy = (IAnimal) Proxy.newProxyInstance(animal.getClass().getClassLoader(), animal.getClass().getInterfaces(), handler);
        return proxy;
    }
}

使用Proxy.newProxyInstance()方法来创建代理。

创建动物就很简单了。

public class ProxyMain {
    public static void main(String[] args) {
        IAnimal cat = AnimalFactory.getAnimal("cat");
        cat.say();
    }
}

想一想,这里的IAnimal cat = AnimalFactory.getAnimal("cat");可不可以写成Cat cat = AnimalFactory.getAnimal("cat");呢?当然是不能的,因为刚才说了,JDK的动态代理只能代理接口,如果需要代理类,那么可以使用cglib。

那么问题又来了,在开发中,我们的Cat、Dog通常都会继承Animal,比如:

public abstract class Animal implements IAnimal {
}

public class Dog extends Animal {
    @Override
    public void say() {
        System.out.println("旺");
    }
}

这个时候如果我们代理Dog,那么就会报错:

Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to IAnimal

因为Dog中没有实现接口,这里我们在Proxy.newProxyInstance()的时候,通过父类获取接口即可。

IAnimal proxy = (IAnimal) Proxy.newProxyInstance(animal.getClass().getClassLoader(), animal.getClass().getSuperclass().getInterfaces(), handler);

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据