一,代理设计模式
我们首先要了解代理的含义:代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。
简单点来说,是地区的经销商,也可以说是我们经常听到的中介。就比如说找中介租房子,中介负责一切事务,你只需要入住就可以了。如果委托A对象想访问一个目标C对象,就需要通过代理B对象去访问,代理B对象会进行一系列操作(确认,验证一下等)才会让委托A对象去访问目标C对象,也可以在委托A对象访问目标C对象之后进行一些代理操作。代理B对象可以实现在目标C对象代码不变的情况下,对访问前后进行一些操作。通俗来讲就是对目标C对象的访问控制。
二,静态代理
某个对象提供一个代理,代理角色固定,以控制对这个对象的访问。 代理类和委托类有共同的父类或父接口,这样在任何使用委托类对象的地方都可以用代理对象替代。代理类负责请求的预处理、过滤、将请求分派给委托类处理、以及委托类执行完请求后的后续处理。
代理接口:
//代理接口,处理给定的任务
public interface Subject{
//执行给定的名字的任务 takeName
public void dealTask(String taskName);
}
委托类,具体事务处理:
//实现代理接口,执行任务的类
public class RealSubiect implements Subject{
//执行名字的任务,打印出任务名,并休眠500ms模拟任务执行很长时间 taskName
@Override
public void dealTask(String taskName){
System.out.println("在执行任务:"+taskName);
try{
Thread.sleep(500);
}catch (InterruptedException e){
e.printStakTrace();
}
}
}
静态代理类:
// 代理类,实现代理类接口
public class ProxySubject implements Subject {
//代理类持有一个委托类的对象引用
private Subject delegate;
public ProxySubject(Subject delegate){
this.delegate = delegate;
}
//将请求分派给委托类执行,记录任务执行前后的时间,时间差为任务处理的时间 taskName
@Override
public void dealTask(String taskName){
long stime = System.currentTimeMillis();
//将请求分派给委托类处理
delegate.dealTask(taskName);
long ftime = System.currentTimeMillis();
System.out.println("执行任务所用时间"+(ftime -stime)+"毫秒");
}
}
生成静态代理类工厂:
public class SubjectStaticFactory {
//客户类调用此方法获得代理对象
//对客户来讲,不知道返回的是什么对象
public static Subject getInstance(){
return new ProxySubject(new RealSubject());
}
}
客户类:
public class Client {
public static void main(String[] args){
Subject proxy = SubjectStaticFactory.getInstance();
proxy.dealTask("DBQueryTask");
}
}
静态代理实现的条件:
1、有共同的行为(房子) - 接口
2、目标角色(租房人) - 实现行为
3、代理角色(中介) - 实现行为 增强目标对象行为
静态代理的特点
1、目标角色固定
2、在应用程序执行前就得到目标角色
3、代理对象会增强目标对象的行为
4、有可能存在多个代理 引起"类爆炸"(缺点)
优点:安全性高 ,保证类的重用性
缺点:大量类接口,灵活性不强
三,动态代理
相比于静态代理,动态代理在创建代理对象上更加的灵活,动态代理类的字节码在程序运行时,由Java反射机制动态产生。它会根据需要,通过反射机制在程序运行期,动态的为目标对象创建代理对象,无需程序员手动编写它的源代码。动态代理不仅简化了编程工作,而且提高了软件系统的可扩展性,因为反射机制可以生成任意类型的动态代理类。代理的行为可以代理多个方法,即满足生产需要的同时又达到代码通用的目的。
动态代理实现的条件
动态代理能够实现代理类无需和被代理类直接关联,但是动态代理类必须实现Invocation接口,并且实现invoke() 方法,在invoke()方法中需要完成两件事情:一是添加服务,二是调用业务逻辑方法。代理服务就是在代理类中的invoke中执行的。我们可以通过反射机制获取目标对象的加载类、接口,还有实现了Invocation接口的代理类传到Proxy.newProxyInstance(被代理类,被代理类接口,代理类)方法中获取到代理类的对象实例。
动态代理的两种实现方式:
1. JDK 动态代理
2. CGLIB动态代理
创建自己调用的处理器
// 动态代理类对应调用处理程序
public class SubjectInvocatinHandler implements InvocationHandler {
//代理类持有一个委托类的对象引用
private Object delegate;
public SubjectInvocationHandler(Object delegate){
this.delegate = delegate;
}
@Override
public void dealTask(String taskName){
long stime = System.currentTimeMillis();
//利用反射机制将请求分配给委托类处理
//Method的invoke返回Object对象作为方法执行结果
//因为示例程序无返回值忽略返回值
method.invoke(delegate, args);
long ftime = System.currentTimeMillis();
System.out.println("执行任务所用时间"+(ftime -stime)+"毫秒");
return null;
}
}
生成动态代理工厂,列出如何生成动态代理对象类的步骤
// 生成动态代理对象工厂
public class DynProxyFactory {
//客户类调用此工厂方法获得代理对象
//对客户类来说,其并不知道哪个类对象
public static Subject getInstance(){
Subject delegate = new RealSubject();
InvocationHandler handler = new SubjectInvocationHandler(delegate);
Subject proxy = null;
proxy = (Subject)Proxy.newProxyInstance(
delegate.getClass().getClassLoader(),
delegate.getClass().getInterfaces(),
handler);
return proxy;
}
}
客户类
public class Client {
public static void main(String[] args){
Subject proxy = DynProxyFactory.getInstance();
proxy.dealTask("DBQueryTask");
}
}
动态代理的特点
- 目标对象不固定
- 在应用程序执行时动态创建目标对象
- 代理对象会增强目标对象的行为
优点:降低了代码的冗余度,较强灵活性
缺点:需要实现接口(Proxy已经设计得非常完美,但还是无法摆脱仅支持interface代理)