概念
所谓的IOC称之为控制反转,简单来说就是将对象的创建的权利及对象的生命周期的管理过程交 由Spring框架来处理,从此在开发过程中不再需要关注对象的创建和生命周期的管理,而是在 需要时由Spring框架提供,这个由spring框架管理对象创建和生命周期的机制称之为控制反 转。而在 创建对象的过程中Spring可以依据配置对对象的属性进行设置,这个过称之为依赖注 入,也即DI。
初代IOC的初始化过程
说人话就是先把XML配置文件加载成输入流,然后解析成为BeanDefinition对象(就是把xml上的东西映射成为一个对象),然后BeanFactory通过反射创建真正的对象
手写IOC
自定义一个User类和一个Dog类
package com.jmy.ioc;
public class User {
private String name;
private int age;
private Dog dog;
public User() {
}
public User(String name, int age, Dog dog) {
this.name = name;
this.age = age;
this.dog = dog;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", dog=" + dog +
'}';
}
public void sayHello(){
System.out.println("Hello world!");
}
}
package com.jmy.ioc;
public class Dog {
private String name;
public Dog() {
}
public Dog(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
'}';
}
}
xml文件转化为InputStream
package com.jmy.ioc;
import java.io.InputStream;
// 此接口用于将xml文件转化为流的形式
public interface Resource {
public InputStream getResource();
}
java
package com.jmy.ioc;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
public class XmlResourceToStream implements Resource{
private String xmlName;
public XmlResourceToStream(String xmlName) {
this.xmlName = xmlName;
}
@Override
public InputStream getResource() {
URL resource = this.getClass().getClassLoader().getResource(xmlName);
InputStream inputStream = null;
try {
URLConnection urlConnection = resource.openConnection();
inputStream = urlConnection.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
return inputStream;
}
}
抽象之后的XML对象BeanDefinition
package com.jmy.ioc;
import java.util.concurrent.ConcurrentHashMap;
public class BeanDefinition {
private String beanId; // xml中bean标签的id
private String beanClassName; // xml中bean标签的class
private Class beanClass; // xml中bean的字节码对象
private Object bean; // bean对象
private ConcurrentHashMap<String,Object> beanProperty; // xml中bean的属性
public BeanDefinition(String className) {
this.beanClassName = className;
}
public Object getBean() {
return bean;
}
public void setBean(Object bean) {
this.bean = bean;
}
public String getBeanId() {
return beanId;
}
public void setBeanId(String beanId) {
this.beanId = beanId;
}
public String getBeanClassName() {
return beanClassName;
}
public void setBeanClassName(String beanClassName) {
this.beanClassName = beanClassName;
}
public Class getBeanClass() {
return beanClass;
}
public void setBeanClass(String beanClassName) {
try {
this.beanClass = Class.forName(beanClassName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public ConcurrentHashMap<String, Object> getBeanProperty() {
return beanProperty;
}
public void setBeanProperty(ConcurrentHashMap<String, Object> beanProperty) {
this.beanProperty = beanProperty;
}
}
如果value的值为引用类型需要我们标记一下
package com.jmy.ioc;
// property标签如果是ref给予标记
public class BeanRefence {
private String ref;
public BeanRefence(String ref) {
this.ref = ref;
}
public String getRef() {
return ref;
}
public void setRef(String ref) {
this.ref = ref;
}
}
读取xml文件封装BeanDefinition
package com.jmy.ioc;
// 读取配置文件定义bean
public interface BeanDefinitionReader {
void loadResource(Resource resource);
}
package com.jmy.ioc;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class XmlBeanDefinitionReader implements BeanDefinitionReader {
ConcurrentHashMap<String, BeanDefinition> map;
public XmlBeanDefinitionReader() {
this.map = new ConcurrentHashMap<String, BeanDefinition>();
}
@Override
public void loadResource(Resource resource) {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
InputStream inputStream = resource.getResource();
try {
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse(inputStream);
this.registBeanDefinition(document);
inputStream.close();
} catch (ParserConfigurationException | SAXException | IOException e) {
e.printStackTrace();
}
}
private void registBeanDefinition(Document document) {
Element root = document.getDocumentElement(); // 直接获取<beans>
NodeList beanList = root.getElementsByTagName("bean"); // 获取所有的bean标签
// 遍历所有的bean标签 为BeanDefinition注入属性
for (int i = ; i < beanList.getLength(); i++) {
Node node = beanList.item(i);
Element beanNode = (Element) node;
String id = beanNode.getAttribute("id");
String className = beanNode.getAttribute("class");
BeanDefinition beanDefinition = new BeanDefinition(className);
// 为bean注入属性
this.injectProperties(beanDefinition, beanNode);
// 注册bean
map.put(id, beanDefinition);
}
}
private void injectProperties(BeanDefinition beanDefinition, Element beanNode) {
NodeList properties = beanNode.getElementsByTagName("property");
ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<>();
if (properties != null) {
for (int i = ; i < properties.getLength(); i++) {
Element property = (Element) properties.item(i);
String name = property.getAttribute("name");
String value = property.getAttribute("value");
if (value != null && value.length() != ) {
map.put(name, value);
} else {
String ref = property.getAttribute("ref");
map.put(name, new BeanRefence(ref));
}
}
beanDefinition.setBeanProperty(map);
}
}
public Map<String, BeanDefinition> getBeanDefinitionMap() {
return map;
}
}
BeanFactory创建对象并注入属性
package com.jmy.ioc;
public interface BeanFactory {
public Object getBean(String name);
}
package com.jmy.ioc;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
// 真正的去创建bean对象并注入属性
public class InjectBeanFactory implements BeanFactory {
private Map<String, BeanDefinition> beanDefinitionMap;
private XmlBeanDefinitionReader beanDefinitionReader;
public InjectBeanFactory(XmlBeanDefinitionReader beanDefinitionReader) {
this.beanDefinitionReader = beanDefinitionReader;
this.setBeanDefinitionMap(beanDefinitionReader.getBeanDefinitionMap());
}
public void setBeanDefinitionMap(Map<String, BeanDefinition> beanDefinitionMap) {
this.beanDefinitionMap = beanDefinitionReader.getBeanDefinitionMap();
}
@Override
public Object getBean(String name) {
BeanDefinition beanDefinition = beanDefinitionMap.get(name);
Object bean = beanDefinition.getBean();
// 创建对象
if (null == bean) {
bean = this.doCreate(beanDefinition);
}
// 注入属性
if (!beanDefinition.getBeanProperty().isEmpty()) {
this.injectProperties(bean, beanDefinition.getBeanProperty());
}
return bean;
}
private void injectProperties(Object bean, ConcurrentHashMap<String, Object> beanProperty) {
for (Map.Entry<String, Object> entry : beanProperty.entrySet()) {
String fieldName = entry.getKey();
// 通过反射获取属性
try {
Field field = bean.getClass().getDeclaredField(fieldName);
// 暴力破解
field.setAccessible(true);
Object value = entry.getValue();
if (value instanceof BeanRefence) {
field.set(bean, this.getBean(((BeanRefence) value).getRef()));
} else {
String type = field.getType().getName();
if (type.equals("java.lang.String")) {
field.set(bean, entry.getValue());
} else if (type.equals("java.lang.Integer") || type.equals("int")) {
field.set(bean, Integer.valueOf((String) entry.getValue()));
}
}
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
private Object doCreate(BeanDefinition beanDefinition) {
try {
beanDefinition.setBean(Class.forName(beanDefinition.getBeanClassName()).newInstance());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return beanDefinition.getBean();
}
}
创建一个自己的ApplicationContext整合前几步
撒花
最后本来想要写一个单元测试但是IDEA今天貌似有一些不给力一单元测试就死机。。所以写个main函数运行一下算了!!
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
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/util">
<bean id="user" class="com.jmy.ioc.User">
<property name="name" value="姜明阳"></property>
<property name="age" value="22"></property>
<property name="dog" ref="dog"></property>
</bean>
<bean id="dog" class="com.jmy.ioc.Dog">
<property name="name" value="旺财"></property>
</bean>
</beans>
主函数
package com.jmy.ioc;
public class Test {
public static void main(String[] args) {
MyClassPathXmlApplicationContext context = new MyClassPathXmlApplicationContext("application.xml");
User user = (User) context.getBean("user");
user.sayHello();
System.out.println(user.getName());
System.out.println(user.getDog());
/*int[] arry = new int[]{1,2,3,4};
for (int i = 0; i < arry.length; i++) {
System.out.println(arry[i]);
}
change(arry);
for (int i = 0; i < arry.length; i++) {
System.out.println(arry[i]);
}*/
}
/*static void change(int[] inarry) {
inarry[0] = 666;
inarry = new int[7];
}*/
}
结果
Hello world!
姜明阳
Dog{name='旺财'}