• 自己动手写spring(三) 支持注解方式


    前言

    本文使用注解方式来读取bean类,并解决bean之间的依赖。其中Component和Value注解直接copy自Spring,Resource注解来自javax。

    扫描包中的所有类

    还是以前文提到的beanA和beanB两个model类为例(省略set和get方法)。

    @Component
    public class BeanA {
    	@Value("studentA")
    	private String title;
    	@Resource
    	private BeanB beanB;
    }
    
    @Component
    public 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工厂,下文将会尝试把注解和配置文件两种方式整合到一块儿。

  • 相关阅读:
    Python_day1
    12/04
    Linux基础笔记
    八:动态规划-未名湖边的烦恼
    七:动态规划-数字三角形
    六:大数运算-减法运算
    五:大数运算-加法运算
    四:大数运算-乘法运算
    三:排序-幸运数字
    二:排序-果园
  • 原文地址:https://www.cnblogs.com/qiankunli/p/4943806.html
Copyright © 2020-2023  润新知