自己动手写spring(三) 支持注解方式
来源:互联网 发布:ubuntu svn 导入源码 编辑:程序博客网 时间:2024/06/05 07:26
前言
本文使用注解方式来读取bean类,并解决bean之间的依赖。其中Component和Value注解直接copy自Spring,Resource注解来自javax。
扫描包中的所有类
还是以前文提到的beanA和beanB两个model类为例(省略set和get方法)。
@Componentpublic class BeanA { @Value("studentA") private String title; @Resource private BeanB beanB;}@Componentpublic class BeanB { @Value("studentB") private String title; }
根据前文,我们可以发现,要实现bean工厂功能,首先要将bean信息加载到内存(由配置文件方式转化为“以类的方式”存储)。
在本文中,虽然配置文件没了,但思路是一致的。我们要根据注解,采集bean信息,存储在map中。注解和配置文件方式的一个不同是:配置文件是配什么bean加载什么,而注解方式,则需要我们扫描目标pacakge中的所有bean。
public class Main { private static Map<String,Class> beanId2Clazz = new HashMap<String,Class>(); // 将一个字符串的首字符小写 private static String smallCaseFirstChar(String prop){ char ch = (char) (prop.charAt(0) + 32); return prop.replaceFirst(prop.charAt(0) + "", ch + ""); } public static void main(String[] args) throws Exception { // 扫描包中包含的类(即扫描目的包所在文件的子文件) String packageName = "org.lqk.lspring.bean"; String rootPath = Main3.class.getResource("/").getPath(); File file = new File(rootPath + File.separator + packageName.replace(".", File.separator)); String[] fileNames = file.list(); // 扫描 for(String fileName : fileNames){ String className = fileName.substring(0,fileName.length() - ".class".length()); String fullClassName = packageName + "." + className; Class clazz = Class.forName(fullClassName); Component cop = (Component) clazz.getAnnotation(Component.class); if(null != cop){ String beanId = cop.value(); if(StringUtils.isEmpty(beanId)){ beanId = smallCaseFirstChar(className); } beanId2Clazz.put(beanId, clazz); } } }}
关于扫描一个包中所有的类,有现成的org.reflections
包,此处为了减少##读者的理解曲线,就不提了。
当加载完bean的信息后,整个步骤已经跟前文很像了。
加载beanB类
public class Main { private static Map<String,Class> beanId2Clazz = new HashMap<String,Class>(); public static void load() throws ClassNotFoundException { // 即为上述的main类 } public static Object getBean(String beanId) throws Exception{ Class clazz = beanId2Clazz.get(beanId); if(null == clazz){ return null; } Object obj = clazz.newInstance(); Field[] fields = clazz.getDeclaredFields(); // 处理带value注解的属性 for(Field field : fields){ Value v = field.getAnnotation(Value.class); if(null == v){ continue; } String propertyValue = v.value(); Method m = clazz.getMethod("set" + bigCaseFirstChar(field.getName()), String.class); m.invoke(obj, propertyValue); } return obj; } public static void main(String[] args) throws Exception { load(); BeanB beanB = (BeanB)getBean("beanB"); System.out.println(beanB.getTitle()); }}
加载beanA类
public class Main2 { private static Map<String,Class> beanId2Clazz = new HashMap<String,Class>(); public static void load() throws ClassNotFoundException { // 不再赘述 } public static Object getBean(String beanId) throws Exception{ Class clazz = beanId2Clazz.get(beanId); if(null == clazz){ return null; } Object obj = clazz.newInstance(); Field[] fields = clazz.getDeclaredFields(); for(Field field : fields){ Method m = clazz.getMethod("set" + bigCaseFirstChar(field.getName()), field.getType()); Value v = field.getAnnotation(Value.class); // 处理value注解 if(null != v){ String propertyValue = v.value(); m.invoke(obj, propertyValue); } Resource r = field.getAnnotation(Resource.class); // 处理resource注解 if(null != r){ String propertyBeanId = r.name(); if(StringUtils.isEmpty(propertyBeanId)){ propertyBeanId = smallCaseFirstChar(field.getType().getSimpleName()); } // 递归处理 Object propertyObj = getBean(propertyBeanId); m.invoke(obj, propertyObj); } } return obj; } public static void main(String[] args) throws Exception { load(); BeanA beanA = (BeanA)getBean("beanA"); System.out.println(beanA.getBeanB().getTitle()); }}
至此,我们已经完全使用注解方式创建了一个bean工厂,下文将会尝试把注解和配置文件两种方式整合到一块儿。
0 0
- 自己动手写spring(三) 支持注解方式
- 自己动手写spring(四) 整合xml与注解方式
- 自己动手写spring(六) 支持FactoryBean
- 自己动手写spring(八) 支持AOP
- 注解(Annotation)自定义注解(三)--自己动手写注解框架(仿xutils)
- 自己动手写操作系统(三)
- 自己动手写操作系统(三)
- 自己动手写操作系统(三)
- 自己动手写俄罗斯方块(三)
- 自己动手写操作系统(三)
- 自己动手写注解
- 自己动手写注解框架
- spring - 自己动手写spring
- Spring学习笔记(三)Spring注解方式实现AOP
- 让spring支持实体类注解方式
- 自己动手写Remoting(三)
- 自己动手写俄罗斯方块(三)
- 自己动手写spring(一) 使用digester
- 最近了解到的东西,做个记录
- 自己动手写spring(二) 创建一个bean工厂
- 选择排序的优化算法
- 天声人語 20151115 パリの無差別テロ
- linux下的进程切换只发生的内核态
- 自己动手写spring(三) 支持注解方式
- java领域的即时通信(openfire+spark+smack)
- OpenGL ES 模型视图矩阵操作
- linux shell 管道命令(pipe)使用及shell重定向
- MyEclipse项目自动部署
- 自己动手写spring(四) 整合xml与注解方式
- JFinal资料
- Python多进程并发操作中进程池Pool的应用
- 日经春秋 20151115