Spring框架的IOC/DI的自己实现

   今天咱们就一起探索spring是怎么完成IOC/DI工作的,也自己做一个简单Spring框架!

Spring中Bean的定义

作用:在spring中使用的bean,都有某些公共属性,此类就是对公共属性的定义

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. public class BeanDefine {    
  2.     
  3.     public String id;    
  4.     public String className;    
  5.     
  6.     public BeanDefine(String id, String className) {    
  7.         this.id = id;    
  8.         this.className = className;    
  9.     }    
  10.     
  11.     public String getId() {    
  12.         return id;    
  13.     }    
  14.     
  15.     public void setId(String id) {    
  16.         this.id = id;    
  17.     }    
  18.     
  19.     public String getClassName() {    
  20.         return className;    
  21.     }    
  22.     
  23.     public void setClassName(String className) {    
  24.         this.className = className;    
  25.     }    
  26.     
  27. }  

2,装配类

2.1,XML装配类

作用:对spring中Xml的配置进行类的装配,实际就是注入
[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. import java.beans.Introspector;    
  2. import java.beans.PropertyDescriptor;    
  3. import java.lang.reflect.Field;    
  4. import java.lang.reflect.Method;    
  5. import java.util.ArrayList;    
  6. import java.util.HashMap;    
  7. import java.util.Iterator;    
  8. import java.util.List;    
  9. import java.util.Map;    
  10. import org.apache.log4j.Logger;    
  11. import org.dom4j.Document;    
  12. import org.dom4j.DocumentException;    
  13. import org.dom4j.Element;    
  14. import org.dom4j.io.SAXReader;    
  15.     
  16. import com.My.Test.TestServiceImpl;    
  17.     
  18. /**  
  19.  * @Description: spring中的注解原理  
  20.  * @ClassName: ClassPathXMLApplicationContext  
  21.  * @Project: MySpring  
  22.  * @Author: xvshu  
  23.  * @Date: 2015年2月28日  
  24.  */    
  25. public class ClassPathXMLApplicationContext {    
  26.     
  27.     Logger log = Logger.getLogger(ClassPathXMLApplicationContext.class);    
  28.     
  29.     List<BeanDefine> beanList = new ArrayList<BeanDefine>();    
  30.     Map<String, Object> sigletions = new HashMap<String, Object>();    
  31.     
  32.     public ClassPathXMLApplicationContext(String fileName) {    
  33.         //读取配置文件中管理的bean    
  34.         this.readXML(fileName);    
  35.         //实例化bean    
  36.         this.instancesBean();    
  37.         //注解处理器    
  38.         this.annotationInject();    
  39.     }    
  40.     
  41.     /**  
  42.      * 读取Bean配置文件  
  43.      * @param fileName  
  44.      * @return  
  45.      */    
  46.     @SuppressWarnings("unchecked")    
  47.     public void readXML(String fileName) {    
  48.         Document document = null;    
  49.         SAXReader saxReader = new SAXReader();    
  50.         try {    
  51.             ClassLoader classLoader = Thread.currentThread().getContextClassLoader();    
  52.             document = saxReader.read(classLoader.getResourceAsStream(fileName));    
  53.             Element beans = document.getRootElement();    
  54.             for (Iterator<Element> beansList = beans.elementIterator(); beansList.hasNext();) {    
  55.                 Element element = beansList.next();    
  56.                 BeanDefine bean = new BeanDefine(    
  57.                         element.attributeValue("id"),    
  58.                         element.attributeValue("class"));    
  59.                 beanList.add(bean);    
  60.             }    
  61.         } catch (DocumentException e) {    
  62.             log.info("读取配置文件出错....");    
  63.         }    
  64.     }    
  65.         
  66.     /**  
  67.      * 实例化Bean  
  68.      */    
  69.     public void instancesBean() {    
  70.         for (BeanDefine bean : beanList) {    
  71.             try {    
  72.                 sigletions.put(bean.getId(), Class.forName(bean.getClassName()).newInstance());    
  73.             } catch (Exception e) {    
  74.                 log.info("实例化Bean出错...");    
  75.             }    
  76.         }    
  77.     }    
  78.         
  79.     /**  
  80.      * 注解处理器  
  81.      * 如果注解ZxfResource配置了name属性,则根据name所指定的名称获取要注入的实例引用,如果注解ZxfResource  
  82.      * 没有配置name属性,则根据属性所属类型来扫描配置文件获取要注入的实例引用  
  83.      *   
  84.      */    
  85.     public void annotationInject(){    
  86.         for(String beanName:sigletions.keySet()){    
  87.             Object bean = sigletions.get(beanName);    
  88.             if(bean!=null){    
  89.                 this.propertyAnnotation(bean);    
  90.                 this.fieldAnnotation(bean);    
  91.             }    
  92.         }    
  93.     }    
  94.         
  95.     /**  
  96.      * 处理在set方法加入的注解  
  97.      * @param bean 处理的bean  
  98.      */    
  99.     public void propertyAnnotation(Object bean){    
  100.         try {    
  101.             //获取其属性的描述    
  102.             PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();    
  103.             for(PropertyDescriptor proderdesc : ps){    
  104.                 //获取所有set方法    
  105.                 Method setter = proderdesc.getWriteMethod();    
  106.                 //判断set方法是否定义了注解    
  107.                 if(setter!=null && setter.isAnnotationPresent(ZxfResource.class)){    
  108.                     //获取当前注解,并判断name属性是否为空    
  109.                     ZxfResource resource = setter.getAnnotation(ZxfResource.class);    
  110.                     String name ="";    
  111.                     Object value = null;    
  112.                     if(resource.name()!=null&&!"".equals(resource.name())){    
  113.                         //获取注解的name属性的内容    
  114.                         name = resource.name();    
  115.                         value = sigletions.get(name);    
  116.                     }else//如果当前注解没有指定name属性,则根据类型进行匹配    
  117.                         for(String key : sigletions.keySet()){    
  118.                             //判断当前属性所属的类型是否在配置文件中存在    
  119.                             if(proderdesc.getPropertyType().isAssignableFrom(sigletions.get(key).getClass())){    
  120.                                 //获取类型匹配的实例对象    
  121.                                 value = sigletions.get(key);    
  122.                                 break;    
  123.                             }    
  124.                         }    
  125.                     }    
  126.                     //允许访问private方法    
  127.                     setter.setAccessible(true);    
  128.                     //把引用对象注入属性    
  129.                     setter.invoke(bean, value);     
  130.                 }    
  131.             }    
  132.         } catch (Exception e) {    
  133.             log.info("set方法注解解析异常..........");    
  134.         }    
  135.     }    
  136.         
  137.     /**  
  138.      * 处理在字段上的注解  
  139.      * @param bean 处理的bean  
  140.      */    
  141.     public void fieldAnnotation(Object bean){    
  142.         try {    
  143.             //获取其全部的字段描述    
  144.             Field[] fields = bean.getClass().getDeclaredFields();    
  145.             for(Field f : fields){    
  146.                 if(f!=null && f.isAnnotationPresent(ZxfResource.class)){    
  147.                     ZxfResource resource = f.getAnnotation(ZxfResource.class);    
  148.                     String name ="";    
  149.                     Object value = null;    
  150.                     if(resource.name()!=null&&!"".equals(resource.name())){    
  151.                         name = resource.name();    
  152.                         value = sigletions.get(name);    
  153.                     }else{    
  154.                         for(String key : sigletions.keySet()){    
  155.                             //判断当前属性所属的类型是否在配置文件中存在    
  156.                             if(f.getType().isAssignableFrom(sigletions.get(key).getClass())){    
  157.                                 //获取类型匹配的实例对象    
  158.                                 value = sigletions.get(key);    
  159.                                 break;    
  160.                             }    
  161.                         }    
  162.                     }    
  163.                     //允许访问private字段    
  164.                     f.setAccessible(true);    
  165.                     //把引用对象注入属性    
  166.                     f.set(bean, value);    
  167.                 }    
  168.             }    
  169.         } catch (Exception e) {    
  170.             log.info("字段注解解析异常..........");    
  171.         }    
  172.     }    
  173.         
  174.     /**  
  175.      * 获取Map中的对应的bean实例  
  176.      * @param beanId  
  177.      * @return  
  178.      */    
  179.     public Object getBean(String beanId) {    
  180.         return sigletions.get(beanId);    
  181.     }    
  182.     
  183.     
  184. }    

2.2,注解装配类

作用:对spring中用注解标记的部分进行注入,就是一个自定义注解
[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. import java.lang.annotation.ElementType;    
  2. import java.lang.annotation.Retention;    
  3. import java.lang.annotation.RetentionPolicy;    
  4. import java.lang.annotation.Target;    
  5.      
  6. // 在运行时执行    
  7. @Retention(RetentionPolicy.RUNTIME)    
  8. // 注解适用地方(字段和方法)    
  9. @Target({ ElementType.FIELD, ElementType.METHOD })    
  10. public @interface ZxfResource {    
  11.     
  12.     //注解的name属性    
  13.     public String name() default "";    
  14. }    

3,配置文件

3.1xml:

[javascript]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encodi  
  2. <beans>      
  3.     <bean id = "TestObject1" class="com.My.Test.TestObject1" />      
  4.     <bean id = "TestObject2" class="com.My.Test.TestObject2" />      
  5.     <bean id = "TestObject3" class="com.My.Test.TestObject3" />      
  6.     <bean id = "TestService" class = "com.My.Test.TestServiceImpl" />      
  7. </beans>   

3.2注解

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. public class TestServiceImpl {    
  2.     
  3.     public TestObject3 TestObject3;    
  4.     public TestObject1 TestObject1;    
  5.     
  6.     // 字段上的注解,可以配置name属性    
  7.     @ZxfResource    
  8.     public TestObject2 TestObject2;    
  9.     
  10.     // set方法上的注解,带有name属性    
  11.     @ZxfResource(name = "TestObject3")    
  12.     public void setUserDao(TestObject3 TestObject3) {    
  13.         this.TestObject3 = TestObject3;    
  14.     }    
  15.     
  16.     // set方法上的注解,没有配置name属性    
  17.     @ZxfResource    
  18.     public void setUser1Dao(TestObject1 TestObject1) {    
  19.         this.TestObject1 = TestObject1;    
  20.     }    
  21.     
  22.     public void show() {    
  23.             
  24.         TestObject1.show1();    
  25.         TestObject2.show2();    
  26.         TestObject3.show();    
  27.             
  28.         System.out.println("调用了TestService方法........");    
  29.             
  30.     }    
  31. }    

4,测试类

和普通spring类一样的写法

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. public static void main(String[] args) {    
  2.         ClassPathXMLApplicationContext path = new ClassPathXMLApplicationContext(    
  3.                 "configAnnotation.xml");    
  4.         TestServiceImpl userService =(TestServiceImpl)path.getBean("TestService");    
  5.         userService.show();    
  6. }  

5,原文博客地址


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值