小型IOC框架的实现

首先要明白IOC框架要实现什么功能

  1.依赖倒转

  2.使用注解

下面是一个Action

@Bean
public class BaseAction {
    @Inject
    private TestService testService;
    @Request
    public void print(){
        System.out.println("print method run...");
        testService.print();
    }
}

这个Action用到了三个注解

@Bean标注这是一个Action

@Inject标注着是需要注入的属性

 

思路:先想一下Spring是怎么来实现的,先在xml文件中定义好使用注解的路径或者Bean类,然后在根据这个路径进行整个项目的扫描,如下

<context:component-scan base-package="com.zhyonk.blablabla" />

那么问题来了,怎么根据这个com.zhyonk.action来扫描呢?

 

应该是获取到项目所在系统中的路径,再拼接字符串,最后拼接出来的应该是在系统中的据对路径。

 

那么先用"C:/dev/workspace/Eclipseworkspace/zhyonk/bin/mvc/zhyonk/action"来代替

 

首先扫描这个目录下所有的以.class结尾的文件并存起来

 

然后获取所有的用@Bean注解的类。将这些类和类的实例存到Map中,因为本质上Spring的IOC容器也是用Map来存储需要托管的类

 

问题又来了,怎么获取所有的包含@Bean的类呢?

 

对,利用反射获取,利用之前存储的.class信息的文件集合,对文件名进行字符串的分割来获取类的完整类名

 

根据这个完整类名。利用Class.forName()来进行类的初始化。最终存储到Map(Class<?>,Object)中

 

获取到包含@Bean注解的类了,之后要在这些类中扫描注入点,也就是@Inject注解的属性。

 

这个也是利用反射,获取到到所有的Field,再调用field.isAnnotationPresent(Inject.class)来判断是否有@Inject注解

 

好了,现在找到的类既有@Bean注解,又有@Inject注解。接下来就是注入了。

 

那么又得扫描了,Spring可以直接用BeanNameProxyCreator进行动态的代理,

<bean id="BeanProxy"
        class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="beanNames">
            <!-- 对类名以ServiceImpl结尾的、标注的类进行代理, -->
            <value>*ServiceImpl</value>
        </property>
        <!-- 对代理类进行加载拦截器(实现通知的过程) -->
        <property name="interceptorNames">
            <list>
                <!-- 该值和拦截器的id保持一致 -->
                <value>transactionInterceptor</value>
            </list>
        </property>
    </bean>

实现起来太麻烦了,我还是先用之前的路径来代替。在那个目录下扫描

 

先判断有没有TestService这个类

@Inject
    private TestService testService;

在判断有没有TestService的子类。

 

在Spring中注入接口只能有一个子类,要是多个的话会直接报错的。

 

怎么判断哪个类是注入接口的子类呢?

 

父类好判断,子类得自己去找。首先的有一个范围。对就是首先确定在哪扫,就用之前的那个路径吧

 

扫描到所有的类再判断

 

    /**
     * 根据接口获取该接口的子类
     * @param interfacetype
     */
    public static Class<?> getClassListByInterface(Class<?> interfacetype,String ImplPath) {
        List<Class<?>> list1 = new ArrayList<Class<?>>();
        File[] scanClassFile = scanClassFile(ImplPath);
        //这样比较麻烦,但就先这样吧
        List<Class<?>> allClassFile = null;
        try {
            allClassFile = getAllClassFile(scanClassFile);
        } catch (ClassNotFoundException e) {
            System.out.println("找实现子类的时候在目录下没有找到类哦");
            e.printStackTrace();
        }
        //遍历指定目录下的所有的类
        for (Class<?> class1 : allClassFile) {
            Class<?>[] interfaces = class1.getInterfaces();
            String supername = interfacetype.getName();
            //遍历类所有的父类
            for (Class<?> superclass : interfaces) {
                //判断父类有没有interfacetype类型的
                if(superclass.getName().equals(supername)){
                    //添加子类的到list中
                    list1.add(class1);
                }
            }
        }
        
        //判断有几个子类,就先返回第一个子类吧
        //如果子类数量大于1个
        if(list1.size()>1){
            System.out.println("抱歉目前只支持返回一个子类");
            return list1.get(0);
        }else{
            return list1.get(0);
        }
    }

返回的是一个Class<?>类型的,因为之需要一个子类

 

哦了,实例需要注入的接口子类对象,用反射注入到之前的Map<Class<?>,Object>中

Object object =subclass.newInstance();
field.setAccessible(true);
field.set(value,object);

 

再提供一个依据类获取对象的方法

    public static Object getBean(Class<?> clazz) {
        return beanmap.get(clazz);
    }

 

完成了

 

重要的是明白其中的思想!

 

源码在

https://github.com/zhyonk/Zhyonk

 

打算写一个MVC框架,刚把IOC容器写好!!

 

posted @ 2016-12-22 15:24  zhyonk  阅读(288)  评论(0编辑  收藏  举报