共计 3712 个字符,预计需要花费 10 分钟才能阅读完成。
代理模式
结构型模式
在代理模式(Proxy Pattern)中,一个类代表另一个类的性能。
在代理模式中,咱们创立具备现有对象的对象,以便向外界提供性能接口。
介绍
用意: 为其余对象提供一种代理以管制对这个对象的拜访。
次要解决: 在间接拜访对象时带来的问题,比如说:要拜访的对象在近程的机器上。在面向对象零碎中,有些对象因为某些起因(比方对象创立开销很大,或者某些操作须要安全控制,或者须要过程外的拜访),间接拜访会给使用者或者系统结构带来很多麻烦,咱们能够在拜访此对象时加上一个对此对象的拜访层。
何时应用: 想在拜访一个类时做一些管制。
如何解决: 减少中间层。
要害代码: 实现与被代理类组合。
具体实现
第一种:动态代理
咱们将创立一个 ITeacherDao 接口和实现了 ITeacherDao 接口的实体类。TeacherDaoProxy 是一个代理类,减少一些额定的性能。
咱们的演示类应用 TeacherDaoProxy 来获取要加载的 ITeacherDao 对象,并依照需要进行显示。
第一步:创立一个接口
public interface ITeacherDao {void teach();
}
第二步:创立实现类
public class TeacherDao implements ITeacherDao {
@Override
public void teach() {System.out.println("老师授课中...");
}
}
第三步:创立代理类
public class TeacherDaoProxy implements ITeacherDao {
// 指标对象, 通过接口来聚合
private ITeacherDao target;
public TeacherDaoProxy(ITeacherDao target) {this.target = target;}
@Override
public void teach() {System.out.println("开始代理...");
target.teach();
System.out.println("完结代理...");
}
}
第四步:创立测试类
public class Client {public static void main(String[] args) {// 创立指标对象 ( 被代理对象)
TeacherDao teacherDao = new TeacherDao();
// 创立代理对象, 同时将被代理对象传递给代理对象
TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(teacherDao);
// 通过代理对象, 调用到被代理对象的办法
teacherDaoProxy.teach();}
}
运行如下:
开始代理...
老师授课中...
完结代理...
长处:
在不批改指标对象的性能前提下,能通过代理对象来对指标性能进行扩大。
毛病:
1、因为代理对象和指标对象都要实现同一接口,所以会有很多代理类。
2、一旦接口减少办法,指标对象和代理对象都要保护。
3、因为在客户端和指标对象之间减少了代理对象,因而有些类型的代理模式可能会造成申请的处理速度变慢。
第二种:动静代理(JDK 代理)
第一步:创立一个接口
public interface ITeacherDao {void teach();
}
第二步:创立实现类
public class TeacherDao implements ITeacherDao {
@Override
public void teach() {System.out.println("老师授课中...");
}
}
第三步:创立动静代理类
public class ProxyFactory {
// 保护指标对象
private Object target;
public ProxyFactory(Object target) {this.target = target;}
// 给指标对象生成代理对象
public Object getProxyInstance() {
//1. ClassLoader loader : 指定以后指标对象应用的类加载器, 获取加载器的办法固定.
//2. Class<?>[] interfaces : 指标对象实现的接口类型, 应用泛型办法确认类型.
//3. InvocationHandler h : 事件处理, 执行指标对象的办法时, 会触发事件处理器的办法, 会把以后执行的指标对象办法作为参数传入.
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), (proxy, method, args) -> {System.out.println("动静代理开始...");
Object returnVal = method.invoke(target, args);
System.out.println("动静代理完结...");
return returnVal;
});
}
}
第四步:创立测试类
public class Client {public static void main(String[] args) {// 创立指标对象 ( 被代理对象)
ITeacherDao target = new TeacherDao();
// 给指标对象生成代理对象
ProxyFactory proxyFactory = new ProxyFactory(target);
ITeacherDao proxyInstance = (ITeacherDao) proxyFactory.getProxyInstance();
proxyInstance.teach();}
}
运行如下:
动静代理开始...
老师授课中...
动静代理完结...
要害代码:
- java.lang.reflect.Proxy: 生成动静代理类和对象;
- java.lang.reflect.InvocationHandler(处理器接口):能够通过 invoke 办法实现
总结
尽管这个变体胜利的防止了动态代理中的反复缺点,然而它依然有一个局限性,它无奈应用不是从接口继承的实现类,就是说,应用动静代理类,原始类必须先要实现一个或多个接口,这个接口也就是代理接口。
第三种:Cglib 代理
在应用 Cglib 代理时候须要引入绝对应的 Jar 包,这里就不展现 maven 是如何配置的。
第一步:创立指标类
public class TeacherDao {public void teach(){System.out.println("老师授课中... 我是 cglib 代理的, 不须要实现接口");
}
}
第二步:创立代理类
public class ProxyFactory implements MethodInterceptor {
// 保护一个指标对象
private Object target;
public ProxyFactory(Object target) {this.target = target;}
// 返回一个代理对象, 是 target 的指标对象
public Object getProxyInstance() {
//1. 创立一个工具类
Enhancer enhancer = new Enhancer();
//2. 设置父类
enhancer.setSuperclass(target.getClass());
//3. 设置回调函数
enhancer.setCallback(this);
//4. 创立子类对象, 及代理对象
return enhancer.create();}
// 重写 intercept 办法, 会调用指标对象的办法
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {System.out.println("cglib 代理模式开始...");
Object returnVal = method.invoke(target, args);
System.out.println("cglib 代理模式完结...");
return returnVal;
}
}
第三步:创立测试
public class Client {public static void main(String[] args) {
// 指标对象
TeacherDao target = new TeacherDao();
// 给指标对象生成代理对象
ProxyFactory proxyFactory = new ProxyFactory(target);
TeacherDao proxyInstance = (TeacherDao) proxyFactory.getProxyInstance();
proxyInstance.teach();}
}
运行如下:
cglib 代理模式开始...
老师授课中... 我是 cglib 代理的, 不须要实现接口
cglib 代理模式完结...
总结:
Cglib 原理是针对指标类生成一个子类,笼罩其中的所有办法, 所以指标类和办法不能申明为 final 类型和 static 类型!
从执行效率上看,Cglib 动静代理效率较高。