简单实现Spring框架--注解版

自己写的Spring框架——简单实现IoC容器功能


前几天在网上看了篇帖子,是用xml的方式实现spring的ioc容器,觉得挺有意思的,这边自己试着用注解的形式造了一套轮子。

工程结构

codeing

ScopeType.java

package xyz.tmlh.type;

import org.apache.commons.lang.StringUtils;

/**
 * <p>
 * Description: bean的作用域
 * </p>
 */
public enum ScopeType {

    /**
     * 原型
     */
    PROTOTYPE,
    
    /**
     * 单例
     */
    SINGLETON;
    
    
    public static ScopeType getScopt(String name){
        if(StringUtils.equalsIgnoreCase(name, PROTOTYPE.toString())) {
            return PROTOTYPE;
        }
        return SINGLETON;
    }
}
View Code

 

 Bean.java

/*
 * $Id: Bean.java, 2019年1月15日 下午4:07:10 TianXin Exp $
 * 
 * Copyright (c) 2018 Vnierlai Technologies Co.,Ltd 
 * All rights reserved.
 * 
 * This software is copyrighted and owned by Vnierlai or the copyright holder
 * specified, unless otherwise noted, and may not be reproduced or distributed
 * in whole or in part in any form or medium without express written permission.
 */
package xyz.tmlh.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import xyz.tmlh.type.ScopeType;

/**
 * <p>
 * Description:
 * </p>
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
    
    String name() default "";
    
    ScopeType scope() default ScopeType.SINGLETON;
    
}
View Code

 

 Configuration.java

package xyz.tmlh.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * <p>
 * Description: 用来标注这是一个配置类
 * </p>
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Configuration {

    String value() default "";

}
View Code

 

AnnotationConfigMange.java

package xyz.tmlh.config;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;

import xyz.tmlh.annotation.Bean;
import xyz.tmlh.annotation.Configuration;
import xyz.tmlh.entity.Property;
import xyz.tmlh.type.ScopeType;

public class AnnotationConfigMange{


    /**
     * 读取配置文件并返回读取结果
     * 返回Map集合便于注入,key是每个Bean的name属性,value是对应的那个Bean对象
     * @throws InvocationTargetException 
     * @throws IllegalArgumentException 
     * @throws IllegalAccessException 
     */
    public Map<String, xyz.tmlh.entity.Bean> getConfig(Class<?> clazz) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        Map<String, xyz.tmlh.entity.Bean> map = new HashMap<String, xyz.tmlh.entity.Bean>();
        
        if(!isExistAnnotation(clazz.getAnnotations())) {
            throw new RuntimeException("not found annotation Configuration");
        }
        //获取类中的所有方法
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            Bean beanMethod = method.getAnnotation(Bean.class);
            if(beanMethod != null) {
                xyz.tmlh.entity.Bean bean = new xyz.tmlh.entity.Bean();
                bean.setId(method.getName());
                try {
                    Object newInstance = clazz.newInstance();
                    bean.setObj( method.invoke(newInstance, null));
                    bean.setScope(beanMethod.scope());
                    if(StringUtils.isEmpty(beanMethod.name())) {
                        map.put(method.getName(), bean);
                    }else {
                        map.put(beanMethod.name(), bean);
                    }
                    
                } catch (InstantiationException e) {
                     e.printStackTrace();
                }
            }
        }
        return map;
    }

    private boolean isExistAnnotation(Annotation[] annotations){
        for (Annotation annotation : annotations) {
            if(Configuration.class == annotation.annotationType()) {
                return true;
            }
        }
        return false;
    }
    
}
View Code

  

接口BeanFactory继承图

 

BeanFactory.java

public interface BeanFactory {
    
    Object getBean(String name);
    
    <T>T getBean(Class<T> clazz) throws Exception;
    
    Object createBean(Bean bean);
}

 

 AbstractBeanFactoryHandler.java

 

package xyz.tmlh.support;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import xyz.tmlh.entity.Bean;
import xyz.tmlh.type.ScopeType;


public abstract class AbstractBeanFactoryHandler implements BeanFactory{

    /**
     * 获得读取的配置文件中的Map信息
     */
    protected Map<String, Bean> map;
    
    /**
     * 作为IOC容器使用,放置spring放置的对象
     */
    protected Map<String, Object> context = new HashMap<String, Object>();
    
    public Object createBean(Bean bean) {
        // 创建该类对象
        Object obj = bean.getObj();
        if (obj == null) {
            throw new RuntimeException(bean.getClassName() + "not found");
        }
        return obj;
    }
    
    @Deprecated
    public <T>T getBean(Class<T> clazz) throws Exception {
        throw new RuntimeException("Please use the method getBean(String beanNme)!");
    }
    
    @Deprecated
    public Object getBean(String name) {
        Object bean = context.get(name);
        // 如果为空说明scope不是singleton,那么容器中是没有的,这里现场创建
        if (bean == null) {
            throw new RuntimeException("Named is " + name + " cannot be found in the ioc!");
        }
        return bean;
    }
    
}
View Code

 

 AnnotationConfigApplicationContext.java

package xyz.tmlh.support;

import java.util.Map.Entry;

import org.apache.commons.beanutils.BeanUtils;

import xyz.tmlh.config.AnnotationConfigMange;
import xyz.tmlh.entity.Bean;
import xyz.tmlh.type.ScopeType;

/**
 * <p>
 * Description: 注解版启动
 * </p>
 */
public class AnnotationConfigApplicationContext extends AbstractBeanFactoryHandler {

    public AnnotationConfigApplicationContext(Class<?> clazz) throws Exception {
        AnnotationConfigMange configManager = new AnnotationConfigMange();
        // 1.读取配置文件得到需要初始化的Bean信息
        map = configManager.getConfig(clazz);
        // 2.遍历配置,初始化Bean
        init();
    }

    public void init() {
        for (Entry<String, Bean> en : map.entrySet()) {
            String beanName = en.getKey();
            Bean bean = en.getValue();

            Object existBean = context.get(beanName);
            // 当容器中为空并且bean的scope属性为singleton时
            if (existBean == null && bean.getScope().equals(ScopeType.SINGLETON)) {
                // 根据字符串创建Bean对象
                Object beanObj = createBean(bean);
                // 把创建好的bean对象放置到map中去
                context.put(beanName, beanObj);
            }
        }
    }

    @SuppressWarnings("unchecked")
    public <T> T getBean(Class<T> clazz) throws Exception {
        T bean = null;
        int n = 0;
        for (Entry<String, Object> entry : context.entrySet()) {
            if (entry.getValue().getClass() == clazz) {
                bean = (T)entry.getValue();
                n++;
            }
        }
        if (n == 2) {
            throw new RuntimeException("容器中存在多个" + clazz.getSimpleName());
        }
        if (n == 0) {
            for (Entry<String, Bean> entry : map.entrySet()) {
                if (entry.getValue().getObj().getClass() == clazz) {
                    if (entry.getValue().getScope().equals(ScopeType.PROTOTYPE)) {
                        T newInstance = (T)entry.getValue().getObj().getClass().newInstance();
                        BeanUtils.copyProperties(newInstance, entry.getValue().getObj());
                        return newInstance;
                    }
                    return (T)entry.getValue().getObj();
                }
            }
            throw new RuntimeException("ioc not found " + clazz.getName());
        }

        return bean;
    }

}
View Code

 

 

测试的代码就不发了

 

这里贴上github地址有兴趣的可以看看: https://github.com/tmlh98/start-work-series/tree/master/MySpring

 

posted @ 2019-01-17 19:50  天莫  阅读(310)  评论(0编辑  收藏  举报