论坛首页 编程语言技术论坛

spring深入源码2 简单实现ioc机制 注解形式

浏览 6024 次
精华帖 (1) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2012-03-26   最后修改:2012-03-27

上一篇文章 我用了xml形式 实现自己简单版的spring ioc依赖注入  这节主要利用注解形式实现 和上集内容一样 只是加了读取注解的方法。

 

DAO接口

 

    public interface PersonDao {  
      
        public void add();  
      
    }  

 

 

实现类

 

    package cn.leam.dao.impl;  
      
    import cn.leam.dao.PersonDao;  
      
    public class PersonDaoBean implements PersonDao {  
        public void add(){  
            System.out.println("执行add()方法");  
        }  
    }  

 

 

服务接口

    public interface PersonService {  
      
        public void save();  
      
    }  
 

服务实现类

    public class PersonServiceBean implements PersonService {  
        @LeamResource private PersonDao personDao;  
          
        public PersonDao getPersonDao() {  
            return personDao;  
        }  
      
        public void setPersonDao(PersonDao personDao) {  
            this.personDao = personDao;  
        }  
          
        public void save(){  
            personDao.add();  
        }  
    }  

 

<?xml version="1.0" encoding="UTF-8"?>  
    <beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"       
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context 
<!--需要加上注解-->
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
        
<!--需要加上注解标签-->
<context:annotation-config/>
               <bean id="personDao" class="cn.leam.dao.impl.PersonDaoBean"></bean>  
              <bean id="personService" class="cn.leam.service.impl.PersonServiceBean">  
               <!--这里把xml定义的属性去掉 我们使用注解获取 
                  <property name="personDao" ref="personDao"></property>  -->
              </bean>  
    </beans>  

 

下面模拟spring对xml配置的类进行实例化

 

存放属性的对象

 

    public class prosDefinition {  
        private String name;  
        private String ref;  
          
        public ProsDefinition(String name, String ref) {  
            this.name = name;  
            this.ref = ref;  
        }  
          
        public String getName() {  
            return name;  
        }  
        public void setName(String name) {  
            this.name = name;  
        }  
        public String getRef() {  
            return ref;  
        }  
        public void setRef(String ref) {  
            this.ref = ref;  
        }  
          
    }  

 

存放bean的 对象

 

    public class Definition {  
        private String id;  
        private String className;  
        private List<ProsDefinition> propertys = new ArrayList<ProsDefinition>();  
          
        public Definition(String id, String className) {  
            this.id = id;  
            this.className = className;  
        }  
        public String getId() {  
            return id;  
        }  
        public void setId(String id) {  
            this.id = id;  
        }  
        public String getClassName() {  
            return className;  
        }  
        public void setClassName(String className) {  
            this.className = className;  
        }  
        public List<PropertyDefinition> getPropertys() {  
            return propertys;  
        }  
        public void setPropertys(List<PropertyDefinition> propertys) {  
            this.propertys = propertys;  
        }  
          
    }  

 

加上注解

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
public @interface LeamResource {
	public String name() default "";
}
 

 

这里是关键点  所有代码都在这里    使用dom4j 解析xml文件中的bean  并获取id和class  再判断元素中是否有引用元素对其一并获取出来存放才Map中 利用java反射一个一个进行实例化

 

    /** 
     * 学习版容器 
     * 
     */  
    public class LeamClassPathXMLApplicationContext {  
        private List<Definition> beanDefines = new ArrayList<Definition>();  
        private Map<String, Object> sigletons = new HashMap<String, Object>();  
          
        public LeamClassPathXMLApplicationContext(String filename){  
            this.readXML(filename);  
            this.instanceBeans();  
            this.annotationInject();
            this.injectObject();  
        }  
        /** 
         * 为bean对象的属性注入值 
         */  
        private void injectObject() {  
            for(Definition beanDefinition : beanDefines){  
                Object bean = sigletons.get(beanDefinition.getId());  
                if(bean!=null){  
                    try {  
                        PropertyDescriptor[] ps = 
                                  Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();  
                        for(ProsDefinition propertyDefinition : beanDefinition.getPropertys()){  
                            for(PropertyDescriptor properdesc : ps){  
                                if(propertyDefinition.getName().equals(properdesc.getName())){  
                                    Method setter = properdesc.getWriteMethod();//获取属性的setter方法 
                                    if(setter!=null){  
                                        Object value = sigletons.get(propertyDefinition.getRef());  
                                        setter.setAccessible(true);  
                                        setter.invoke(bean, value);//把引用对象注入到属性  
                                    }  
                                    break;  
                                }  
                            }  
                        }  
                    } catch (Exception e) {  
                    }  
                }  
            }  
        }  
        /** 
         * 完成bean的实例化 
         */  
        private void instanceBeans() {  
            for(Definition beanDefinition : beanDefines){  
                try {  
                    if(beanDefinition.getClassName()!=null && !""
                                          .equals(beanDefinition.getClassName().trim()))  
                                  sigletons.put(beanDefinition.getId(),   
                                      Class.forName(beanDefinition.getClassName()).newInstance());  
                } catch (Exception e) {  
                    e.printStackTrace();  
                }  
            }  
              
        }  
        /** 
         * 读取xml配置文件 
         * @param filename 
         */  
        private void readXML(String filename) {  
               SAXReader saxReader = new SAXReader();     
                Document document=null;     
                try{  
                 URL xmlpath = this.getClass().getClassLoader().getResource(filename);  
                 document = saxReader.read(xmlpath);  
                 Map<String,String> nsMap = new HashMap<String,String>();  
                 nsMap.put("ns","http://www.springframework.org/schema/beans");//加入命名空间  
                 XPath xsub = document.createXPath("//ns:beans/ns:bean");//创建beans/bean查询路径  
                 xsub.setNamespaceURIs(nsMap);//设置命名空间  
                 List<Element> beans = xsub.selectNodes(document);//获取文档下所有bean节点   
                 for(Element element: beans){  
                    String id = element.attributeValue("id");//获取id属性值  
                    String clazz = element.attributeValue("class"); //获取class属性值          
                    Definition beanDefine = new Definition(id, clazz);  
                    XPath propertysub =  element.createXPath("ns:property");  
                    propertysub.setNamespaceURIs(nsMap);//设置命名空间  
                    List<Element> propertys = propertysub.selectNodes(element);  
                    for(Element property : propertys){                    
                      String propertyName = property.attributeValue("name");//元素内部引用的属性也获取  
                        String propertyref = property.attributeValue("ref");  
                     ProsDefinition propertyDefinition = new ProsDefinition(propertyName, propertyref);  
                        beanDefine.getPropertys().add(propertyDefinition);  
                    }  
                    beanDefines.add(beanDefine);  
                 }   
                }catch(Exception e){     
                    e.printStackTrace();  
                }  
        }  
        /** 
         * 获取bean实例 
         * @param beanName 
         * @return 
         */  
        public Object getBean(String beanName){  
            return this.sigletons.get(beanName);  
        }  
    }  



       /**
	 * 通过注解实现注入依赖对象
	 */
	private void annotationInject() {
		for(String beanName : sigletons.keySet()){
			Object bean = sigletons.get(beanName);
			if(bean!=null){
				try {
					PropertyDescriptor[] ps =
                                  Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
					for(PropertyDescriptor properdesc : ps){
						Method setter = properdesc.getWriteMethod();//获取属性的setter方法
                                                 //如果是用了注解 将在set方法注入进去
						if(setter!=null && setter.isAnnotationPresent(LeamResource.class)){
							LeamResource resource = setter.getAnnotation(LeamResource.class);
							Object value = null;
							if(resource.name()!=null && !"".equals(resource.name())){
								value = sigletons.get(resource.name());
							}else{
								value = sigletons.get(properdesc.getName());
								if(value==null){
									for(String key : sigletons.keySet()){
										if(properdesc.getPropertyType().
                                     isAssignableFrom(sigletons.get(key).getClass())){
											value = sigletons.get(key);
											break;
										}
									}
								}								
							}
							setter.setAccessible(true);允许访问私有字段
							setter.invoke(bean, value);//把引用对象注入到属性
						}
					}
					Field[] fields = bean.getClass().getDeclaredFields();
					for(Field field : fields){
						if(field.isAnnotationPresent(LeamResource.class)){
							LeamResource resource = field.getAnnotation(LeamResource.class);
							Object value = null;
							if(resource.name()!=null && !"".equals(resource.name())){
								value = sigletons.get(resource.name());
							}else{
								value = sigletons.get(field.getName());
								if(value==null){
									for(String key : sigletons.keySet()){
										if(field.getType().
                                 isAssignableFrom(sigletons.get(key).getClass())){
											value = sigletons.get(key);
											break;
										}
									}
								}								
							}
							field.setAccessible(true);//允许访问private字段
							field.set(bean, value);
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

 

 

 

    public class SpringTest {  
      
        @BeforeClass  
        public static void setUpBeforeClass() throws Exception {  
        }  
      
        @Test public void instanceSpring(){  
            LeamClassPathXMLApplicationContext ctx = new  
                                          LeamClassPathXMLApplicationContext("beans.xml");  
            PersonService personService = (PersonService)ctx.getBean("personService");  
            personService.save();         
        }  
    }  

 

 

最终输出

 

"执行add()方法" 说明实例化成功  否则 出现空指针异常。

 

下节将 aop细节,spring初始化进行分析。

   发表时间:2012-03-28  
很好,但是为什么又不把代码贴全一些呢,还是需要哪些额外JAR包也说一下吧。。。最好还是吧完整代码打包下。。。
0 请登录后投票
   发表时间:2012-03-30  
很好,理解的可以a
0 请登录后投票
   发表时间:2012-03-30  
问一下啊,这个bean的实例化是applicationContext实例化的时候一次全部加载的吗?
而不是什么时候需要bean的实例的时候才加载?
0 请登录后投票
   发表时间:2012-03-30  
b87936260 写道
问一下啊,这个bean的实例化是applicationContext实例化的时候一次全部加载的吗?
而不是什么时候需要bean的实例的时候才加载?



如果需要用到才实例化  可以加上延迟属性  lazy-init="true"
0 请登录后投票
   发表时间:2012-03-30  
liguocai2009 写道
很好,但是为什么又不把代码贴全一些呢,还是需要哪些额外JAR包也说一下吧。。。最好还是吧完整代码打包下。。。




源码 附件中
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics