java 动态代理实现

最近在写Java服务器,一边学一边做,所以很多基础的不是很清楚,遇到了拦截器都说本质是动态代理。所以好好的看了下。
java的代理用我的理解就是:为了在接口的方法执行之前或之后添加一些相关操作所以绕个圈用反射获取方法再执行,这么做更多的是考虑代码的可拓展性和解耦合。
jdk的动态代理是基于实现接口完成的,所以我们首先要定义接口,这里我们定义两个接口:

public interface DrinkService {
    /**
     * 普通的接口,用于代理
     * */
 public String drinkFood(String food);
}

public interface EatService {
    /**
     * 接口用于动态代理测试
     * */
    public String eatFood(String food);
}

这个两个接口中分别有一个方法,然后要有一个类来实现这些接口,在实际的业务中这个类创建的对象就是用来处理实际业务的,也是被代理对象。我们会采用反射来在代理中调用这个对象的方法,注意这个方法是实现自接口的方法。

/**
 * 被代理的类,jdk的动态代理只能代理接口
 * */
public class DrinkAndEat implements EatService,DrinkService{
    /**
     * 实现接口EatService
     * */
    @Override
    public String eatFood(String food) {
        System.out.println("吃"+food);
        return "吃"+food;
    }
    /**
     * 实现接口DrinkService
     * */
    @Override
    public String drinkFood(String food) {
        System.out.println("喝"+food);
        return "喝"+food;
    }
}

好了到了这里我的前置准备已经完成了,正常的业务也都是这么做的,现在我们需要给这个类设置也给动态代理,所以我们要定义一个类,这个类实现InvocationHandler接口,并且和要被代理的类绑定,如果绑定很简单:在这个类中写个属性,属性类型就是这个类。
在这个类中要实现接口的方法:

 public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable

在这个方法中我们会通过反射机制调用被代理类的方法,同样的java 服务器中的拦截也是在这个方法中实现的,看具体代码:

/**
 * 触发器,动态代理是通过这个触发器调用具体的业务实现方法的
 * */
public class InvocationHandlerImpl implements InvocationHandler{
    /**
     * 被代理的对象,即实现具体业务的对象
     * */
    private DrinkAndEat de;

    public void setDe(DrinkAndEat de) {
        this.de = de;
    }

    /**
     * 代理通过这个方法调用具体的业务实现
     * */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
        //可在此进行方法调用之前的拦截
        System.out.println("方法执行之前拦截");
        Object test = method.invoke(de,args[0]);
        System.out.println("方法执行之后拦截");
        return test;
    }

}

要注意的是:Object test = method.invoke(de,args[0]);
中invoke方法的返回值,就是被代理类中方法的返回值,在Object invoke(Object proxy, Method method, Object[] args) throws Throwable这个方法中我们要将前面的返回值test返回,只有这样我们才可以在外面代理中获取被代理类的方法的返回值的。
下面我们就进行测试:
首先我们要创建代理:

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

在这个方法中我们需要三个参数,一个是被代理类的加载器这样获取:

DrinkAndEat de = new DrinkAndEat();
        ClassLoader loader = de.getClass().getClassLoader();

一个是被代理类中的接口方法:

Class[] interfaces = de.getClass().getInterfaces();

最后一个参数就是我们刚刚创建的实现了InvocationHandler接口的类:

InvocationHandlerImpl handler = new InvocationHandlerImpl();
        handler.setDe(de);

然后我们创建代理:

Object test = Proxy.newProxyInstance(loader, interfaces, handler);

代理创建出来后要进行类型转换,我们将这个代理类型强转成接口类型,再调用方法:

DrinkService drink = (DrinkService) test;
        EatService eat = (EatService)test;
        String drinkString = drink.drinkFood("水");
        String eatString = eat.eatFood("米饭");

这是测试的完整代码:

DrinkAndEat de = new DrinkAndEat();
        ClassLoader loader = de.getClass().getClassLoader();
        Class[] interfaces = de.getClass().getInterfaces();
        InvocationHandlerImpl handler = new InvocationHandlerImpl();
        handler.setDe(de);
        Object test = Proxy.newProxyInstance(loader, interfaces, handler);
        DrinkService drink = (DrinkService) test;
        EatService eat = (EatService)test;
        String drinkString = drink.drinkFood("水");
        String eatString = eat.eatFood("米饭");
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章