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(); }