代理模式
结构型模式
在代理模式(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动静代理效率较高。