文档章节

我的IOC原理实现——使用注解读取元数据

啦啦啦拉拉
 啦啦啦拉拉
发布于 2016/08/29 20:41
字数 592
阅读 31
收藏 0

我的个人博客

IOC容器就是具有依赖注入功能的容器,IOC容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。应用程序无需直接在代码中实例化的对象,应用程序由IOC容器进行组装。

以往一般使用基于XML配置文件进行配置元数据,Spring与配置文件完全解耦。但是编写XML定义读取实在是过于繁琐,所以近来都倾向使用注解配置。

模仿 Spring Boot 对目录下的包进行扫描,读取Bean注解的就通过反射将它实例化,字段value注解就对字段赋值。

实例为均为单例模式,暂时未考虑到多线程冲突的情况。

画成这样了

                           instanite              
+---------------------+                +-------+  
|WinterBootApplication|  +--------->   |  Car  |  
+------+-------------++                +---+---+  
       |             |                     ^      
       |             |          set value  |      
       | read file   |                     |      
       |             |                 +---+----+ 
       v             +---------------> |  @Bean | 
                     | read annotation +--------+ 
   +-----------+     |                            
   | Car.class |     |                            
   +-----------+     |                 +---------+
                     +---------------> |  @Value |
                                       +---------+

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Bean {

}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Value {
    String value();
}

@Bean
class Car {
    @Value("beetle")
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("Car{");
        sb.append("name='").append(name).append('\'');
        sb.append('}');
        return sb.toString();
    }
}

class MyApplication {
    public static void main(String[] args) {
        WinterBootApplication.run(MyApplication.class);
        Car car = (Car) WinterBootApplication.getBean("me.zonghua.spring.concept.ioc.Car");
        Log.d(car);
    }

}

public class WinterBootApplication {
    static Map<String, Object> bucket = new HashMap<String, Object>();
    static List<String> classFilePaths = new ArrayList<String>();

    /**
     * 首字母大写的最优方法
     *
     * @param name
     * @return
     */
    static String captureName(String name) {
        char[] cs = name.toCharArray();
        cs[0] -= 32;
        return String.valueOf(cs);
    }

    static void readClassName(File file) {
        String fileName = file.getName();
        if (file.isDirectory()) {
            File[] files = file.listFiles(new FilenameFilter() {
                public boolean accept(File dir, String name) {
                    if (name.endsWith(".class") && !name.contains("$")) {
                        return true;
                    } else {
                        return false;
                    }
                }
            });
            for (File fileItem : files) {
                readClassName(fileItem);//递归读取类文件
            }
        } else if (file.isFile() && fileName.endsWith(".class") && !fileName.contains("$")) {
            classFilePaths.add(file.getPath());
        }
    }

    static void loadClass(String className) {
        try {
            Class<?> beanClass = Class.forName(className);
            Bean beanAnnotation = beanClass.getAnnotation(Bean.class);

            if (beanAnnotation != null) {//更改有Bean注解的类
                Object bean = beanClass.newInstance();
                Field[] fields = beanClass.getDeclaredFields();//获取所有声明的字段
                for (Field field : fields) {
                    Value valueAnnotation = field.getAnnotation(Value.class);
                    if (valueAnnotation != null) {
                        String value = valueAnnotation.value();
                        String fieldName = field.getName();
                        String setMethodName = "set" + captureName(fieldName);//获取set方法名
                        Log.d("setMethod : " + setMethodName + "(" + value + ")");
                        Method setMethod = beanClass.getMethod(setMethodName, String.class);
                        setMethod.invoke(bean, value);//动态执行
                    }
                }
                bucket.put(className, bean);//存放到容器
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void run(Class clazz) {
        String rootFilePath = clazz.getResource("").getFile();
        String classPath = clazz.getClassLoader().getResource("").getPath();
        classPath = classPath.replace("/", "\\").substring(1, classPath.length() - 1);
        File rootFile = new File(rootFilePath);
        readClassName(rootFile);
        for (String classFilePath : classFilePaths) {
            String className = classFilePath.replace(classPath, "")
                    .replace(".class", "")
                    .replace("\\", ".");
            className = className.substring(1, className.length());
            loadClass(className);
        }
    }

    public static Object getBean(String className) {
        return bucket.get(className);//通过其他设置,可以实现懒加载或者多次实例化而不是单例
    }
}

运行结果

setMethod : setName(beetle)
Car{name='beetle'}

© 著作权归作者所有

共有 人打赏支持
啦啦啦拉拉
粉丝 4
博文 1
码字总数 592
作品 0
广州
程序员
私信 提问
java annotation与AOP点滴积累

spring注解,与依赖注入 (1).类级别的注解:如@Component、@Repository、@Controller 、@Service 以及JavaEE6的@ManagedBean和@Named注解,都是添加在类上面的类级别注解,Spring容器根据注解...

浮云过眼
2016/03/16
72
0
手把手教你实现Spring ioc

手把手教你实现Spring ioc “Don’t call us, we’ll call you(不要联系我,我会主动联系你)” 这是好莱坞很经典的一句话,应用在ioc(控制反转)领域,发现理解起来相得益彰——你作为用户...

loda0128
2015/06/11
0
0
Spring核心——JSR250与资源控制

JSR-175与元编程 要说明JSR-250先要解释清楚JSR-175,要解释清楚JSR就的先了解JCP是什么。网上资料很多,就不细说了,简单的说JCP(Java Community Process)是管理Java生态(包括J2SE、J2E...

随风溜达的向日葵
07/18
0
0
Spring对注解(Annotation)处理源码分析1——扫描和读取Bean定义

1.从Spring2.0以后的版本中,Spring也引入了基于注解(Annotation)方式的配置,注解(Annotation)是JDK1.5中引入的一个新特性,用于简化Bean的配置,某些场合可以取代XML配置文件。开发人员对注...

李长春
2011/10/08
0
0
Spring核心——Stereotype组件与Bean扫描

在注解自动装载中介绍了通过注解(Annotation)自动向Bean中注入其他Bean的方法,本篇将介绍通过注解(Annotation)向容器添加Bean的方法。 Spring的核心容器提供了@Component和@Bean注解来标...

随风溜达的向日葵
07/20
0
0

没有更多内容

加载失败,请刷新页面

加载更多

sed, awk 练习

1. sed打印某行到某行之间的内容 2. sed 转换大小写 将单词首字母转化大写 将所有小写转化大写 3. sed 在某一行最后面添加一个数字 4. 删除某行到最后一行 解析: {:a;N;$!ba;d} :a : 是...

Fc丶
今天
2
0
babel6升级到7,jest-babel报错:Requires Babel "^7.0.0-0", but was loaded with "6.26.3".

自从将前端环境更新到babel7,jest-babel之前是基于babel6的,执行时候就会报:Requires Babel "^7.0.0-0", but was loaded with "6.26.3". 很烦,因为连续帮好几台电脑修复这个问题,所以记...

曾建凯
今天
1
0
探索802.11ax

802.11ax承诺在真实条件下改善峰值性能和最差情况。 如何改善今天的Wi-Fi? 在决定如何改进当前版本以外的Wi-Fi时,802.11ac,IEEE和Wi-Fi联盟调查了Wi-Fi部署和行为,以确定更广泛使用的障碍...

linuxprobe16
今天
2
0
使用linux将64G的SDCARD格式化为FAT32

一、命令如下: sudo fdisk -lsudo mkfs.vfat /dev/sda -Isudo fdisk /dev/sda Welcome to fdisk (util-linux 2.29.2). Changes will remain in memory only, until you decide to wri......

mbzhong
今天
4
0
深入理解Plasma(四):Plasma Cash

这一系列文章将围绕以太坊的二层扩容框架,介绍其基本运行原理,具体操作细节,安全性讨论以及未来研究方向等。本篇文章主要介绍在 Plasma 框架下的项目 Plasma Cash。 深入理解Plasma(1):...

HiBlock
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部