代理模式-jdk动态代理

IDB 

package com.bjpowernode.proxy;

/**
 * 代理类和目标类都必须使用同一个接口。 
 */
public interface IDB {
    
    int insert();
    int delete();
    int update();
}

OracleDB 

package com.bjpowernode.proxy;

/**
 * 这是一个Oracle数据库相关的操作类
 * 
 * 目标类(委托类)。
 */
public class OracleDB implements IDB{
    public int insert(){
        
        //以下是一个插入操作
        System.out.println("Oracle insert data....");
        try {
            Thread.sleep(526);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 0;
    }
    
    
    public int delete(){
        
        //以下是一个删除操作
        System.out.println("Oracle delete data....");
        try {
            Thread.sleep(569);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        return 0;
    }
    
    
    public int update(){
        
        //以下是一个更新操作
        System.out.println("Oracle update data....");
        try {
            Thread.sleep(456);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        return 0;
    }
    
}

TimeInvocationHandler 

package com.bjpowernode.proxy;

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

/**
 * 注册在这个接口中的代码,在代理对象调用代理方法的时候,自动执行。
 * 我们的扩展代码就注册在这个类中。
 */
public class TimeInvocationHandler implements InvocationHandler {

    //这个程序运行期,obj引用中保存了内存地址指向的对象是一个目标对象。
    private Object obj;
    
    public TimeInvocationHandler(Object obj){
        this.obj = obj;
    }
    
    /**
     * proxy 是代理对象的引用。
     * method 是目标类中的目标方法
     * args 是目标类中的目标方法的实参
     */
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        
        long begin = System.currentTimeMillis();
        
        //通过反射机制去调用目标类中的目标方法
        Object retValue = method.invoke(obj, args);
        
        long end = System.currentTimeMillis();
        System.out.println("方法执行所耗费" + (end-begin) + "毫秒");
        
        return retValue;
    }

}

Test 

package com.bjpowernode.proxy;

import java.lang.reflect.Proxy;

public class Test {

    public static void main(String[] args) {
        
        //创建目标类对象
        IDB db = new OracleDB();
        
        //创建代理对象
        //DBProxy dbProxy = new DBProxy(); //这是静态代理模式中创建对象,因为DBProxy是我们程序员手动编写的。
        
        //创建代理对象(这次创建代理对象是交给JVM完成,包括在这个过程中,JVM也会自动生成“代理类的字节码”)
        //这个代理类是动态生成的字节码不会以.class文件的形式保存在硬盘上,所以我们称作动态代理。
        
        //第一个参数是类装载器:JVM会在内存中自动生成一个字节码,但是这个字节码要想运行,必须经过类装载器的装载
        //然后进一步解析,所以必须传递一个类装载器,这个类装载器就是用来装载这个临时的“字节码”。
        //代理类和目标类必须使用同一个类装载器。
        
        //第二个参数:是JVM在生成代理类的时候需要实现接口,但是这个接口又不能随便写,因为代理类和目标类要求实现相同的接口。
        //所以我们将目标类实现的接口获取到之后传递过来就行了。
        //JDK中提供的代理模式只能代理接口。如果目标类它的父类型不是一个接口而是一个抽象类,那么JDK中提供的动态代理就不能用了,需要使用
        //第三方组件,例如:cglib。
        
        //第三个参数:是InvocationHandler,这是一个接口,这个接口中的方法会在代理类调用代理方法的时候自动执行。
        IDB dbProxy = (IDB)Proxy.newProxyInstance(db.getClass().getClassLoader(), db.getClass().getInterfaces(), new TimeInvocationHandler(db));
        
        
        //通过代理对象中的方法去执行目标对象中的方法。
        dbProxy.insert(); //dbProxy是一个动态生成的代理对象,由于这个代理对象实现了和OracleDB一样的接口,所以可以用IDB接口指向JVM中的代理对象。
        dbProxy.delete(); // 这里调用的delete方法是是代理类中的代理方法,不是目标类中的目标方法。但是一定会通过代理方法去调用目标方法。
        dbProxy.update();
        
    }

}

 

  

posted @ 2020-02-27 00:34  Ayan_ayan  阅读(236)  评论(0编辑  收藏  举报