zoukankan      html  css  js  c++  java
  • Spring、Spring依赖注入与编码剖析Spring依赖注入的原理

    Spring依赖注入

    新建PersonIDao 和PersonDao底实现Save方法:

    public interface PersonIDao {
    	public void save();
    }

    public class PersonDaoImpl  implements PersonIDao{
    	@Override
    	public void save() {
    		System.out.println("我是dao的Save方法");
    	}
    }
    

    在Bean.xml中注入PersonIDao,并将PersonIDao注入到PersonService中:

    <bean id="personIDao" class="cn.dao.impl.PersonDaoImpl" />
    	<bean id="personIService" class="cn.server.impl.PersonServiceImpl">
    		<property name="personIDao" ref="personIDao" />
    	</bean>


    在PersonService中添加PersonIDao类型属性并实现属性的set方法,然后调用PersonIDao的save方法

    public class PersonServiceImpl implements PersonIService {
    	private PersonIDao personIDao;
    	
    	public PersonIDao getPersonIDao() {
    		return personIDao;
    	}
    	public void setPersonIDao(PersonIDao personIDao) {
    		this.personIDao = personIDao;
    	}
    	@Override
    	public void save() {
    		personIDao.save();
    	}
    }

    然后测试:

    @Test
    	public void testSave() {
    		AbstractApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
    		PersonIService personIService=(PersonIService)ac.getBean("personIService");
    		personIService.save();
    	}



    编码剖析Spring依赖注入的原理

    通过编码的方法式来剖析Spring 依赖注入的原理方法,新建PropertyDefinition类用来承载Bean中注入的property的属性:

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

    新建BeanDefinition用来承载解析到的Bean属性

    public class BeanDefinition {
    	private String id;
    	private String className;
    	private List<PropertyDefinition> properties=new ArrayList<PropertyDefinition>();
    	public BeanDefinition(){}
    	public BeanDefinition(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> getProperties() {
    		return properties;
    	}
    	public void setProperties(List<PropertyDefinition> properties) {
    		this.properties = properties;
    	}
    }

    新建OtherClassPathXMLApplicationContext 用来解析bean.xml

    public class OtherClassPathXMLApplicationContext {
    	private List<BeanDefinition> list=new ArrayList<BeanDefinition>();
    	private Map<String,Object> beans=new HashMap<String, Object>();
    	
    	public OtherClassPathXMLApplicationContext(String fileName){
    		this.readXML(fileName);
    		this.instanceBeans();
    		this.instanceProperties();
    	}
    	private void instanceBeans(){
    		for(BeanDefinition bean : list){
    			try {
    				// 创建Bean实例,并放到Map中
    				if(bean.getClassName()!=null && !bean.getClassName().trim().equals("")){
    					beans.put(bean.getId(), Class.forName(bean.getClassName()).newInstance());
    				}
    			} catch (Exception e) {
    				e.printStackTrace();
    			} 
    		}
    	}
    	private void instanceProperties(){
    		for(BeanDefinition beanDefinition : list){
    			Object bean=beans.get(beanDefinition.getId());
    			if(bean!=null){
    				 try {
    					// 获取bean下所有的属性定义描述
    					PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
    					for(PropertyDefinition propertyDefinition : beanDefinition.getProperties()){
    						for(PropertyDescriptor propertyDescriptor : ps){
    							// 如果bean下的属性名字与当前的BeanDefinition下的属性名称一样的话,则将引用对象注入到属性
    							if(propertyDefinition.getName().equals(propertyDescriptor.getName())){
    								Method setter=propertyDescriptor.getWriteMethod(); // 获取Bean的所有写入的方法 即 setter方法
    								setter.setAccessible(true); // true: 直接访问私有属性,将例子中的私有属性改值。
    								Object value=beans.get(propertyDefinition.getRef());
    								setter.invoke(bean, value);  // 把引用对象注入属性
    								break;
    							}
    						}
    					}
    				} catch (Exception e) {
    					e.printStackTrace();
    				}
    			}
    		}
    	}
    	private void readXML(String fileName){
    		SAXReader saxReader = new SAXReader();
    		Document doc=null;
    		try{
    			// JAVA里面对于类进行调用配置资源的文件数据,以this.getClass().getResourceAsStream()来读取比较合适。
    			// 路径采用相对路径直接可以从工程的path路径去找。
    			URL xmlpath=this.getClass().getClassLoader().getResource(fileName);
    			doc=saxReader.read(xmlpath);
    			Map<String,String> nsMap=new HashMap<String,String>(); 
    			nsMap.put("ns", "http://www.springframework.org/schema/beans"); // 加入命名空间
    			XPath xsub=doc.createXPath("//ns:beans/ns:bean"); // 创建 beans/bean的查询路径
    			xsub.setNamespaceURIs(nsMap); // 设置命名空间
    			List beans=xsub.selectNodes(doc); // 获取文档下的所有bean节点
    			for(Object node : beans){
    				Element element=(Element)node;
    				String id=element.attributeValue("id");
    				String className=element.attributeValue("class");
    				BeanDefinition bean=new BeanDefinition(id,className);
    				
    				// 编码剖析Spring依赖注入的原理
    				// 加载bean下的Property
    				XPath xproperty=element.createXPath("ns:property"); // 为xproperty 添加查询路径
    				xproperty.setNamespaceURIs(nsMap);
    				List properties=xproperty.selectNodes(element); // 查询出bean下的所有property
    				for(Object propertyNode : properties){
    					Element propertyElement=(Element)propertyNode;
    					String name=propertyElement.attributeValue("name");
    					String ref=propertyElement.attributeValue("ref");
    					bean.getProperties().add(new PropertyDefinition(name, ref));
    				}
    				list.add(bean);
    			}
    			
    		}catch(Exception e){
    			e.printStackTrace();
    		}
    	}
    	// 通过Id名称,获取Bean
    	public Object getBean(String name){
    		return beans.get(name);
    	}
    }

    测试代码:

    	@Test
    	public void testSave2() {
    		OtherClassPathXMLApplicationContext ac = new OtherClassPathXMLApplicationContext("beans.xml");
    		PersonIService personIService=(PersonIService)ac.getBean("personIService");
    		personIService.save();
    	}







  • 相关阅读:
    Netty的常用概念
    netty学习
    MarkDown思考
    Xshell配置SSH秘钥登录
    Maven中避开测试环节
    Maven文件配置
    机器学习资源
    数学问题-高精度运算
    对局匹配
    发现环
  • 原文地址:https://www.cnblogs.com/raphael5200/p/5114741.html
Copyright © 2011-2022 走看看