反射实现动态代理

代理模式

代理模式的定义:为其他对象提供一种代理以控制这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用应一个对象,需要实现相同的接口,而代理对象可以在客户端和目标对象之间起到中介的作用。


就好比销售。代理商是受别人的委托,帮助委托人销售指定的商品。而这件商品原本是委托人,而不是代理商的,代理商可以把商品说的天花乱坠,但商品原本是不变的,这就类似于“拓展”。

Java中的开闭原则:对拓展是开放的,修改是封闭的,不得修改源代码。当我们对一个类进行拓展时,这时就需要使用代理模式了,将拓展的代码写在代理类中。

静态代理

静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类,在程序运行前就编译好的。以膨胀空间来节省时间!

package Demo;

//接口
interface IShow {
    void show();
}
//用户类  被代理类
class User implements IShow{

    @Override
    public void show() {
        System.out.println("520秀一下!");
    }
}
//代理类
class Agency implements IShow{
    private User user;

    //被代理类作为参数传入
    public Agency(User user) {
        this.user = user;
    }

    @Override
    public void show() {
        System.out.println("****拓展代码****");
        user.show();
        System.out.println("****拓展代码****");
    }
}
public class Test {
    public static void main(String[] args) {
        User user=new User();
        Agency agency=new Agency(user);
        agency.show();
    }
}

结果:

****拓展代码****
520秀一下!

****拓展代码****

代理类和委托类需要实现同一个接口,并重写相应的方法。然后在代理类的构造方法中以委托类对象作为参数传入。在代理类重写的方法通过传入的委托类对象调用委托类的方法,并加上拓展的一些代码,就实现了代理。

动态代理

1. 代理对象 , 不需要实现接口
2.
代理对象的生成 , 是利用 JDK API, 动态的在内存中构建代理对象 ( 需要我们指定创建代理对象 / 目标对象实现的接口的类型 )
3.
动态代理也叫做 :JDK 代理 , 接口代理

JDK中生成代理对象的API
代理类所在包:java.lang.reflect.Proxy
JDK
实现代理只需要使用newProxyInstance方法,但是该方法需要接收三个参数,完整的写法是:

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

注意该方法是在Proxy类中是静态方法,且接收的三个参数依次为:

·        ClassLoader loader,:指定当前目标对象使用类加载器,获取加载器的方法是固定的

·        Class<?>[]interfaces,:目标对象实现的接口的类型,使用泛型方式确认类型

·        InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入

package Demo;

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

interface IShow{
    void show();
}
class User implements IShow{

    @Override
    public void show() {
        System.out.println("520秀一下!");
    }
}

/**
 * 方法一
 * 代理类 将newProxyInstance写在代理类中
 */
class Dynamic_Proxy{
    private User user;

    public Dynamic_Proxy(User user) {
        this.user = user;
    }
    public Object getProxy(){//       获得代理类的类加载器
       return Proxy.newProxyInstance(Dynamic_Proxy.class.getClassLoader(),
                user.getClass().getInterfaces(),//得到委托类实现的接口
                new InvocationHandler() {//将代理类与委托类建立联系
                    @Override//         委托类对象       方法           方法的参数
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("****拓展代码****");
                        Object invoke = method.invoke(user, args);//调用委托类中的方法
                        System.out.println("****拓展代码****\n");
                        return invoke;
                    }
                });
    }
}

/**
 * 方法二
 * 代理类 实现InvocationHandler接口
 */
class DynamicProxy implements InvocationHandler{
    private User user;

    public DynamicProxy(User user) {
        this.user = user;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("****拓展代码****");
        //反射  调用方法             对象   参数
        Object invoke = method.invoke(user, args);
        System.out.println("****拓展代码****");
        return null;
    }
}

public class Test {
    public static void main(String[] args) {
        //方法一
        User user=new User();
        Dynamic_Proxy proxy=new Dynamic_Proxy(user);
        IShow instance =(IShow) proxy.getProxy();
        instance.show();

        //方法二
        User us=new User();
         // 得到InvocationHandler对象
         // 因为DynamicProxy实现了得到InvocationHandler对象 并重写了invoke方法
        InvocationHandler handler = new DynamicProxy(us);
        // 返回的是接口类型                                        代理类的类加载器
        IShow proxyInstance =(IShow) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
                us.getClass().getInterfaces(),//委托类实现的接口
                handler);//将代理类与委托类建立联系

        proxyInstance.show();

    }
}

方法一和方法二的原理是类似的,一个无非是是在内部重写InvocationHandler接口实现Involve方法;另一个则将newProxyInstance方法写在外面,传入指定的参数。它们的结果是一样的。多次用到反射的知识点,通过反射调用方法,得到类的接口,类的加载器等,包括导的包都是基于Reflect下面的。

总结:

使用代理的好处:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.  这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法。

静态代理,以膨胀空间来节省时间(类在运行前就已经全被加载);动态代理,以膨胀时间来节省空间(使用反射,动态加载,需要用到的时候就加载)。

动态加载使用的会比较多,比如说:三大框架中的Spring框架的底层,使用过动态代理,用于解耦和,提高开发效率。在后面的框架中动态代理无处不在。

       

       每日鸡汤:要按照你想的去生活,否则,你迟早会按照你生活的去想。

Over!






猜你喜欢

转载自blog.csdn.net/chianz632/article/details/80411414