目录
1.使用IOC控制反转 中的DI依赖注入
手工注入
A:使用set 方法 注入 (1.使用 ref 2.使用bean)
B.使用 构造 注入
自动注入
C 注解 (未)
2.自己编写 模仿 spring 的 注入功能
3.依赖 注入各种集合类型 set, map, list, properties
[b][color=red]使用DI依赖注入dao( 编写dao---> 在service中使用 set方法注入dao-->配置)[/color][/b]
//发现 打印出 "调用personDao中的add方法" 这句话 说明 spring 的 IOC DI 成功.
[b][color=red]2.下面我们来 模仿 spring的 注入功能 我想 这样你就更清楚了 [/color][/b](主要在我们昨天 编写的 mini spring 框架上 添加 属性的 注入功能)
在 加入一个 commons-beanutils-1.8.3.jar 帮助我们进行 类型转换
1.首先 定义 spring 配置中的 bean
2.定义 bean节点中的属性 property
3.定义 ClassPathXmlApplicationContext
4.测试
如果上面的 打印出了 "调用personDao中的add方法" 说明我们手动的 编写的 spring注入 成成功实现了 注入对象和 注入基本类型. 我想这样 不会告诉我说你不懂 spring IOC了吧 呵呵
[b][color=red]3.依赖 注入各种集合类型 set, map, list, properties[/color][/b]
5.使用构造注入
//从上面可以测试出 我们在给构造函数 给参数的时候 可以根据 name 和 index 来赋值 type是可选的
1.使用IOC控制反转 中的DI依赖注入
手工注入
A:使用set 方法 注入 (1.使用 ref 2.使用bean)
B.使用 构造 注入
自动注入
C 注解 (未)
2.自己编写 模仿 spring 的 注入功能
3.依赖 注入各种集合类型 set, map, list, properties
[b][color=red]使用DI依赖注入dao( 编写dao---> 在service中使用 set方法注入dao-->配置)[/color][/b]
package com.person.dao;
public interface PersonDao {
public void add();
}
package com.person.dao.impl;
import com.person.dao.PersonDao;
public class PersonDaoBean implements PersonDao {
public void add(){
System.out.println("调用personDao中的add方法");
}
}
import com.person.dao.PersonDao;
import com.person.service.PersonService;
public class PersonServiceBean implements PersonService {
private PersonDao personDao; //注入 object
private String name; //注入基本类型
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//只需要提供 set方法 就可以 让 spring 的反射机制 给我们 注入dao
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
//调用 dao中的方法
public void add(){
personDao.add();
}
}
<!-- 使用 spring 管理 dao -->
<bean id="personDao" class="com.person.dao.impl.PersonDaoBean">
</bean>
<!-- 这里配置后 就会有 spring来管理, 注意id 和name 的区别 -->
<bean id="personService" class="com.person.service.impl.PersonServiceBean" lazy-init="true" >
<!-- 配置 service 中引用 的dao 对象 为上面的 配置的 dao -->
<property name="personDao" ref="personDao"/>
<!-- 也可以使用这种 方式 注入 区别 在于 上面的 personDao就可以不用定义了 ,这样 其他的 service就不能访问 personDao, 根据需求使用 这两种方式
<property name="personDao">
<bean class="com.person.dao.impl.PersonDaoBean"/>
</property> -->
<!-- 为基本上属性注入值 -->
<property name="name" value="JACK"/>
</bean>
@Test //测试 spring的 依赖注入
public void init7(){
ApplicationContext ctx=new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
PersonService personService=(PersonService)ctx.getBean("personService");
personService.add();
}
//发现 打印出 "调用personDao中的add方法" 这句话 说明 spring 的 IOC DI 成功.
[b][color=red]2.下面我们来 模仿 spring的 注入功能 我想 这样你就更清楚了 [/color][/b](主要在我们昨天 编写的 mini spring 框架上 添加 属性的 注入功能)
在 加入一个 commons-beanutils-1.8.3.jar 帮助我们进行 类型转换
1.首先 定义 spring 配置中的 bean
package junit.test;
import java.util.ArrayList;
import java.util.List;
/**
* 定义 保存 spring配置文件中的bean对象
* @author Bin
*/
public class BeanDefinition {
private String id; //对应 spring配置文件中的id
private String className; //对应 spring配置文件中的class
//定义 bean中 属性的节点 集合
private List<PropertyDefinition> propertys= new ArrayList<PropertyDefinition>();
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 BeanDefinition() {
}
public List<PropertyDefinition> getPropertys() {
return propertys;
}
public void setPropertys(List<PropertyDefinition> propertys) {
this.propertys = propertys;
}
public BeanDefinition(String id, String className) {
this.id = id;
this.className = className;
}
}
2.定义 bean节点中的属性 property
package junit.test;
public class PropertyDefinition {
private String name; //对应配置 文件中的name
private String ref; //对应配置 文件中的ref
private String value; //为基本属性注入值
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
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;
}
public PropertyDefinition() {
super();
// TODO Auto-generated constructor stub
}
public PropertyDefinition(String name, String ref) {
super();
this.name = name;
this.ref = ref;
}
public PropertyDefinition(String name, String ref, String value) {
super();
this.name = name;
this.ref = ref;
this.value = value;
}
}
3.定义 ClassPathXmlApplicationContext
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.apache.commons.beanutils.ConvertUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.XPath;
import org.dom4j.io.SAXReader;
import com.sun.xml.internal.fastinfoset.stax.events.Util;
/*
* 编写自己的 mini spring 容器
* 来模拟spring 的工作
*/
public class MySpringClassPathXmlApplicationContext {
//保存 配置文件中的 bean 的信息
private List<BeanDefinition> beandefines=new ArrayList<BeanDefinition>();
//保存初始化 后的对象
private Map<String,Object> sigletons=new HashMap<String,Object>();
//构造方法
public MySpringClassPathXmlApplicationContext(String fileName) {
//读取配置文件
this.readXml(fileName);
//初始化所有的bean
this.instanceBean();
//为所有bean 依赖注入 属性
this.injectObject();
}
/**==================
* 读取xml配置文件
* ==================
* @author Bin
* @param fileName
*/
private void readXml(String fileName) {
SAXReader saxReader=new SAXReader();
Document doucment=null;
try {
URL xmlPath=this.getClass().getClassLoader().getResource(fileName);
doucment=saxReader.read(xmlPath);
Map<String,String> nsMap=new HashMap<String,String>();
//给spring配置文件的命名空间 一个别名 ns
nsMap.put("ns","http://www.springframework.org/schema/beans"); //加入命名空间 xmlns: spring配置文件中的
XPath xsub=doucment.createXPath("//ns:beans/ns:bean"); //创建 beans/bean 查询路径
xsub.setNamespaceURIs(nsMap); //设置命名空间
List<Element> beans=xsub.selectNodes(doucment); //获取文档下的所有bean节点
for (Element element : beans) {
String id=element.attributeValue("id"); //获取 id的属性值
String clazz=element.attributeValue("class"); // 获取 class属性
//类是 spring中的 : org.springframework.beans.factory.config.BeanDefinition;
BeanDefinition beandefine=new BeanDefinition(id,clazz);
//解析 bean节点中的property 属性节点
XPath propertysub=element.createXPath("ns:property"); //创建 property的查询路径 //使用相对路径
propertysub.setNamespaceURIs(nsMap); //设置命名空间
List<Element> propertys=propertysub.selectNodes(element); //根据 查询路径 在 这个元素中查找 子元素
for (Element property : propertys) { //取出查找到 的 property 子节点
String propertyName=property.attributeValue("name");
String propertyRef=property.attributeValue("ref");
String propertyValue=property.attributeValue("value");
PropertyDefinition propertyDefinition= new PropertyDefinition(propertyName,propertyRef,propertyValue);
//放入 bean 的property 集合中
beandefine.getPropertys().add(propertyDefinition);
}
beandefines.add(beandefine); //将这个bean保存的 集合中
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**===================================
* 完成Bean 的实例化
* ===================================
* @author Bin
*/
private void instanceBean() {
for (BeanDefinition beandefine : beandefines) {
try {
if(!Util.isEmptyString(beandefine.getClassName()))
sigletons.put(beandefine.getId(), Class.forName(beandefine.getClassName().trim()).newInstance());
}catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//注入对象 主要是 根据 set 方法
private void injectObject() {
try{
//遍历 spring配置中的 bean节点信息的集合 (id class)
for (BeanDefinition beandefine : beandefines) {
//根据id 到 初试化好了的 对象集合中 查找对象
Object bean=sigletons.get(beandefine.getId());
if(bean!=null){
//如果对象不为空 就获取这个对象的 所有属性信息
PropertyDescriptor[] ps=Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
//遍历 bean节点中 所有的 property 子节点集合
for(PropertyDefinition propertyDefinition:beandefine.getPropertys()){
//遍历 初始化好后的 对象中的 属性 描述
for(PropertyDescriptor properDesc:ps){
//如果 两个 属性名相等 就说明找到了这个对象中的属性了
if(propertyDefinition.getName().equals(properDesc.getName())){
Method setter=properDesc.getWriteMethod(); //获取属性的setter方法 可 能是 public ,private 类型
if(setter!=null){
Object value=null;
if(!setter.isAccessible()){ //判断是否是 私有只读的
setter.setAccessible(true); //强制访问 私有属性的 setter 方法
}
if(!Util.isEmptyString(propertyDefinition.getRef())){ //说明是引用类型
//根据属性节点中的ref 到 sigletons 中取出对象
value=sigletons.get(propertyDefinition.getRef());
}else{//说明 是基本类型
value=ConvertUtils.convert(propertyDefinition.getValue(),properDesc.getPropertyType());
}
setter.invoke(bean, value); //给 某个对象某个方法 注入一个值
}
break; //注入 完一个 属性后 就跳出 继续为下一个属性 赋值
}
}
}
}
}
}catch(Exception e){
e.printStackTrace();
}
}
/**=======================
* 获取bean
* =======================
* @param beanName
* @return
*/
public Object getBean(String beanName){
return this.sigletons.get(beanName);
}
}
4.测试
@Test //测试自己 编写的 spring 注入 功能
public void init8(){
MySpringClassPathXmlApplicationContext ctx= new MySpringClassPathXmlApplicationContext("applicationContext.xml");
PersonService personService=(PersonService)ctx.getBean("personService");
personService.add();
}
如果上面的 打印出了 "调用personDao中的add方法" 说明我们手动的 编写的 spring注入 成成功实现了 注入对象和 注入基本类型. 我想这样 不会告诉我说你不懂 spring IOC了吧 呵呵
[b][color=red]3.依赖 注入各种集合类型 set, map, list, properties[/color][/b]
package com.person.service;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public interface PersonService {
//为了能在 前台访问 所以就提供这样的一个方法 用来放回注入后的set 集合
public Set<String> getSets();
public List<String> getLists();
public Properties getProperties();
public Map<String, String> getMaps();
public void save();
public void add();
}
package com.person.service.impl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import com.person.dao.PersonDao;
import com.person.service.PersonService;
public class PersonServiceBean implements PersonService {
//引用对象
private PersonDao personDao; //注入 object
//基本类型
private String name; //注入基本类型
// Set 集合类型
private Set<String> sets=new HashSet<String>();
// list 集合类型
private List<String> lists=new ArrayList<String>();
// Properties 集合类型
private Properties properties=new Properties();
// Map 集合类型
private Map<String,String> maps=new HashMap<String,String>();
// get set
}
<?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/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd ">
<!-- 使用 spring 管理 dao -->
<bean id="personDao" class="com.person.dao.impl.PersonDaoBean">
</bean>
<!-- 这里配置后 就会有 spring来管理, 注意id 和name 的区别 -->
<bean id="personService" class="com.person.service.impl.PersonServiceBean" lazy-init="true" >
<!-- 配置 service 中引用 的dao 对象 为上面的 配置的 dao -->
<property name="personDao" ref="personDao"/>
<!-- 也可以使用这种 方式 注入 区别 在于 上面的 personDao就可以不用定义了 ,这样 其他的 service就不能访问 personDao, 根据需求使用 这两种方式
<property name="personDao">
<bean class="com.person.dao.impl.PersonDaoBean"/>
</property> -->
<!-- 为基本上属性注入值 -->
<property name="name" value="JACK"/>
<property name="sets">
<set>
<value>第一个</value>
<value>第二个</value>
<value>第三个</value>
<value>第四个</value>
</set>
</property>
<property name="lists">
<list>
<value>第一个List元素</value>
<value>第二个List元素</value>
<value>第三个List元素</value>
</list>
</property>
<property name="properties">
<props>
<prop key="key1">value1</prop>
<prop key="key2">value2</prop>
<prop key="key3">value3</prop>
</props>
</property>
<property name="maps">
<map>
<entry key="key-1" value="value-1"/>
<entry key="key-2" value="value-2"/>
<entry key="key-3" value="value-3"/>
</map>
</property>
</bean>
</beans>
@Test //测试 spring的 依赖注入
public void init9(){
ApplicationContext ctx=new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
PersonService personService=(PersonService)ctx.getBean("personService");
personService.add();
System.out.println("============set============");
for (String name : personService.getSets()) {
System.out.println(name);
}
System.out.println("============List============");
for (String desc : personService.getLists()) {
System.out.println(desc);
}
System.out.println("============properties============");
for (Object key : personService.getProperties().keySet()) {
System.out.println(key+"="+personService.getProperties().getProperty(key.toString()));
}
System.out.println("============maps============");
for (String key: personService.getMaps().keySet()) {
System.out.println(key+"="+personService.getMaps().get(key));
}
}
5.使用构造注入
package com.person.service.impl;
import com.person.dao.PersonDao;
import com.person.service.PersonService;
public class PersonServiceBean implements PersonService {
//引用对象
private PersonDao personDao; //注入 object
//基本类型
private String name; //注入基本类型
// 使用构造注入
public PersonServiceBean(PersonDao personDao, String name) {
this.personDao = personDao;
this.name = name;
}
}
<!-- 使用 spring 管理 dao -->
<bean id="personDao" class="com.person.dao.impl.PersonDaoBean">
</bean>
<bean id="personService4" class="com.person.service.impl.PersonServiceBean" >
<constructor-arg index="0" type="com.person.dao.PersonDao" ref="personDao"/>
<constructor-arg index="1" type="java.lang.String" value="欢迎踩踩!"/>
</bean>
@Test
public void init10(){
ApplicationContext ctx=new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
PersonService personService=(PersonService)ctx.getBean("personService4");
personService.add();
}
//从上面可以测试出 我们在给构造函数 给参数的时候 可以根据 name 和 index 来赋值 type是可选的