一:经过前面的学习我们知道,通过控制反射可以将依赖对象交给Spring管理,
通过容器注入到组件内部。
二:在spring是如何将对象注入到组件内部?
1、创建类PresonDaoImpl,代码如下:
package com.learn.dao.impl;
import com.learn.dao.PresonDao;
public class PresonDaoImpl implements PresonDao {
public void add(){
System.out.println("执行add()!");
}
}
2、抽取出接口(在前面讲过,这里不再赘余。)
3、将 PresonDao 注入到 PresonServiceImpl 中
(1)、通过属性的 setter 方法注入
<1>、PresonServiceImpl 代码如下:
package com.learn.service.impl;
import com.learn.dao.PresonDao;
import com.learn.service.PresonService;
/**
* 业务层
* @author Administrator
*
*/
public class PresonServiceImpl implements PresonService {
private PresonDao presonDao;
public PresonDao getPresonDao() {
return presonDao;
}
public void setPresonDao(PresonDao presonDao) {
this.presonDao = presonDao;
}
/* (non-Javadoc)
* @see com.learn.service.impl.PresonService#save()
*/
@Override
public void save(){
presonDao.add();
}
}
属性注入依赖对象的时候,一定要有setter方法,只能通过 setter 方法为属性注入值。在save() 方法调用注入进来的依赖对象的add() 方法。在 PresonServiceImpl 类中我们看不到 PresonDaoImpl 这个类,也就是说我们并不关心 dao 的实现类是谁。只是通过接口 PresonDao 引用注入进来的对象,然后通过接口调用方法。这样,service层的组件和 dao 层的组件实现了彻底的解耦。
<2>、如何给属性 presonDao 注入bean?首先要将 PresonDaoImpl 配置在spring的 xml 文件中。修改 xml 代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="personDao" class="com.learn.dao.impl.PresonDaoImpl"></bean>
<bean id="personService" name="" class="com.learn.service.impl.PresonServiceImpl">
<property name="presonDao" ref="personDao"></property>
</bean>
</beans>
property 元素表示的是为父节点bean 所对应的类中的属性注入值。name 属性的值 presonDao 要与PresonServiceImpl 类中属性名称 presonDao 一致,表示了要注入的属性;要将 bean(对象)注入到属性presonDao中,要用到ref, 属性 ref 的值 就是要注入到 属性 presonDao 中bean的 id 值。
<3>、调用测试:
package junit.test;
import static org.junit.Assert.*;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.learn.service.PresonService;
public class TestSpring {
@Test
public void initContainerSpring() {
//实例化spring容器 (使用类构造器实例化)
AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("com//learn//spring//learn1.xml");
PresonService personService = (PresonService)ctx.getBean("personService");
personService.save();
ctx.close();
}
}
(2)、通过内部 bean 注入依赖对象
<1>、现在我们只需要修改 XML 文件即可,代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="personService" class="com.learn.service.impl.PresonServiceImpl">
<property name="presonDao">
<bean class="com.learn.dao.impl.PresonDaoImpl"/>
</property>
</bean>
</beans>
<2>、单元测试代码如下:
package junit.test;
import static org.junit.Assert.*;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.learn.service.PresonService;
public class TestSpring {
@Test
public void initContainerSpring() {
//实例化spring容器 (使用类构造器实例化)
AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("com//learn//spring//learn1.xml");
PresonService personService = (PresonService)ctx.getBean("personService");
personService.save();
}
}
4、内部是如何实现注入的呢?
(1)、创建类 PropertyDefinition ,用于存放xml文件中 property 元素的信息,代码如下:
package junit.test;
/**
* 用于存放xml文件中 property 元素的信息
* @author Administrator
*
*/
public class PropertyDefinition {
//以下两个变量表示 property 元素中的属性,并用于存放属性值
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;
}
}
(2)、在 BeanDefinition(之前创建过) 类中定义List 集合,用于存放 bean 元素下面所有 property 元素信息,代码如下:
package junit.test;
import java.util.ArrayList;
import java.util.List;
/**
* 用于存放读取到的xml文件中bean的信息
* @author Administrator
*
*/
public class BeanDefinition {
private String id;
private String className;
//定义 List 集合,用于存放 bean 元素下面所有 property 元素信息
private List<PropertyDefinition> property = new ArrayList<PropertyDefinition>();
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> getProperty() {
return property;
}
public void setProperty(List<PropertyDefinition> property) {
this.property = property;
}
}
(3)、修改 TestClassPathXMLApplicationContext (之前创建过)类,代码如下:
package junit.test;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.XPath;
import org.dom4j.io.SAXReader;
/**
* 模拟spring
* @author Administrator
*
*/
public class TestClassPathXMLApplicationContext {
List<BeanDefinition> beanDefines = new ArrayList<BeanDefinition>();
Map<String, Object> sigletons = new HashMap<String, Object>();
public TestClassPathXMLApplicationContext(String filename){
readFile(filename);
instanceBeans();
injectObj();
}
/**
* 为 bean 对象属性注入值
*/
private void injectObj() {
for(BeanDefinition beanDefinition : beanDefines){
//通过 id 得到 bean 元素所指向的类
Object bean = sigletons.get(beanDefinition.getId());
if(null != bean){ //判断类是否存在
try{
// 得到类的属性描述
PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
for(PropertyDefinition propertyDefinition : beanDefinition.getProperty()){
for(PropertyDescriptor propertydesc : ps){
if(propertyDefinition.getName().equals(propertydesc.getName())){
//获取属性的setter方法
Method setter = propertydesc.getWriteMethod();
if(null != setter){ //容错处理
Object value = sigletons.get(propertyDefinition.getRef());
setter.setAccessible(true); //如果setter方法是私有的,经调用该方法处理表示可以访问
setter.invoke(bean, value);
}
break;
}
}
}
}catch(Exception e){
}
}
}
}
/**
* 实例化bean对象
*/
private void instanceBeans() {
for(BeanDefinition beanDefinition : beanDefines){
try {
/**
* 通过反射技术将bean实例化
*/
if(null != beanDefinition.getClassName() && !"".equals(beanDefinition.getClassName().trim())){
sigletons.put(beanDefinition.getId(), Class.forName(beanDefinition.getClassName()).newInstance());
}
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* 读取xml文件
* @param filename
*/
private void readFile(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>();
//加入命名空间,xml 文件中的命名空间为 xmlns="http://www.springframework.org/schema/beans" ,我们这里将它放入到ns中
nsMap.put("ns", "http://www.springframework.org/schema/beans");
//创建beans/bean查询路径,通过命名空间找到,该命名空间下的节点元素
XPath xsub = document.createXPath("//ns:beans/ns:bean");
//设置命名空间
xsub.setNamespaceURIs(nsMap);
//获取文档下所有的bean节点
@SuppressWarnings("unchecked")
List<Element> beans = xsub.selectNodes(document);
for(Element element : beans){
String id = element.attributeValue("id");
String className = element.attributeValue("class");
BeanDefinition beanDefine = new BeanDefinition(id, className);
//创建查询路径
XPath propertysub = element.createXPath("ns:property");
//设置命名空间
propertysub.setNamespaceURIs(nsMap);
//获取当前元素下的节点
@SuppressWarnings("unchecked")
List<Element> propertys = propertysub.selectNodes(element);
for(Element property : propertys){
String propertyName = property.attributeValue("name");
String propertyRef = property.attributeValue("ref");
PropertyDefinition propertyDefinition = new PropertyDefinition(propertyName, propertyRef);
beanDefine.getProperty().add(propertyDefinition);
}
beanDefines.add(beanDefine);
}
}catch(Exception e){
e.printStackTrace();
}
}
/**
* 获取bean实例
* @param beanName
* @return
*/
public Object getBean(String beanName){
return sigletons.get(beanName);
}
public void initStr(){
System.out.append("ff");
}
}
(4)、XML 文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="personDao" class="com.learn.dao.impl.PresonDaoImpl"></bean>
<bean id="personService" class="com.learn.service.impl.PresonServiceImpl">
<property name="presonDao" ref="personDao"></property>
</bean>
</beans>
(5)、调用测试:
package junit.test;
import static org.junit.Assert.*;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.learn.service.PresonService;
public class TestSpring {
@Test
public void initContainerSpring() {
TestClassPathXMLApplicationContext ctx = new TestClassPathXMLApplicationContext("com//learn//spring//learn1.xml");
PresonService personService = (PresonService)ctx.getBean("personService");
personService.save();
}
}
浙公网安备 33010602011771号