代理模式-jdk动态代理

时间:2021-09-30 03:15:51

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(); } }