• 【SSH进阶之路】一步步重构容器实现Spring框架——彻底封装,实现简单灵活的Spring框架(十一)


    目录
         【SSH进阶之路】一步步重构容器实现Spring框架——从一个简单的容器开始(八)
         【SSH进阶之路】一步步重构容器实现Spring框架——解决容器对组件的“侵入式”管理的两种方案--主动查找和控制反转(九)
         【SSH进阶之路】一步步重构容器实现Spring框架——配置文件+反射实现IoC容器(十)
         【SSH进阶之路】一步步重构容器实现Spring框架——彻底封装,实现简单灵活的Spring框架(十一)


          博文【SSH进阶之路】一步步重构容器实现Spring框架——从一个简单的容器开始(八),我们为了去掉接口对具体实现的依赖关系,封装了一个特别简陋的容器。
          博文【SSH进阶之路】一步步重构容器实现Spring框架——解决容器对组件的“侵入式”管理的两种方案--主动查找和控制反转(九),我们利用控制反转,去掉了组件对容器的依赖。

          博文【SSH进阶之路】一步步重构容器实现Spring框架——配置文件+反射实现IoC容器(十),我们实现了读取配置文件,以及容器创建对象的灵活,简单的IoC。

      

          这篇博文的目标是不仅形似Spring,而且要神似Spring,进一步封装对象的依赖关系

          我们知道Spring框架,不仅可以根据配置创建对象,而且可以根据配置创建对象之间的依赖关系。对象之间的依

    赖关系怎么配置呢,那我们先看一下配置文件。

    <?xml version="1.0" encoding="UTF-8"?>
    <beans>
    
      <bean id="dao" class="com.tgb.container.dao.impl.Dao4MySqlImpl" />
      
      <bean id="service" class="com.tgb.container.service.impl.ServiceImpl">
      	<property name="dao" ref="dao"></property>
      </bean>
    	
    </beans>

          我们发现配置文件中多了两个属性:property和ref,表达了Service需要依赖Dao的关系,所以我们需要将dao注入

    给Service,怎么做呢?我们只需要像存储bean一样建立一个JavaBean即可:

    public class PropertyDefinition {
    
    	private String name;
    	private String ref;
    
    	public PropertyDefinition(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;
    	}
    	
    }

          有了javabean,我们就只需要专注于怎么为bean对象的属性注入值。我们可以利用内省来操作Bean类属性、事

    件。一般的做法是通过类Introspector来获取某个对象的BeanInfo信息,然后通过BeanInfo来获取属性的描述器

    (PropertyDescriptor),通过这个属性描述器就可以获取某个属性对应的getter/setter方法,然后我们就可以通过反

    射机制来调用这些方法,最后将引用对象注入到属性中。

    import java.beans.Introspector;
    import java.beans.PropertyDescriptor;
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import org.jdom.Document;
    import org.jdom.Element;
    import org.jdom.input.SAXBuilder;
    import org.jdom.xpath.XPath;
    
    /**
     * 容器
     * 
     * @author liang
     * 
     */
    public class ClassPathXmlApplicationContext implements BeanFactory {
    
    	// 用于存放Bean
    	private List<BeanDefinition> beanDefines = new ArrayList<BeanDefinition>();
    	// 用于存放Bean的实例
    	private Map<String, Object> sigletons =new HashMap<String, Object>();
    	
    	
    	public ClassPathXmlApplicationContext(String fileName) {
    
    		this.readXML(fileName);
    		
    		this.instanceBeans();
    		
    		this.injectObject();
    	}
    	/**
    	 * 为bean对象的属性注入值
    	 */
    	private void injectObject() {
    		for (BeanDefinition beanDefinition :beanDefines) {
    			Object bean = sigletons.get(beanDefinition.getId());
    			if(bean != null){
    				try {
    					// 通过Introspector取得bean的定义信息,之后再取得属性的描述信息,返回一个数组
    					PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
    					
    					for(PropertyDefinition propertyDefinition:beanDefinition.getPropertys()){
    						for(PropertyDescriptor properdesc: ps){
    							if(propertyDefinition.getName().equals(properdesc.getName())){
    								// 获取属性的setter方法,private
    								Method setter = properdesc.getWriteMethod(); 
    								if(setter != null){
    									Object value = sigletons.get(propertyDefinition.getRef());
    									// 允许访问私有方法
    									setter.setAccessible(true); 
    									// 把引用对象注入到属性
    									setter.invoke(bean, value); 
    								}
    								break;
    							}
    						}
    					}
    				} catch (Exception e) {
    					e.printStackTrace();
    				}
    			}
    		}
    	}
    
    	/**
    	 * 完成bean的实例化
    	 */
    	private void instanceBeans() {
    		for(BeanDefinition 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配置文件
    	 */
    	private void readXML(String fileName) {
    		// 创建SAXBuilder对象
    		SAXBuilder saxBuilder = new SAXBuilder();
    
    		try {
    			// 读取资源,获得document对象
    			Document doc = saxBuilder.build(this.getClass().getClassLoader()
    					.getResourceAsStream(fileName));
    			// 获取根元素
    			Element rootEle = doc.getRootElement();
    			// 从根元素获得所有的子元素,建立元素集合
    			List listBean = XPath.selectNodes(rootEle, "/beans/bean");
    
    			// 遍历根元素的子元素集合,扫描配置文件中的bean
    			for (int i = 0; i < listBean.size(); i++) {
    				 // 将根元素beans下的bean子元素作为一个新的子根元素
    				Element elementBean = (Element) listBean.get(i);
    				//获取id属性值
    				String id = elementBean.getAttributeValue("id");
    				//获取class属性值
    				String clazz = elementBean.getAttributeValue("class");
    				
    				BeanDefinition beanDefine = new BeanDefinition(id,clazz);
    				// 获取子根元素bean下的所有property子元素
    				List listProperty = elementBean.getChildren("property");
    				// 遍历子根元素的子元素集合(即遍历property元素)
    				for (int j = 0; j < listProperty.size(); j++) {
    					// 获取property元素
    					Element elmentProperty = (Element)listProperty.get(j);
    					// 获取name属性值
    					String propertyName = elmentProperty.getAttributeValue("name");
    					// 获取ref属性值
    					String propertyref = elmentProperty.getAttributeValue("ref");
    					
    					PropertyDefinition propertyDefinition = new PropertyDefinition(propertyName,propertyref);
    					
    					beanDefine.getPropertys().add(propertyDefinition);
    				}
    				
    				// 将javabean添加到集合中
    				beanDefines.add(beanDefine);
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    
    
    	/**
    	 * 获取bean实例
    	 */
    	@Override
    	public Object getBean(String beanName) {
    		return this.sigletons.get(beanName);
    	}
    }


    此时我们就可以把Service接口的set方法去掉了。
    public interface Service {
    	public void serviceMethod();
    }


    这里仅有部分代码,大家可以在下面链接中下载。

     

    总结


            经过四篇博文的重构,我们实现了一个Spring的雏形,它可以让我们更加深刻的认识Spring的原理,对我们更加 

    深入的学习Spring埋下了伏笔。


            源码下载


  • 相关阅读:
    python中F/f表达式优于format()表达式
    java8新特性-foreach&lambda
    Java实现多线程的四种方式
    Java中的字符串常量池,栈和堆的概念
    java对象只有值传递,为什么?
    面向对象和面向过程程序设计理解及区别
    String对象为什么不可变
    mybatis_plus插件——生成器
    基于grpc的流式方式实现双向通讯(python)
    Django使用DataTables插件总结
  • 原文地址:https://www.cnblogs.com/ainima/p/6330964.html
Copyright © 2020-2023  润新知