JFianl自定义IOC工具
来源:互联网 发布:科技美学知乎 编辑:程序博客网 时间:2024/06/09 14:59
学习和了解了关于JFianl框架的一些东西后,发现JFinal并没提供IOC,虽然网上有人说可以通过IOC插件实现,但毕竟JFinal没有原生支持,算是个遗憾。在昨天我自己写了一个IOC工具,今天跟大家分享一下,并且这个工具在我自己的一个Demo项目中也被应用了。
首先说说IOC实现的原理,如果不是很懂IOC的朋友请先搜索一下相关的知识,最起码要了解IOC的功能,而我会直奔主题,我是如何实现的。这里有三个准备工作:
1、IOC注解,作为注入工具,首先我要拿到实例创建的或者引用赋值的权利,而标志需要被IOC管理的类级元素或者成员,我会用注解来描述。
2、IOC注解的翻译器,只要发现了有类级元素或者成员被IOC注解修饰过,那么就需要被管理器接管。
3、IOC管理器,管理所有被托管的类型,负责对外提供类的实例。
针对IOC注解,这里我目前只定义了一个,可能不是很恰当,主要原因有两个:一个是该注解不能很好的描述被标记的类元素所属的层级(MVC层);第二个是IOC管理器目前接管了所有被标记的类,当托管容量过大的时候,或者类型略复杂的时候,这个注解显得过于单薄,这一点以后有时间我会做些改动。目前该注解如下:
/** * @author Rocky * 当该注解被修饰类级元素时,会被IocProcessor加入到IocManager中,如果未指定name,则取ClassForName()作为它的值; * 当该注解被修饰域时,IocProcessor则会从IocManager中取得实例,此时isSingle不发生任何作用 */@Target({ElementType.TYPE, ElementType.FIELD})@Retention(RetentionPolicy.RUNTIME)@Inherited@Documentedpublic @interface InjectBind { String name() default ""; boolean isSingle() default true;}首先它描述了两个作用范围:一个是Type,一个是Field(这里就是我上面提到的一点不足,因为仅有一个注解,那么我需要让它的功能变得强大,而代价就是变得复杂)。当InjectBind修饰一个类的时候,那么表明,该类是需要被IOC管理器接管的;如果修饰一个类的域,那么表明,在该类的对象被初始化后,IOC管理器需要为该域赋值(从管理器中取得一个实例,或者新创建,或者单例取得)。
该注解之后就是对应的处理器,处理器相对简单,先上代码,然后有几点再仔细说明:
/** * @author Rocky * Ioc处理器,翻译InjectBind,实现注入绑定和获得实例功能 */public class IocProcessor {/** * Ioc管理器 */private static IocManager im = IocManager.getIocManager();/** * 如果当前Class被InjectBind修饰则加入Ioc管理器; * 如果当前Class有字段被InjectBind修饰则通过Ioc管理器取得实例 * @param obj如果obj是Class类型的时候,表明该类需要被判断是否加入IocManger,否则process就应当在对象实例化之后使用 */public static void process(Object obj) {Class<?> clazz = null;if(obj instanceof Class) {clazz = (Class<?>) obj;} else {clazz = obj.getClass();}if(clazz.isAnnotationPresent(InjectBind.class)) {InjectBind jb = clazz.getAnnotation(InjectBind.class);String name = jb.name();boolean isSingle = jb.isSingle();if(name.isEmpty()) {im.add(clazz, isSingle);} else {im.add(name, clazz, isSingle);}} else {Field[] fields = clazz.getDeclaredFields();for(Field f : fields) {if(f.isAnnotationPresent(InjectBind.class)) {InjectBind jb = f.getAnnotation(InjectBind.class);String name = jb.name();Object inject = null;if(name.isEmpty()) {inject = IocManager.getInstance(f.getClass().getName());} else {inject = IocManager.getInstance(name);}try {f.setAccessible(true);f.set(obj, inject);} catch (IllegalArgumentException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}}}}}首先要说明的是该处理器持有一个IOC管理器,因为IOC注解工具在翻译注解之后,一旦发现该类或者该类的成员有被IOC注解修饰,那么就需要通过IOC管理器添加到托管集合中,或者从托管集合中取出实例。
第二点就是process()方法接收的参数是Object类型,这里的处理是情非得已。原因有三:第一是因为IOC注解并没有区分究竟是描述的类,还是域,那么process方法就需要把两个情况都考虑到;第二就是当IOC注解描述的是成员的时候,process需要通过IOC管理器取得实例,并为该成员赋值,这里就有一个问题,此时的类对象必须存在,也就是说此时process接收到的一定是一个Object类型的对象实例;第三Class类型也是派生自Object,所以当我使用更底层的类型,是没有问题的,仅需要判断下此时的obj对象的类型是不是Class即可。
最后在看看IOC管理器:
/** * @author Rocky * Ioc管理器,其内部维护着两个Map,分别持有单例和非单例的类映射 */public class IocManager { private static final IocManager im = new IocManager();private Map<String, Class<?>> map = new HashMap<String, Class<?>>();private Map<String, Object> sMap = new HashMap<String, Object>();private IocManager() {}public static IocManager getIocManager() {return im;}/** * 添加一个映射,当未指定key值的时候,取value.getName() * @param clazz映射value * @param isSingle是否单例模式 * @return */public IocManager add(Class<?> clazz, boolean isSingle) {add(clazz.getName(), clazz, isSingle);return this;}/** * 添加一个映射,当未指定value值的时候,取Class.forName() * @param name映射key * @param isSingle是否单例模式 * @return */public IocManager add(String name, boolean isSingle) {try {add(name, Class.forName(name), isSingle);} catch (ClassNotFoundException e) {e.printStackTrace();}return this;}/** * @param name映射key * @param clazz映射value * @param isSingle是否单例模式 * @return */public IocManager add(String name, Class<?> clazz, boolean isSingle) {if(isSingle) {try {sMap.put(name, clazz.newInstance());} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}} else {map.put(name, clazz);}return this;}/** * 取得实例 * @param name映射key * @return */public static Object getInstance(String name) {if(im.map.containsKey(name)) {try {return im.map.get(name).newInstance();} catch (InstantiationException e) {e.printStackTrace();return null;} catch (IllegalAccessException e) {e.printStackTrace();return null;}} else {return im.sMap.get(name);}}}这里也有几点需要说明,IOC管理器必须是唯一的,因此是单例的。其次IOC管理器内部维护着两个Map,一个是单例模式被托管的类,一个是非单例的。最后管理器提供了两个主要功能,一个是向其内部的两个Map中添加元素,一个是通过getInstance方法对外提供实例。
至此准备工作结束,最后我来说明下它们是怎么工作的。
在应用部署服务器之后,启动容器,此时我会一个处理,就是扫描指定的路径,获得该路径下的所有的类,然后依次检查是否有被IOC注解修饰(仅检查类级元素),如果有就被加入到IOC管理器中。
之后在运行期间,每当一个实例被创建执行其内部方法的时候,我需要在方法调用前拦截,检查该对象内部是否有成员被IOC注解修饰,如果有则为其赋值。
那么可以简单的模拟一下:
public class A {@InjectBind(name="B")private B b;public void test() {System.out.println(b);System.out.println(b.getTest());}}类A有一个B类型的成员b,已经被InjectBind修饰,继续:
@InjectBind(name="B")public class B {public String getTest() {return "成功绑定";}}类B被InjectBind修饰,需要在应用启动时加入到IOC管理器中,最后模拟环境如下:
public class IocTest {@Testpublic void isBindSuccess() {IocProcessor.process(B.class);A a = new A();IocProcessor.process(a);a.test();}}isBindSuccess方法首先要处理B.class,这是模拟了容器启动后的扫描工作,将被IOC注解修饰的类型加入到IOC管理器中。然后在执行test()方法前处理a对象,这是模拟执行对象方法前的拦截,将对象进行扫描,检查是否有成员被IOC注解修饰,如果有为其赋值,看看结果吧:
最后我要说是,这个IOC工具编写的很简陋,但是方向应该没有太大的偏差,当然这是我自己认为的……如果有朋友发现哪里有问题,希望能及时联系我,感激不尽。
1 0
- JFianl自定义IOC工具
- beetl jfianl
- Spring IOC 自定义事件
- 自定义Android IOC框架
- IOC/AOP工具 jBeanBox
- JFianl源码走读_7_Interceptor
- jfianl 初用redis
- jfianl中的图形验证
- JFianl框架学习笔记一
- IDEA Maven JFianl环境搭建
- Jfianl 多数据源连接
- IDEA Maven JFianl环境搭建
- 【Java.Spring.Core】【IoC】自定义bean nature
- 自定义实现spring式的IOC
- Spring AOP与IOC以及自定义注解
- Spring IOC 自定义属性编辑器PropertyEditor
- spring 实现自定义 ioc(简单版)
- Spring IOC源码分析-自定义标签加载
- Angular强大的指令
- JavaScript中的模块化开发
- linux 静态库和动态库的一些笔记
- 线程安全和线程不安全理解
- mysql 触发器案例
- JFianl自定义IOC工具
- java之socket
- 邮件读取协议POP3和IMAP
- FastBoot BootLoader Recovery 模式解释
- River Hopscotch poj3258 (二分+贪心思想+最小值最大化)
- 《Head First 设计模式》-抽象工厂模式C++实现
- zookeer
- windows 下redis在后台运行
- 方法记