一. (不喜欢勿喷,还在大学阶段 今后有高人指点的话 会修改写的更好 谢谢支持)
编写自己的 MyClassUtils 主要用于获取一个包名下的所有.class,接口的不回获取到
package cn.edu.hbpu.util;
import java.io.*;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
public class MyClassUtils
{
/**
* 加载所有的class文件
* @param packageName 包名
* @return class list集合
*/
public static List<Class<?>> getClasses(String packageName)
{
List<Class<?>> allClass = new ArrayList<Class<?>> ();
// 获取包的名字 并进行替换 比如 cn.edu.hbpu -> cn/edu/hbpu
String packageDirName = packageName.replace('.', '/');
try
{
//得到物理文件url路径
URL resource = Thread.currentThread ().getContextClassLoader ().getResource (packageDirName);
//得到物理文件具体路径
// ********一定要注意 指定编码格式获取,不然会出错*******
String filePath = URLDecoder.decode(resource.getFile(), "UTF-8");
//递归循环该文件下的所有 class文件 反射Class.forName 添加到集合中
listPackage (filePath,packageName,allClass);
} catch (Exception e)
{
e.printStackTrace ();
}
return allClass;
}
/**
*
* @param filePath 物理地址
* @param allClass
*/
public static void listPackage(String filePath, String packageName, List<Class<?>> allClass)
{
//创建文件 filePath: /D:/Intellij%20IEDA/IDEAworkSpace2/SpringIOC/target/classes/cn/edu/hbpu
File file = new File (filePath);
//判断该文件是否是一个文件夹,是否存在 如果不是 报异常
if ( !file.isDirectory() || !file.exists ()) {
return;
}
/**
* 过滤文件夹 把是文件夹的或者以.class结尾的文件都提取出来
*/
File[] files = file.listFiles (new FileFilter ()
{
@Override
public boolean accept(File file)
{
return (file.isDirectory ()) || file.getName ().endsWith (".class");
}
});
//遍历 cn.edu.hbpu 下的所有文件
for(File everyFile:files)
{
if(everyFile.isDirectory ())
{
//传入文件的 具体地址 和相应的包名
listPackage (everyFile.getAbsolutePath (),packageName+"."+everyFile.getName (), allClass);
}
//代表 是普通的.class文件
else {
//得到文件的全限定类名 比如 cn.edu.hbpu.service.ProductServiceImpl
String classAllName=packageName+"."+everyFile.getName ().substring (0,everyFile.getName ().length ()-6);
try
{
//添加到集合中
Class<?> everyClass = Class.forName (classAllName);
/**
* 如果是接口类型,就直接省略
* 把不是接口类型的扫描进去
*/
if(!everyClass.isInterface ())
{
allClass.add (everyClass);
}
} catch (ClassNotFoundException e)
{
e.printStackTrace ();
}
}
}
}
}
二.开始实现自己的IOC
1.包名属性
2.map集合 ->ioc容器
3.构造方法要初始化ioc容器 并且要 扫描包把加了MyCompoment注解的类实例化再加入到spring 容器中。
// 扫描包的路径
private String packageName;
//spring容器
private ConcurrentHashMap<String, Object> ioc;
public MySpringIOC(String packageName) throws Exception
{
this.packageName = packageName;
//实例化ioc容器
ioc = new ConcurrentHashMap<String, Object> ();
//初始化bean 把所有加了注解的bean加载到ioc容器中
initBean ();
}
initBean:
/**
* 初始化bean容器 准备工作
*/
private void initBean() throws Exception
{
/**
* 扫描该包下的所有.class文件 反射得到所有的class文件
*/
List<Class<?>> classes = MyClassUtils.getClasses (this.packageName);
//得到加了MyCompoment注解的集合
List<Class<?>> anncotaionedClasses = findClassIsPreAnnoctation (classes);
//根据anncotaionedClasses 开始实例化bean (反射实现的)
newInstanceBean (anncotaionedClasses);
//实现AutoWired功能 也就是依赖注入
autoWiredBeanByName();
}
findClassIsPreAnnoctation :
/**
* 返回被注解申明的 class 这里就是被MyCompoment修饰的类
*
* @param classes
* @return
*/
private List<Class<?>> findClassIsPreAnnoctation(List<Class<?>> classes)
{
//加了注解的集合
List<Class<?>> annoctationPresentClasses = new ArrayList<> ();
for (Class clazz : classes)
{
//判断是否加了MyCompoment注解
if (clazz.isAnnotationPresent (MyCompoment.class))
{
//添加到容器中
annoctationPresentClasses.add (clazz);
continue;
}
}
return annoctationPresentClasses;
}
两个注解类:
package spring;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定义注解
*/
@Target(value = { ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface MyCompoment
{
/**
* 给bean申明一个bean id 默认为空
* @return
*/
String beanName() default "";
}
package spring;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 只能用于属性上面 ElementType.FIELD
*/
@Target(value = { ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAutoWired
{
}
newInstanceBean:方法
/**
* 反射实例化bean
*/
private void newInstanceBean(List<Class<?>> anncotaionedClasses) throws Exception
{
//没有空参构造器的 clazz 等有空参构造器的初始化完了再初始化
List<Class<?>> nullConstructor = new ArrayList<> ();
for (Class clazz : anncotaionedClasses)
{
//判断是否有空参构造方法,有的话直接初始化,没有的话放置到后面
Constructor constructor = clazz.getConstructor ();
if (constructor == null)
{
anncotaionedClasses.remove (clazz);
nullConstructor.add (clazz);
continue;
}
//反射实例化
Object o = clazz.newInstance ();
// 获取 类名即可
String className = toLowerCaseFirstOne (clazz.getSimpleName ());
String beanId = toLowerCaseFirstOne (className);
//添加到ioc容器中
ioc.put (beanId,o);
}
//单独初始化 有参构造的bean (这里我还未实现 等待以后实现)
}
// 首字母转小写
public static String toLowerCaseFirstOne(String s)
{
if (Character.isLowerCase (s.charAt (0)))
{
return s;
}
else
{
return (new StringBuilder ()).append (Character.toLowerCase (s.charAt (0))).append (s.substring (1)).toString ();
}
}
autoWiredBeanByName
依赖注入的实现,也就是被MyAutoWired注解修饰的字段
/**
* 实现AutoWired功能,依赖注入
* 注意这个只是根据名字注入
*/
private void autoWiredBeanByName() throws Exception
{
Set<Map.Entry<String, Object>> iocSet = ioc.entrySet ();
for(Map.Entry entry : iocSet)
{
//得到每一个bean对象 实现依赖注入
Object diObj = entry.getValue ();
Field[] declaredFields = diObj.getClass ().getDeclaredFields ();
for (Field field : declaredFields)
{
//如果是被 MyAutoWired 修饰的字段则进行赋值
if(field.isAnnotationPresent (MyAutoWired.class))
{
String fieldName = field.getName ();
Object bean = this.ioc.get (fieldName);
if(bean!=null)
{
// 私有访问允许访问
field.setAccessible (true);
// 给属性赋值
field.set(diObj, bean);
continue;
}
}
}
}
}
最后 实验的类加上去 ProductServiceImpl 和 ProductDao
package cn.edu.hbpu.service;
import cn.edu.hbpu.dao.ProductDao;
import spring.MyAutoWired;
import spring.MyCompoment;
@MyCompoment
public class ProductServiceImpl implements ProductService
{
@MyAutoWired
private ProductDao productDao;
public void addProduct()
{
System.out.println ("ProductServiceImpl 添加商品");
productDao.addProduct ();
}
}
package cn.edu.hbpu.dao;
import spring.MyCompoment;
@MyCompoment
public class ProductDao
{
public void addProduct()
{
System.out.println ("dao层实现");
}
}
获取的代码
/**
* 返回ioc容器
* @return
*/
public ConcurrentHashMap getIOC()
{
return this.ioc;
}
/**
* 根据id获取bean
* @param beanId id
* @return
*/
public Object getBeanById(String beanId)
{
return ioc.get (beanId);
}
测试
public class MyIOCTest
{
public static void main(String[] args) throws Exception
{
/* List<Class<?>> classes = MyClassUtils.getClasses ("cn.edu.hbpu");
for (Class clazz : classes)
{
System.out.println (clazz.getSimpleName ());
}*/
MySpringIOC mySpringIOC = new MySpringIOC ("cn.edu.hbpu");
ProductServiceImpl productServiceImpl = (ProductServiceImpl)mySpringIOC.getBeanById ("productServiceImpl");
productServiceImpl.addProduct ();
}
}
最终效果图