自己实现的Spring反转控制和依赖注入

实现目的:能根据xml配置文件或者注解的方式实现bean的实例化和属性注入。
实现原理:读取xml文件,根据配置,处理注解,利用反射技术实现以上目的。
说明:实现的比较粗糙,只是为了自己加深对Spring的某个方面的理解。

package com.spring.core;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

public class Spring
{
        
	private String[] configFiles;
	
	private Map<String,Bean> beanMap = new HashMap<String,Bean>();
	
	private Map<String,Object> objectMap = new HashMap<String,Object>();
	
	private List<String> classList = new ArrayList<String>();
	
	private Scan scan;
	
	private boolean resource;
	
	
	
	public Spring(String[] configFiles)
	{
		this.configFiles = configFiles;
		init();
	}
	
	public Spring(String configFile)
	{
		this(new String[]{configFile});
		
	}
	
	private void init()
	{
		loadConfigFiles();
		
		scan();
		
		instanceObject();
	}
	
	//扫描spring.xml,将xml中的节点全部保存.
	private void loadConfigFiles()
	{
		if (null == this.configFiles)
			return;
		
		for(String configFile : this.configFiles)
		{
			SAXReader reader = new SAXReader();
			InputStream ins = this.getClass().getClassLoader().getResourceAsStream(configFile);
			try {
				Document dom = reader.read(ins);
				Element rootEle = dom.getRootElement();
				List<Element> elements = rootEle.elements();
				
				for(Element element : elements)
				{
					String elementName = element.getName();
					if("bean".equals(elementName))
					{
						String id = element.attributeValue("id");
						String className = element.attributeValue("class");
						String scope = element.attributeValue("scope");
						
						List<Element> propEles = element.elements("property");
						Properties properties = new Properties();
						if ( propEles.size() != 0)
						{
							for(Element propEle : propEles)
							{
								String key = propEle.attributeValue("name");
								String value = propEle.attributeValue("ref");
								
								properties.put(key, value);
							}
						}
						
						beanMap.put(id, new Bean(id,className,scope,properties));
					}
					
					if ("scan".equals(elementName))
					{
						String[] packages = element.attributeValue("package").split(",");
						this.scan = new Scan(true,packages);
					}
					
					if ("resource".equals(elementName))
					{
						this.resource = true;
					}
				}
			} catch (DocumentException e) {
				//
			}
		}
	}
	
	//如果有scan元素,则为指定的包下标明service,controller注解的类管理对象。
	private void scan()
	{
		if (this.scan == null || !this.scan.isScan())
			return;
		
		String[] packages = this.scan.getPackages();
		
		for(String packageName : packages)
		{
			scanClassFromPackage(packageName.replace(".", "/"));
			
		}
		
		for(String className : this.classList)
		{
			try {
				Class<?> clazz = Class.forName(className);
				com.spring.core.Service service = clazz.getAnnotation(com.spring.core.Service.class);
				if(null != service)
				{
					String id = className.replace(".", "/");
					id =id.split("/")[id.split("/").length-1];
					id = id.substring(0,1).toLowerCase() + id.substring(1);
					
					this.beanMap.put(id, new Bean(id,className,"singleton",null));
				}
				
			} catch (ClassNotFoundException e) {
				//
			}
		}
	}
	
	//对指定的类名,扫描其属性和setter方法,为其属性注入值。
	private void resource(Bean bean)
	{
		if (null == bean)
			return;
		
		try {
			Class<?> clazz = Class.forName(bean.getClassName());
			Field[]  fields = clazz.getDeclaredFields();
			for(Field field : fields)
			{
				Resource resouce = field.getAnnotation(Resource.class);
				if(null != resouce)
				{
					if(null == bean.getProperties())
						bean.setProperties(new Properties());
					
					bean.getProperties().put(field.getName(), "resource:" + field.getType().getName());
				}
			}
			
		} catch (ClassNotFoundException e) {
			//
		}
	}
	
	
	//递归扫描包下的类
	private void scanClassFromPackage(String resourceName)
	{
		try {
			Enumeration<URL> dirs = Thread.currentThread().getContextClassLoader().getResources(resourceName);
			while(dirs.hasMoreElements())
			{
				URL url = dirs.nextElement();
				String filePath = URLDecoder.decode(url.getFile(),"utf-8");
				File file = new File(filePath);
				
				if(!file.isDirectory())
				{
					if(filePath.endsWith(".class"))
					{
						String className = resourceName.replace("/", ".").replaceAll(".class", "");
						this.classList.add(className);
					}
				}else
				{
					File[] files = file.listFiles();
					for(File subfile : files)
					{
						String subresourceName = resourceName.replace("/", "\\");
						subresourceName =  subresourceName + "/" + subfile.getName().split(subresourceName)[subfile.getName().split(subresourceName).length-1];
						subresourceName = subresourceName.replace("\\", "/");
						scanClassFromPackage(subresourceName);
					}
				}
			}
			
		} catch (IOException e) {
			//
		}
	}
	
	//将所有配置在spring。xml中的bean,生成对象并注入属性对象.
	private void instanceObject()
	{
		if (beanMap.isEmpty())
			return;
		
		for(String key : beanMap.keySet())
		{
			Bean bean = beanMap.get(key);
			try {
				if(bean.getScope() != null && !"singleton".equals(bean.getScope()))
					continue;
				
				 Object obj = Class.forName(bean.getClassName()).newInstance();
				 if(this.resource)
					 resource(bean);
				 
				 setProperties(obj,bean.getProperties());
				 this.objectMap.put(key, obj);
				
			} catch (Exception e){
				//
			}
		}
	}
	
	//根据id取得实例
	public Object getInstance(String id)
	{
		if(null == id)
			return null;
		
		Bean bean = beanMap.get(id);
		if(null == bean)
			return null;
		
		if(null == bean.getScope() || "singleton".equals(bean.getScope()))
			return objectMap.get(id);
		
		try {
			return Class.forName(bean.getClassName()).newInstance();
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException();
		}
	}
	
	
	private void setProperties(Object obj,Properties proerties)
	{
		if (null == obj || null == proerties)
			return;
		
		Method[] methods = obj.getClass().getDeclaredMethods();
		for(Method method : methods)
		{
			if(!method.getName().startsWith("set"))
				continue;
			
			String methodName = method.getName();
			String key = methodName.replace("set", "");
			key = key.substring(0, 1).toLowerCase() + key.substring(1);

			String ref = (String)proerties.get(key);
			if(null == ref)
				continue;
			
			try {
				Object object = null;
				if(ref.startsWith("resource:"))
				{
					object = Class.forName(ref.replaceFirst("resource:", "")).newInstance();
				}else
				{
					object = getInstance(ref);
				}
				
				method.invoke(obj, object);
			} catch (Exception e) {
				//
			}
		}
	}
}

你可能感兴趣的:(spring)