动态代理–Dnamic Proxy
一.代理对象是什么?
在理解动态代理之前,首先要了解下代理对象是什么,代理对象是可以代替被代理的对象执行它的业务逻辑,并且在被代理对象的业务逻辑的基础上任意增肌属于自己的业务逻辑。
二. 动态代理是什么?
动态代理是java.lang.reflect(反射)包中的一部分,它可以动态的创建任意接口的代理对象。要了解动态与静态的区别,首先要了解静态代理。
三. 静态代理
在JAVA中,静态代理有两种方法可以实现,继承和聚合。
1. 继承方式:代理类通过继承被代理的类的方式继承和重写业务逻辑。
package DynamicProxy.example;
//抽象了消费者购物逻辑相关的接口
public interface Shopping {
public void buy();
}
一个消费者类实现该接口。
package DynamicProxy.example;
public class Consumer implements Shopping{
//购买
@Override
public void buy() {
System.out.println("soochief buying a sennheiser's HD555");
}
}
现在要在消费者购物后打印购物的时间,于是代理类继承了消费者类,通过调用父类的方法执行了被代理对象的逻辑,并且在此的基础上添加了新的逻辑。
package DynamicProxy.example;
import java.util.Date;
//继承方式的代理
public class Consumer_Proxy1 extends Consumer{
public void buy() {
super.buy();
//购物后打印购物的时间
System.out.println(new Date());
}
}
可以看出继承的方式有一个重大的缺点,如果要在代理类的基础上继续添加新的逻辑,则要不停的创建新的类继承下去,这就造成了类的冗余。
2. 聚合方式:通过聚合被代理对象的方式来实现代理模式
还是使用消费者模型,在这里代理类不再继承而是把代理对象聚合了进来。
package DynamicProxy.example;
import java.util.Date;
//聚合方式代理,并且实现了消费者的购物逻辑接口
public class TimeHandler implements Shopping{
//聚合了被代理类
private Shopping s;
//通过构造方法初始化了代理类
public TimeHandler(Shopping s){
this.s = s;
}
@Override
public void buy() {
s.buy();
//购物后打印购物的时间
System.out.println(new Date());
}
}
执行代理
Consumer c = new Consumer(); TimeHandler t = new TimeHandler(c);
如果要在此基础上添加一个日志业务
LogHandler l = newe LogHandler(c);
可以看出聚合的方式其业务逻辑部分是可以自由的组合的,这相比继承方式更加的合理。但是如果现在又要代理另一个类,则又必须重新编写代码,依然没有解决代码的冗余。而JDK提供的动态代理类则解决了这个问题。
四.动态代理
在JDK的reflec包里提供了一个接口InvocationHandler,动态代理的业务逻辑部分在包含在实现这个接口的类中,并且这个类的内部将动态的生成代理类的代码。
package DynamicProxy.example;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Date;
//JDK的动态代理业务逻辑部分,这里大部分代码都是固定的,不需要自己编写
public class LogHandler implements InvocationHandler{
private Object target;
public LogHandler(Object target){
super();
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//通过反射调用方法
method.invoke(target, args);
//需要编写的逻辑代码
System.out.println(new Date()+":buy a sennheiser's HD555");
return null;
}
}
执行
Consumer u = new Consumer();
InvocationHandler log = new LogHandler(u);
/*
*第一个参数是类的加载器,用于把动态生成的代码写入内存,这样代码才能执行
*第二个参数是被代理对象的的CLASS信息,动态代码的类型与方法取决于这个参数
*第三个参数是InvocationHandler的实例
*/
Shopping s = (Shopping) Proxy.newProxyInstance(Shopping.class
.getClassLoader(), new Class[] { Shopping.class }, log);
使用动态代理,新的业务逻辑将可以作用于任意的类型对象,不再会产生冗余代码。它的内部是通过反射动态的生成代码,并加载过程。
浙公网安备 33010602011771号