动态代理

Posted WWWYC

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态代理相关的知识,希望对你有一定的参考价值。

 

时间:2017-1-4 22:33

 

——动态代理(Proxy)概述

1、只学一个方法:
    Proxy proxy = newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 

2、方法的作用:
    在运行时动态创建一个实现了一组指定接口的对象。

3、参数:
    1)ClassLoader:类加载器
        它是用来加载类的,把.class文件加载到内存,生成Class对象。

    2)Class[] interfaces:Class数组
        指定要实现的接口们。

    3)InvocationHandler:
        代理对象的所有方法(个别方法不执行,例如getClass())都会调用InvocationHandler的invoke()方法。

4、动态代理的作用
    最终学习AOP(面向切面编程),它与装饰设计模式相似,但比装饰设计模式灵活。

示例代码:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
 
import org.junit.Test;
 
public class Demo {
    @Test
    public void fun(){
 
        /*
         * 三大参数
         * 1、ClassLoader
         * 该方法会动态生成一个类,这个类实现了A、B接口,然后创建这个类的对象
         * 需要生成一个类,这个类也需要通过ClassLoader加载到方法区中
         * 
         * 2、Class[] interfaces
         * 它是要实现的接口们
         * 
         * 3、InvocationHandler
         * 它是调用处理器
         * 
         * 代理对象实现的所有接口中的方法内容都是调用InvocationHandler的invoke()方法
         */
        ClassLoader loader = this.getClass().getClassLoader();

 
        InvocationHandler h = new InvocationHandler(){
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("Hello Proxy");
                return null;
            }
        };
 
        //使用三大参数创建代理对象
        Object o = Proxy.newProxyInstance(loader, new Class[]{A.class, B.class}, h);
 
        A a = (A)o;
        B b = (B)o;
 
        a.a();
        b.b();
    }
}
 
interface A{
    public Object a(String s, int i);
    public Object aa(String s, int i); 
}
 
interface B{
    public void b();
}

打印结果:
Hello Proxy
Hello Proxy
 




——InvocationHandler接口

1、只有一个方法:
    public Object invoke(Object proxy, Method method, Object[] args);
    在调用代理对象所实现接口中的方法时被调用。

    *   Object proxy:当前对象,即代理对象。
    *   Method method:当前被调用的方法(目标方法)。
    *   Object[] args:实参。

2、invoke()方法与代理对象调用方法的关系
    技术分享


——动态代理应用

增强的方式:
    1、继承
        *   被增强对象不能变
        *   增强内容不能变
    2、装饰设计模式
        *   被增强对象可变
        *   增强内容不可变
    3、动态代理
        *   被增强对象可变
        *   增强内容可变

目标对象:被增强的对象。
代理对象:需要目标对象,然后在目标对象上添加了增强后的对象。
目标方法:被增强的内容。

代理对象 = 目标对象 + 增强内容

=============================================================================
示例代码:

package com.wyc.demo2;
 
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
 
import org.junit.Test;
 
public class Demo2 {
    @Test
    public void fun1() {
        // 目标对象
        Waiter manWaiter = new ManWaiter();
        /*
         * 给出三个参数,来创建方法,得到代理对象
         */
        ClassLoader loader = this.getClass().getClassLoader();
        Class[] interfaces = { Waiter.class };
 
        // manWaiter表示目标对象
        InvocationHandler h = new WaiterInvocationHandler(manWaiter);
 
        // 得到代理对象,其实代理对象就是在目标对象的基础上进行增强的对象
        Waiter waiterProxy = (Waiter)Proxy.newProxyInstance(loader, interfaces, h);
 
        /*
         * 在服务方法前添加“你好”,在服务方法后添加“再见”
         */
        waiterProxy.serve();
    }
}
 
class WaiterInvocationHandler implements InvocationHandler {
    // 目标对象
    private Waiter waiter;
    public WaiterInvocationHandler(Waiter waiter){
        this.waiter = waiter;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("您好");
        // 调用目标对象的目标方法
        this.waiter.serve();
        System.out.println("再见");
        return null;
    }
}

----------------------------------------------------------------------------------------------------------------------------

package com.wyc.demo2;
 
public interface Waiter {
    // 服务方法
    public void serve();
}

----------------------------------------------------------------------------------------------------------------------------

package com.wyc.demo2;
 
public class ManWaiter implements Waiter {
    @Override
    public void serve() {
        System.out.println("服务中...");
    }
}
============================================================================= 
 

——代理工厂实现

============================================================================= 


ProxyFactory:

package com.wyc.demo3;
 
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
 
/*
 * 代理工厂
 * 它用来(组装)生成代理对象
 * 所需参数:
 *  * 目标对象
 *  * 增强内容
 */
 
/*
 * 1、创建代理工厂
 * 2、给工厂设置三个属性:
 *  * 目标对象:setTargetObject(xxx);
 *  * 前置增强对象:setBeforeAdvice(该接口的实现类)
 *  * 后置增强对象:setAfterAdvice(该接口的实现类)
 *  
 * 3、调用createProxy()方法得到代理对象
 *  * 执行代理对象方法时,首先执行的是BeforeAdvice的before()方法
 *  * 目标对象的目标方法
 *  * 最后会执行AfterAdvice的after()方法
 */
public class ProxyFactory {
    // 目标对象
    private Object targetObject;
 
    // 前置增强对象
    private BeforeAdvice beforeAdvice;
 
    // 后置增强对象
    private AfterAdvice afterAdvice;
 
    /*
     * 用来生成代理对象
     */
    public Object createProxy(){
        /*
         * 1、给出三大参数
         */
        ClassLoader loader = this.getClass().getClassLoader();
        // 得到该对象的真实类型,获取该类型实现的所有接口
        Class[] interfaces = targetObject.getClass().getInterfaces();
        InvocationHandler h = new InvocationHandler(){
 
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                /*
                 * 在调用代理对象的方法时,会调用该方法,执行这里的内容
                 */
                // 执行前置增强
                if(beforeAdvice != null){
                    beforeAdvice.before();
                }
 
                // 通过反射得到的Method类,调用目标对象的目标方法
                Object result = method.invoke(targetObject, args);
 
                // 执行后置增强
                if(afterAdvice != null){
                    afterAdvice.after();
                }
 
                // 返回目标对象的返回值
                return result;
            }
        };
 
        /*
         * 2、得到代理对象
         */
        Object proxyObject = Proxy.newProxyInstance(loader, interfaces, h);
        return proxyObject;
    }
 
    public Object getTargetObject() {
        return targetObject;
    }
 
    public void setTargetObject(Object targetObject) {
        this.targetObject = targetObject;
    }
 
    public BeforeAdvice getBeforeAdvice() {
        return beforeAdvice;
    }
 
    public void setBeforeAdvice(BeforeAdvice beforeAdvice) {
        this.beforeAdvice = beforeAdvice;
    }
 
    public AfterAdvice getAfterAdvice() {
        return afterAdvice;
    }
 
    public void setAfterAdvice(AfterAdvice afterAdvice) {
        this.afterAdvice = afterAdvice;
    }
}
----------------------------------------------------------------------------------------------------------------------------

测试:

package com.wyc.demo3;
 
import org.junit.Test;
 
/*
 * 让目标对象和增强内容都可以切换
 * 不决定增强对象和增强内容,只起到了装配作用
 */
public class Demo3 {
    @Test
    public void fun() {
        // 创建工厂
        ProxyFactory factory = new ProxyFactory();
 
        // 设置目标对象
        factory.setTargetObject(new ManWaiter());
 
        // 设置前置增强对象
        factory.setBeforeAdvice(new BeforeAdvice() {
 
            @Override
            public void before() {
                System.out.println("您好");
            }
        });
 
        // 设置后置增强对象
        factory.setAfterAdvice(new AfterAdvice() {
 
            @Override
            public void after() {
                System.out.println("再见");
            }
        });
 
        Waiter waiter = (Waiter) factory.createProxy();
        waiter.serve();
        waiter.money();
    }
}
----------------------------------------------------------------------------------------------------------------------------

Waiter接口:

package com.wyc.demo3;
 
public interface Waiter {
    // 服务方法
    public void serve();
 
    // 增加方法
    public void money();
}
----------------------------------------------------------------------------------------------------------------------------

ManWaiter接口:

package com.wyc.demo3;
 
public class ManWaiter implements Waiter {
 
    @Override
    public void serve() {
        System.out.println("服务中...");
    }
 
    @Override
    public void money() {
        System.out.println("收钱...");
    }
}

----------------------------------------------------------------------------------------------------------------------------

BeforeAdvice接口:

package com.wyc.demo3;
 
/*
 * 前置增强
 */
public interface BeforeAdvice {
    public void before();
}

----------------------------------------------------------------------------------------------------------------------------
 

AfterAdvice接口:

package com.wyc.demo3;
 
/*
 * 后置增强
 */
public interface AfterAdvice {
    public void after();
}






































































































以上是关于动态代理的主要内容,如果未能解决你的问题,请参考以下文章

动态代理模式——JDK动态代理

动态代理

设计模式 结构型模式 -- 代理模式(动态代理(JDK动态代理(JDK动态代理要求必须定义接口,对接口进行代理。)动态代理原理(使用arthas-boot.jar查看代理类的结构)动态代理的作用)(代

动态代理——JDK中的动态代理

Spring 静态代理+JDK动态代理和CGLIB动态代理

(java反射-JDK动态代理)+CGLIB动态代理