说说代理--动态代理

动态代理:

我们都知道,接口是不能被new的,只有类才能被new的。

我们来看看Person接口,和实现了Person接口的Student类,到底有什么区别:

public class Test01 {
    public static void main(String[] args) {
        Class<Person> personClass = Person.class;
        Constructor<?>[] constructors = personClass.getConstructors();
        System.out.println("===Person接口的构造器===");
        for (Constructor c:
                constructors) {
            System.out.println(c);
        }
        System.out.println("===Person接口的方法===");
        Method[] methods = personClass.getMethods();
        for (Method m:
                methods) {
            System.out.println(m);
        }

        Class<Student> studentClass = Student.class;
        Constructor<?>[] constructors2 = studentClass.getConstructors();
        System.out.println("===实现Person接口的Student类的构造器===");
        for (Constructor c:
                constructors2) {
            System.out.println(c);
        }
        System.out.println("===实现Person接口的Student类的方法===");
        Method[] methods2 = studentClass.getMethods();
        for (Method m:
                methods2) {
            System.out.println(m);
        }

    }
}

  运行结果:

Person接口,没有构造器,所以Person不能被new。

Student类有构造器,所以可以被new。

接口中只有2个方法

实现类有2个方法和父类Object类的一些方法

 

也就是说除了构造器之外,接口跟实现类的结构差不多。

 

什么是动态代理:

通过上一篇我们介绍完静态代理(见上文:https://www.cnblogs.com/takeyblogs/p/14035553.html)的优缺点之后,我们来用动态代理来弥补静态代理的缺点。

 

 

 通过查看API,我们发现Proxy类有一个静态方法:

 

 

 

 Proxy.getProxyClass(ClassLoader loader,Class<?>... interfaces):我们传入一个接口的Class对象,就可以给我返回一个代理类。

上代码:

public class Test {
    public static void main(String[] args) {
        Class<?> proxyClass = Proxy.getProxyClass(Person.class.getClassLoader(), Person.class);
        System.out.println(proxyClass.getName());

        System.out.println("-----打印代理对象的构造器-----");
        Constructor<?>[] constructors = proxyClass.getConstructors();
        for (Constructor c:
                constructors) {
            System.out.println(c);
        }
        System.out.println("-----打印代理对象的方法-----");
        Method[] methods = proxyClass.getMethods();
        for (Method m:
                methods) {
            System.out.println(m);
        }
    }
}

  输出结果:

 

 

 通过Proxy.getProxyClass(),我们可以获得一个增强类,即包含了构造器,也包含了各种方法。与上文的对比,我们多了一个重要的构造器。

简单梳理一下:

1.我们一开始需要直接根据Person接口得到代理对象,但是我们发现了,接口没有构造器,没办法new出对象。

2.我们假象,能不能构造出一个类,即有构造器,又包含Person接口的方法。

3.我们发现java自带的Proxy类中有一个getProxyClass()方法,我们传入Person接口,它可以给我们返回一个带构造器又包含Person接口方法的Class对象。

 

 

 

那我们现在获取到了代理对象了。我们能不能生成代理实例呢?

 

 

 

public class Test {
    public static void main(String[] args) {
        try {
            Class<?> proxyClass = Proxy.getProxyClass(Person.class.getClassLoader(), Person.class);
            System.out.println(proxyClass.getName());

            Object o = proxyClass.newInstance();
            System.out.println(o);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

    }
}  

 

结果:

 

 

我们发现直接去实例化是会报错的,因为newInstance()调用的是类的无参构造器,但是我们再上面看到的是,代理类的构造器是有参数的:

 

 那我们就给他传入一个参数:

public class Test {
public static void main(String[] args) throws Exception{
Class<?> proxyClass = Proxy.getProxyClass(Person.class.getClassLoader(), Person.class);
Constructor<?> constructor = proxyClass.getConstructor(InvocationHandler.class);
//通过反射创建对象
Person PersonProxy = (Person)constructor.newInstance(new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
});

System.out.println(PersonProxy.dance(1,2));
}
}

  至此,我们就创建出来了一个代理对象了。

执行上面代码,结果:

 

 

发现报了空指针异常。

如果我们修改了invoke方法的返回值:

 

 我们会发现结果返回666。

那么我们不难猜到,结果跟返回值有关系:

 

 

 

我们知道,在实例化代理对象的时候,我们传入一个参数InvocationHandler,我们不难发现,代理对象中肯定有一个属性,来维护这个传入的对象,就像

静态代理一样,我们传入一个目标对象,然后代理对象有一个属性来维护这个目标对象。

 

 为什么要这么设计呢?

为了解耦,为了通用性。

JVM生成代理对象,只生成一个空壳的方法,把具体的逻辑留给InvocationHandler去实现。

 

API还有另一方法:

 

 

public class Test {
    public static void main(String[] args) throws  Exception{
        Student student = new Student();
        Person proxy = (Person)getProxy(student);
        proxy.sing();
        proxy.dance(2,3);
    }

    public static Object getProxy(final Object target) throws Exception{
        Object proxy = Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println(method.getName() + "方法开始执行");
                        Object invoke = method.invoke(target, args);
                        System.out.println(invoke);
                        System.out.println(method.getName() + "方法结束");
                        return invoke;
                    }
                }
        );
        return proxy;
    }
}

  执行结果:

 

posted @ 2020-11-27 09:41  Takey  阅读(145)  评论(0编辑  收藏  举报