自己动手写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工厂,下文将会尝试把注解和配置文件两种方式整合到一块儿。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值