简介:
什么是动态代理
动态代理是一种在运行时创建代理对象的机制,它允许在不修改目标对象代码的情况下,对
目标对象的方法进行增强或拦截。
静态代理与动态代理的对比
静态代理:
-
在编译时就已经确定了代理类和被代理类的关系,需要为每个被代理的类手动创建一个代理类。
-
当被代理的类较多或者接口方法发生变化时,需要编写大量的代理类代码,维护成本较高。
动态代理:
- 代理类是在运行时动态生成的,无需手动编写代理类代码。
- 需要指定接口和处理器,就可以在运行时创建代理对象,更加灵活和方便。
动态代理的实现方式
Java 反射机制实现动态代理
在 Java 中,主要有两种基于反射机制实现动态代理的方式:JDK 动态代理和 CGLIB 动态代理。
JDK 动态代理
- 原理 :JDK 动态代理是基于接口的代理方式,它通过
java.lang.reflect.Proxy
类和java.lang.reflect.InvocationHandler
接口来实现。Proxy
类用于创建代理对象,InvocationHandler
接口用于定义代理对象。
jdk动态代理代码实现:
首先创建一个接口:
javascript
public interface Service{
void add();
void delete();
void update();
void query();
}
创建一个目标对象实现这个接口:
java
public class ServiceImpl implements Service{
@Override
public void add() {
System.out.println("add...");
}
@Override
public void delete() {
System.out.println("delete...");
}
@Override
public void update() {
System.out.println("update...");
}
@Override
public void query() {
System.out.println("query...");
}
}
开始写测试代码
java
public class Client {
public static void main(String[] args) {
//创建目标对象
OrderService target = new OrderServiceImpl();
//创建代理对象
Proxy.newProxyInstance(参数1,参数2,参数3)
}
}
Proxy.newProxyInstance()参数介绍
注:代理对象底层是jdk自动创建的
参数一:ClassLoader 类加载器(经类加载器运行的类才能在虚拟机上运行),jdk要求
代理对象类加载器必须和目标对象一致,所以要传target.getClass().getClassLoader()
参数二:要传一个接口,就是目标对象实现的接口,所以传target.getClass.getInterfaces()
参数三:InvocationHandle调用处理器,是一个接口,你要对源程序的增强就写在该接口的实
现类里。
因为第三个参数的特殊性,所以我们现在要自己写一个实现类作为第三个参数。
InvocationHandle实现类
java
public class InvocationHandleImpl implements InvoCationHandle{
private Object target;
public InvocationHandleImpl(Object target){
this.target = target;
}
/**
*参数1:传进来一个代理对象,不常用
*参数2:传入需要调用目标对象的方法
*参数3:传入目标方法上的实参
*/
@Override
public Object invoke( Object Proxy,Method method,Object[] args){
//这个接口的目的是为了写增强代码
long begin = System.currentTimeMillis();
//调用方法
method.invoke(target,args)
long end = System.currentTimeMillis();
System.out.println((end-begin)+"ms");
//注意这个invoke方法的反回值,如果代理对象调用代理方法之后,需要返回结果的话,invoke方
法必须将目标方法执行结果继续返回
return invoke;
}
}
传参执行代理:
java
public class Client {
public static void main(String[] args) {
//创建目标对象
Service target = new ServiceImpl();
//创建代理对象
Service ServiceProxy = (Service)Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandleImp(target));
//调用方法
ServicePoxy.add();
ServicePoxy.delete();
ServicePoxy.update();
ServicePoxy.query();
}
}
优缺点:
优点:
1.面向接口编程
2.自动编写代理类,无需手动编写,代码简洁
3.动态性强,继承方便
缺点:
1.只能代理实现接口的类
2.性能开销打
3.维护和调试难度大