这个版本中我自定义了一个配置文件,并在其中定义了需要扫描的包,然后对包中的文件进行自动注入。个人感觉这和spring的IOC模型已经很像了,提供一个xml给用户进行配置,其余事情都交给容器进行管理
上代码
package com.kevindai.testioc;
import org.springframework.beans.factory.annotation.Autowired;
public class PrivateCar {
private String color;
@Autowired
private Engine engine;
private Integer i;
protected void drive(){
System.out.println("drive my " + color + " car!");
System.out.println("THE engine brand : " + engine.brand);
System.out.println("init int " + i);
}
}
package com.kevindai.testioc;
public class Engine {
public static String brand = "benz";
}
XML配置(这个可以理解为是applicationContext.xml)
<?xml version="1.0" encoding="UTF-8"?>
<xml-body>
<component-scan>
<value>com.kevindai.testioc.*</value>
</component-scan>
</xml-body>
package com.kevindai.test;
import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
public class AbstactReflect {
@SuppressWarnings("unchecked")
public static void main(String[] args) throws Exception {
//通过jdom解析自定义的XML,来获取要加载哪些类
ResourcePatternResolver rl = new PathMatchingResourcePatternResolver();
Resource resource = rl.getResource("classpath:myioc.xml");
File myiocXml = resource.getFile();
SAXBuilder saxBuilder = new SAXBuilder();
Document doc = saxBuilder.build(myiocXml);
Element root = doc.getRootElement();
List<Element> allChildren = root.getChildren();
for(Element e : allChildren){
//获取配置好的要扫描的路径
String packageDirName = e.getChild("value").getText();
if(packageDirName.endsWith(".*")){
packageDirName = packageDirName.substring(0,packageDirName.indexOf(".*"));
}
//因配置中配置的都是类似com.kevindai.**的,因此要把.换成*
String packagePathName = packageDirName.replace(".", "/");
resource = rl.getResource("classpath:/" + packagePathName);
File dir = resource.getFile();
if(!dir.exists()){
System.out.println("can't not find " + packageDirName + " in myioc.xml");
}else{
File[] fileList = dir.listFiles();
//获取配置文件中配置的要扫描的包下面的所有class文件
for(File file : fileList){
//通过反射机制获取类、方法
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Class<?> clazz = cl.loadClass(packageDirName + "." + file.getName().substring(0,file.getName().indexOf(".class")));
Object o = clazz.newInstance();
Field[] fields = clazz.getDeclaredFields();
for(Field f : fields){
//这一步的意义是找到有注解的属性,并完成自动找到该属性对应的实体,并完成注入
//这里其实可以自定义注解,然后用扫描到自定义注解的属性才去注入,但我这里只是演示,因此不做自定义注解及后续判断
Annotation[] annotation = f.getDeclaredAnnotations();
if(annotation.length > 0){
if(!f.isAccessible()){
f.setAccessible(true);
}
//找到当前属性的类型并新建一个对象赋值给属性(类似spring注入一个实体)
Class<?> cla = f.getType();
Object object = cla.newInstance();
//这样注入有一个问题,当属性没有无参构造函数(如Integer)时会有问题,且不用对基本数据类型这样注入
f.set(o,object);
}
}
Method[] methods = clazz.getDeclaredMethods();
for(Method m :methods){
if(!m.isAccessible()){
m.setAccessible(true);
}
//反射机制制定方法参数类型
Class<?>[] cla = m.getParameterTypes();
Object[] methodArgs = new Object[m.getParameterTypes().length];
int i = 0;
for(Class<?> c : cla){
methodArgs[i] = c.cast(c.newInstance());
i++;
}
m.invoke(o,methodArgs);
}
}
}
}
}
}
只想对自己刷一行6
***************分割线******************
666666666666666666666666666666666