实现目的:能根据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) {
//
}
}
}
}