小型IOC框架的实现
首先要明白IOC框架要实现什么功能
1.依赖倒转
2.使用注解
下面是一个Action
@Bean public class BaseAction { @Inject private TestService testService; @Request public void print(){ System.out.println("print method run..."); testService.print(); } }
这个Action用到了三个注解
@Bean标注这是一个Action
@Inject标注着是需要注入的属性
思路:先想一下Spring是怎么来实现的,先在xml文件中定义好使用注解的路径或者Bean类,然后在根据这个路径进行整个项目的扫描,如下
<context:component-scan base-package="com.zhyonk.blablabla" />
那么问题来了,怎么根据这个com.zhyonk.action来扫描呢?
应该是获取到项目所在系统中的路径,再拼接字符串,最后拼接出来的应该是在系统中的据对路径。
那么先用"C:/dev/workspace/Eclipseworkspace/zhyonk/bin/mvc/zhyonk/action"来代替
首先扫描这个目录下所有的以.class结尾的文件并存起来
然后获取所有的用@Bean注解的类。将这些类和类的实例存到Map中,因为本质上Spring的IOC容器也是用Map来存储需要托管的类
问题又来了,怎么获取所有的包含@Bean的类呢?
对,利用反射获取,利用之前存储的.class信息的文件集合,对文件名进行字符串的分割来获取类的完整类名
根据这个完整类名。利用Class.forName()来进行类的初始化。最终存储到Map(Class<?>,Object)中
获取到包含@Bean注解的类了,之后要在这些类中扫描注入点,也就是@Inject注解的属性。
这个也是利用反射,获取到到所有的Field,再调用field.isAnnotationPresent(Inject.class)来判断是否有@Inject注解
好了,现在找到的类既有@Bean注解,又有@Inject注解。接下来就是注入了。
那么又得扫描了,Spring可以直接用BeanNameProxyCreator进行动态的代理,
<bean id="BeanProxy"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<!-- 对类名以ServiceImpl结尾的、标注的类进行代理, -->
<value>*ServiceImpl</value>
</property>
<!-- 对代理类进行加载拦截器(实现通知的过程) -->
<property name="interceptorNames">
<list>
<!-- 该值和拦截器的id保持一致 -->
<value>transactionInterceptor</value>
</list>
</property>
</bean>
实现起来太麻烦了,我还是先用之前的路径来代替。在那个目录下扫描
先判断有没有TestService这个类
@Inject
private TestService testService;
在判断有没有TestService的子类。
在Spring中注入接口只能有一个子类,要是多个的话会直接报错的。
怎么判断哪个类是注入接口的子类呢?
父类好判断,子类得自己去找。首先的有一个范围。对就是首先确定在哪扫,就用之前的那个路径吧
扫描到所有的类再判断
/** * 根据接口获取该接口的子类 * @param interfacetype */ public static Class<?> getClassListByInterface(Class<?> interfacetype,String ImplPath) { List<Class<?>> list1 = new ArrayList<Class<?>>(); File[] scanClassFile = scanClassFile(ImplPath); //这样比较麻烦,但就先这样吧 List<Class<?>> allClassFile = null; try { allClassFile = getAllClassFile(scanClassFile); } catch (ClassNotFoundException e) { System.out.println("找实现子类的时候在目录下没有找到类哦"); e.printStackTrace(); } //遍历指定目录下的所有的类 for (Class<?> class1 : allClassFile) { Class<?>[] interfaces = class1.getInterfaces(); String supername = interfacetype.getName(); //遍历类所有的父类 for (Class<?> superclass : interfaces) { //判断父类有没有interfacetype类型的 if(superclass.getName().equals(supername)){ //添加子类的到list中 list1.add(class1); } } } //判断有几个子类,就先返回第一个子类吧 //如果子类数量大于1个 if(list1.size()>1){ System.out.println("抱歉目前只支持返回一个子类"); return list1.get(0); }else{ return list1.get(0); } }
返回的是一个Class<?>类型的,因为之需要一个子类
哦了,实例需要注入的接口子类对象,用反射注入到之前的Map<Class<?>,Object>中
Object object =subclass.newInstance(); field.setAccessible(true); field.set(value,object);
再提供一个依据类获取对象的方法
public static Object getBean(Class<?> clazz) { return beanmap.get(clazz); }
完成了
重要的是明白其中的思想!
源码在
https://github.com/zhyonk/Zhyonk
打算写一个MVC框架,刚把IOC容器写好!!