mybatis中用了不少设计模式,其中mappr接口调用使用了动态代理:
代理模式
-
代理
- 静态代理
- 事件一般用接口或者抽象类
- 代理类(实现这个事件 必须东这个事件才能代理) 包含被代理的事件的主角
- 事件的主角(也实现这个事件) 被代理的对象
- 静态代理 只对一个熟悉 不具备通用性
- 动态代理
- 专门做动态代理的接口 implements InvocationHander
- 重写invoke方法 什么都可以
- 把目标和代理对象捏合成一个新的对象(新的代理类 才能去代理),在捏合的过程中,把目标的类加载器 接口还有代理对象都传递给proxy.newProxyInstance方法
- getInterfaces() 通过反射获得接口数组
- jdk下面的Proxy对象下的newInstance,要求必须要有事件,委托人必须要实现事件的接口
- cglib字节码修改器
-
性能更高
-
直接通过类加载器 对类的字节文件进行修改
-
类加载器:将磁盘中的文件通过io流加载到内存中。加载到内存中才能对类进行修改。
-
代理一般使用CGLIBProxy
-
不要忘记导入jar包 asm cglib javassist
-
一个类代表另一个类,创建现有对象的对象,以便向外界提供功能接口。 向在访问这个类的时候做一些控制的时候可以使用代理模式 增加中间层,实现与被代理类的组合。
优点----为什么时候代理模式
-
职责清晰 高扩展性 智能化
-
当你在访问一个对象的时侯想要对这个类进行一些控制,(装饰者模式是增强功能)
-
提供了对目标对象另外的访问方式。通过代理对象来访问目标对象,好处:可以在目标对象的基础上增加额外的功能来扩展目标对象的功能。
-
当你想要对要使用的对象进行修改的时候,不要直接在源码上进行修改,而是使用代理工厂的模式 使用代理类来实现你想的功能
应用
- 远程代理: 为一个对象在不用的地址空间提供局部代表,这样可以隐藏一个对象存在于不同地址空间的事实。
- 虚拟代理:根据需要创建开销很大的对象。通过它来存放实例化需要很长时间的真实对象。
- 安全代理:用来控制真实对象访问时的权限
- 智能指引:指调用真实对象时,代理处理另外一些事。
应用实例
- 火车票不仅可以在火车站买也可以在车代售点买。
- 一个人A变换成另一个人B的模样,将B的外貌抽象出来,A B都实现了这个接口,用户C访问A的时候 看不出A不是B 所以可说A是B的代理类。 以说A是B的代理类。
代理模式的分类
- 代理的实现 聚合和继承
动态代理模式(不知道代理类的名称 直接产生代理对象)
解决类太多的问题
-
继承:不宜与扩展
-
聚合(使用接口的方式):一个类A中有另外一个类B的对象(接口),两个类实现相同的接口,但是在一个类A中调用的是另一个类B的方法。 A就是B的一个代理,因为在A中调用的方法是B的方法
- 通过接口来实现代理
- 比较灵活,可以随意地调换代理事务的顺序。
-
实现动态的编译
- JavaCompiler(java的编译器 javac)
静态代理(需要知道代理类的类名)
一个代理类 和 触发人 实现接口 一个代理类只有一个功能
-
实现动态代理模式的方式有两种:
-
依赖jdk的Proxy对象下的newProxyInstance()
- 注意事项:必须要救要有事件,委托人必须要实现事件接口
- 代理人实现InvocationHander接口 重写invoke方法 在invoke方法中做一些代理的额处理,通过method.invoke(this.obj,args) 来调用委托人的方法
- 调用的时候将代理人和委托人通过(代理类)Procy.newProxyInstance(委托类.getClassLoader(),委托类.getInterfaces(),代理类);
-
cglib字节码修改器实现代理
- 于jdk中的实现动态代理方式不同的就是,委托人不需要实现特定的接口
- 需要导入 ams.jar 和 cglib.jar 和 javassist.jar
- 核心类 Enhancer
- 委托类不需要实现接口, 代理类要实现MethodInterceptor接口 使用回调的方法,效率比proxy要快
- 在代理类中写createProxy方法
public Object createProxy(Object target){ this.obj = target; Enhancer enhancer = new Enhancer(); //设置被代理对象目标 enhancer.setSuperclass(this.obj.getClass()); //回调 调用下面的intercept(..)方法 enhancer.setCallback(this); enhancer.setClassLoader(target.getClass().getClassLoader()); return enhancer.create();
-
- 调用:
Target t = new Target(); MyProxy my = new MyProxy(); Target t2 = (Target) my.createProxy(t); t2.getMsg("sdsf");