PostConstruct:注入完成后自动调用方法 基于自动的依赖注入的类的实例只有在依赖注入完成以后才可以被使用。为了在被注入的类中安全的使用实例,可以申明[PostConstruct]元数据,从而在所有的注入完成后,自动调用被[PostConstruct]申明的方法。可以通过order参数来决定方法调用的顺序,如: 如下例 - package
- {
- public class InjecteeClass//接收注入的类
- {
- [Inject]public var injectPoint:InjectObject;//注入点
- public function InjecteeClass()
- {
- }
- [PostConstruct(order=1)]
- public function order1():void{//定义注入完成后执行的第一个函数
- trace("post 1");
- }
-
- [PostConstruct(order=2)]
- public function order2():void{//定义注入完成后执行的第一个函数
- trace("post 2")
- }
- }
- }
-
- package
- {
- public class InjectObject//被注入的对象
- {
- public function InjectObject()
- {
- trace("created");//构造函数
- }
- public function call():void{//一个简单的方法调用
- trace("called");
- }
- }
- }
-
- package
- {
- import flash.display.Sprite;
-
- import org.swiftsuspenders.Injector;
-
- public class SwiftSuspenderDemo extends Sprite
- {
- public function SwiftSuspenderDemo()//一个demo
- {
-
- var injector:Injector = new Injector();//申明注入器
- injector.mapClass(InjectObject,InjectObject);//对InjectorObject类进行类映射
- injector.mapClass(InjecteeClass,InjecteeClass);//对InjecteeClass进行类映射
-
-
- var instance:InjecteeClass = injector.getInstance(InjecteeClass);//通过注入器获取InjecteeClass对象,注入器自动完成注入
- instance.injectPoint.call();//对注入过的对象进行调用
-
- }
- }
- }
复制代码输出结果: created post 1 post 2 called 可以看出,在完成注入后,分别调用了order1和order2方法。通过PostConstruct元数据可以完成注入后的一些逻辑代码。 查询注入映射 在1.5版本以后,Swiftsuspenders可以通过Injector类的hasMapping方法查询已有映射规则的存在性,hasMapping方法会通过类或接口的加上注入名来查询是否有相应的注入映射。如果有返回ture,没有则返回false 直接应用注入 在SwiftSuspenders1.5以后,可以通过使用Injector的getInstance方法直接应用注入。getInstance方法需要传入一个类或者接口(注入名可选),从而返回开发者定义的映射结果。如果没有定义,则会抛出异常 返回的值依赖于定义的请求映射。如,已经为一个请求定义了一个单例映射,则共享的单例对象在接受请求时会被返回,而不是新建一个实例。 异常处理 如果请求的注入映射没有找到,包含目标类和请求属性类型的异常会被抛出。 子注入器(Injector) 从SwiftSuspenders1.5开始,支持创建子注入器(Injector)。子注入器会依赖父注入器,并且会自动继承父注入器的映射规则。除此之外,资注入器还可以有自己的隐射规则,同时还可以重写父注入器的映射规则。 这个特性主要为解决所谓的”机器人腿问题”(robot legs problem)。当使用依赖注入时,开发者希望创建只有很轻微差别的相思的对象树。以一个简单的机器人(robot)为例,这个机器人可以使用相同的零件做腿(leg),但是需要使用不同的零件分辨做为左脚(left foot)和右脚(right foot)。使用传统的依赖注入,开发者需要针对RobotLeg类分别扩展子类,从而实现对不同脚的不同注入,子类会实现样板代码来父类希望注入的脚的对象。如下例 - public class Robot//机器人类
- {
- [Inject] public var leftLeg : LeftRobotLeg;//属性注入,左腿
- [Inject] public var rightLeg : RightRobotLeg;//属性注入,右腿
- }
-
- public class RobotLeg//腿的父类
- {
- protected var foot : RobotFoot;//脚属性
- }
-
- public class LeftRobotLeg extends RobotLeg//左腿类
- {
- [Inject] public function set foot (foot : LeftRobotFoot) : void//方法注入,注入一个左脚
- {
- this.foot = foot;
- }
- }
-
- public class RightRobotLeg extends RobotLeg//右腿类
- {
- [Inject] public function set foot (foot : RightRobotFoot) : void//方法注入,注入一个右脚
- {
- this.foot = foot;
- }
- }
-
- public class RobotConstruction
- {
- var injector : Injector = new Injector();//申明一个注入器
- injector.mapClass(LeftRobotLeg, LeftRobotLeg);//左腿类映射
- injector.mapClass(RightRobotLeg, RightRobotLeg);//右腿类映射
- injector.mapClass(LeftRobotFoot, LeftRobotFoot);//左脚类映射
- injector.mapClass(RightRobotFoot, RightRobotFoot);//右脚类映射
- var robot : Robot = injector.instantiate(Robot);//实例化机器人,自动完成所有注入
- }
复制代码 而使用子注入器,机器人可以值使用RobotLeg类进行构建,并且同时支持对不同的腿注入不同的脚,如: - public class Robot//机器人类
- {
- [Inject(name=‘leftLeg’)] public var leftLeg : RobotLeg;//属性注入,注入名为左腿
- [Inject(name=‘rightLeg’)] public var rightLeg : RobotLeg;//属性注入,注入名为右腿
- }
-
- public class RobotLeg//腿类
- {
- protected var foot : RobotFoot;
- }
-
- public class RobotConstruction
- {
- var injector : Injector = new Injector();//申明注入器
- var leftLegRule : InjectionConfig = injector.mapClass(RobotLeg, RobotLeg, ‘leftLeg’); //定义左腿注入配置(InjectionConfig)
- var leftLegInjector : Injector = injector.createChildInjector(); //创建左腿子注入器
- leftLegInjector.mapClass(RobotFoot, LeftRobotFoot); //左腿子注入器加入左脚映射
- leftLegRule.setInjector(leftLegInjector); //为左腿注入规则定义相应的注入器, 这里其实是SwiftSuspenders实现决定的,如果一个注入配置没有设置特有的注入器(Injector),那么会调用创建该注入规则的注入器进行注入;如果诸如配置设置了特有的注入器,那么优先调用设置的注入器进行注入,这部分会在深入部分的源码分析中详细阐述。
-
- //以下为右腿,与左腿类似
- var rightLegInjector : Injector = injector.createChildInjector();
- rightLegInjector.mapClass(RobotFoot, RightRobotFoot);
- rightLegRule.setInjector(rightLegInjector);
- //finally, create the object tree by instantiating the Robot class:
- var robot : Robot = injector.instantiate(Robot);//创建实例,所有注入自动完成
- }
复制代码 子注入器会将它们没有的映射请求推送到它们的父注入器。这样就可以在注入器之间共享额外的映射规则。例如,机器人的脚可能会有脚指头对象,这些脚指头对不同的脚都是相同的,所以针对脚指头的映射就会添加到父亲注入器而不是每一个子注入器中。 如果一个从父注入器的映射被使用了,这不代表子注入器不再被随后的注入使用了。例如,你可以在你的子注入器中有一个洞,这个洞会由祖先注入器来弥补,然后任然在你的子注入器中定义其他的,你想要在以后通过依赖注入构建对象树时使用的隐射。 注入器可以创建任意复杂度的配置树。 基于XML配置注入点(Injection points) 注意:现在已经可以再Flash CS3/4/5中使用元数据了。所以基于XML配置注入点的主要原因就不复存在了。为了让你的应用支持所有的元数据,请检查在发布设置(Publish Settings)面板中的导出SWC文件(export swc)选项。更多的信息请参考博客:http://www.patrickmowrer.com/2010/03/03/compiling-custom-as3-metadata-flash-professional Injector类的构造函数中有一个可选的参数,这个参数是一个XML对象,如果这个XML被提供了,SwiftSuspenders就会根据这个XML来配置所有的注入点 XML配置文件由一系列的<type />节点组成,这些节点代表了注入点。注入的目标类由name属性指定。Setter注入和属性注入有<field />节点指定,方法注入由<method />节点指定,构造函数注入由<constructor />节点指定。对于所有的注入类型,目标属性由name属性给出,要指定注入的注入名,可以通过injectionname属性指定。对于方法和构造函数注入,多个参数可以由<arg />节点定义。 注入类型仍然由运行时的反射机制获得,所以不需要对注入类型进行支持。 除了注入点之外,PostConstruct方法同样可以通过添加<postconstruct />节点声明 下面的示例代码包含了所有可能的配置选项 - <types xmlns="http://github.com/tschneidereit/SwiftSuspenders">
- <type name='com.example.injectees::FirstInjectee'>
- <field name='unnamedInjectionPoint'/>
- <field name='namedInjectionPoint' injectionname='namedInjection'/>
- <postconstruct name='firstPostConstructMethod' order='1'/>
- <postconstruct name='secondPostConstructMethod' order='2'/>
- </type>
- <type name='com.example.injectees::SecondInjectee'>
- <method name='unnamedInjectionMethod'/>
- <method name='namedInjectionMethodWithOneArgument' injectionname='namedInjection'/>
- <method name='namedInjectionMethodWithMultipleArguments'>
- <arg injectionname='namedInjection'/>
- <arg injectionname='namedInjection2'/>
- </method>
- </type>
- <type name='com.example.injectees::ThirdInjectee'>
- <constructor>
- <arg injectionname='namedInjection'/>
- <arg injectionname='namedInjection2'/>
- </constructor>
- </type>
- </types>
复制代码注意,要确保Flash IDE和 MXMLC(如,flex)编译的一样,如果XML配置文件使用时,SwiftSuspenders会忽略所有的元数据。 swiftSuspenders是一个基于元数据的依赖注入框架,元数据是AS3的特有一种特性。其时本质上AS3的元数据就是在AS类的XML表示中添加一些自定义的标签。所以本质上,swiftsuspenders还是一个基于XML进行依赖注入配置的框架。基于XML的配置实际上相当于手动添加元数据信息。 依赖注入是针对对象的进一步解耦,将对象之间的耦合关系通过一种配置文件进行表示(通常是XML),然后通过解析配置文件将对象之间的依赖关系进行注入,从而生成对象。 使用外部XML的另一个好处是可以动态载入,基于元数据的注入如果需要修改,需要重新编译源码,这也有一些违背依赖注入设计的一些初衷。而通过外部的XML进行依赖配置,可以动态的更改依赖而不需要重新编译代码。所以基于XML的依赖配置还是很有作用的。 范例(官方提供)属性和setter注入 假设你的类需要注入依赖如下: - package
- {
- public class MyDependentClass//需要注入的类
- {
- [Inject]
- public var firstDepency : MovieClip;//申明一个MovieClip类型的注入点,无注入名
-
- [Inject(name="currentTime")]
- public var secondDependency : Date;//申明一个Date类型的注入点,注入名为currentTime
-
- [Inject]
- public function set thirdDependency(value : Sprite) : void//申明一个setter方法的注入点,无注入名
- {
- m_thirdDependency = value;
- }
- private var m_thirdDependency : Sprite;
- }
- }
复制代码要想向这个对象的实例里面进行依赖注入,你需要首先定义依赖映射,然后调用Injector的InjectInto方法,如下: - var injector : Injector = new Injector();
- injector.mapValue(MovieClip, new MovieClip());//值映射
- var currentTime : Date = new Date();
- injector.mapValue(Date, currentTime, 'currentTime');//带有注入名的值映射
- injector.mapSingleton(Sprite); //单例映射
- var injectee : MyDependentClass = new MyDependentClass();
- injector.injectInto(injectee);//注入依赖
复制代码 方法注入 假设你的类需要注入依赖如下: - package
- {
- public class MyDependentClass
- {
- private var myMovieClip : MovieClip;
- private var currentTime : Date;
-
- [Inject]
- public function setFirstDependency(injection : MovieClip) : void//方法注入,不带注入名
- {
- myMovieClip = injection;
- }
-
- [Inject(name="currentTime")]//方法注入,带有名为currentTime的注入名,单个参数
- public function setSecondDependency(injection : Date) : void
- {
- currentTime = injection;
- }
-
- [Inject(name='', name="currentTime")]//方法注入,带有名为currentTime的注入名,多个参数
- public function setMultipleDependencies(movieClip : MovieClip, date : Date) : void
- {
- myMovieClip = movieClip;
- currentTime = date;
- }
- }
- }
复制代码-要想向这个对象的实例里面进行依赖注入,你需要首先定义依赖映射,然后调用Injector的InjectInto方法,如下: - var injector : Injector = new Injector();
- injector.mapValue(MovieClip, new MovieClip());
- var currentTime : Date = new Date();
- injector.mapValue(Date, currentTime, 'currentTime');
- var injectee : MyDependentClass = new MyDependentClass();
- injector.injectInto(injectee);
复制代码 构造函数注入 假设你的类需要注入依赖如下: - package
- {
- [Inject(name='', name="currentTime")]
- public class MyDependentClass//构造函数注入需要写在类之前
- {
- private var myMovieClip : MovieClip;
- private var currentTime : Date;
-
- public function MyDependentClass(movieClip : MovieClip, date : Date)
- {
- myMovieClip = movieClip;
- currentTime = date;
- }
- }
- }
复制代码要想向这个对象的实例里面进行依赖注入,你需要首先定义依赖映射,然后调用Injector的InjectInto方法,如下: - var injector : Injector = new Injector();
- injector.mapValue(MovieClip, new MovieClip());
- var currentTime : Date = new Date();
- injector.mapValue(Date, currentTime, 'currentTime');
- var injectee : MyDependentClass = injector.instantiate(MyDependentClass);
复制代码至此SwiftSuspenders 1.6 浅出深入的浅出部分就结束了,相信通过这篇浅出教程大家应该可以对SwiftSuspenders 有个大致的认识。之前没有过依赖注入编程经验的童鞋应该会对依赖注入有一个大致的认识。之前有过依赖注入相关知识了解的童鞋应该已经可以采用SwiftSuspenders做相应的开发了。 后面开始就会进入SwiftSuspenders 1.6 浅出深入 的深入部分。
传送门:
|