實(shí)現(xiàn)Spring的IOC機(jī)制痹屹,當(dāng)然這里面沒有對(duì)類進(jìn)行注解標(biāo)示(類似Spring的@Service看疙,@Configuration,@Controller)痹束,而是對(duì)全部類進(jìn)行裝載,可以自定義注解后通過class.getAnnotations()獲取并篩選裝載讶请。
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.net.JarURLConnection;
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.jar.JarEntry;
import java.util.jar.JarFile;
import com.google.gson.Gson;
public class PackageLoader {
/**類實(shí)例映射**/
private static final Map<Class<?>, Object> MAP = new HashMap<Class<?>, Object>();
public static void main(String[] args) {
try {
String packageName = "com.google";
load(packageName);
Gson o = getBean(Gson.class);
System.out.println(o.getClass().getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 從已經(jīng)裝載的類中獲取指的的實(shí)例
* @param clazz
* @return
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(Class<T> clazz){
Object object = MAP.get(clazz);
return (T) object;
}
/**
* 裝載類
* @param packageName
* @return
* @throws ClassNotFoundException
* @throws InstantiationException
* @throws IllegalAccessException
* @throws IOException
*/
public static void load(String packageName) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException{
List<String> classNames = classNames(packageName);
for(String cn : classNames){
Class<?> clazz = Class.forName(cn);
if(Modifier.isAbstract(clazz.getModifiers()) || Modifier.isInterface(clazz.getModifiers())){//抽象類和接口去掉
continue;
}
Constructor<?>[] dcs = clazz.getDeclaredConstructors();
boolean noArgsConst = false;
for(Constructor<?> c : dcs){
if(c.getParameterTypes().length == 0 && Modifier.isPublic(c.getModifiers())){
noArgsConst = true;
break;
}
}
if(!noArgsConst){//沒有public的無參構(gòu)造方法的去掉
continue;
}
Object object = clazz.newInstance();
MAP.put(clazz, object);
}
}
/**
* 獲取包下面的說有類名
* @param packageName
* @return
* @throws IOException
*/
private static List<String> classNames(String packageName)throws IOException {
String packageDirName = packageName.replace('.', '/');
Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
List<String> classes = new ArrayList<String>();
while(resources.hasMoreElements()){
URL url = resources.nextElement();
String protocol = url.getProtocol();
if("jar".equals(protocol)){//項(xiàng)目引用的第三方j(luò)ar文件
JarFile jar = ((JarURLConnection) url.openConnection()).getJarFile();
classesFromJar(jar, packageName, classes);
}
if("file".equals(protocol)){//項(xiàng)目自身pachage的.class文件
String packagePath = URLDecoder.decode(url.getFile(), "UTF-8");
classesFromFile(packagePath,packageName, classes);
}
}
return classes;
}
/**
* 從自身pachage中的.class獲取類名
* @param packagePath
* @param packageName
* @param classes
*/
private static void classesFromFile(String packagePath,String packageName,List<String> classes){
File dir = new File(packagePath);
if (!dir.exists() || !dir.isDirectory()) {
return;
}
File[] files = dir.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isDirectory() || pathname.getName().endsWith(".class");
}
});
for(File file : files){
if(file.isDirectory()){
classesFromFile(file.getAbsolutePath(), packageName + "." + file.getName(), classes);
}else{
classes.add(packageName + "." + file.getName().replace(".class", ""));
}
}
}
/**
* 從引用的第三方j(luò)ar中的.class獲取類名
* @param jar
* @param packageName
* @param classes
*/
private static void classesFromJar(JarFile jar,String packageName,List<String> classes){
Enumeration<JarEntry> entries = jar.entries();
while(entries.hasMoreElements()){
JarEntry entry = entries.nextElement();
String name = entry.getName();
if(!name.replace("/", ".").startsWith(packageName) || !name.endsWith(".class")){
continue;
}
classes.add(name.replace("/", ".").replace(".class", ""));
}
}
}