实践
项目目录结构
项目下载
https://github.com/cbeann/Demoo/tree/master/ioc-demo
pom
代码语言:javascript复制<!--解析XML的依赖-->
<!-- https://mvnrepository.com/artifact/org.jdom/jdom -->
<dependency>
<groupId>org.jdom</groupId>
<artifactId>jdom</artifactId>
<version>2.0.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/jaxen/jaxen -->
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.6</version>
</dependency>
实体类
BeanDefinationn :Bean的定义信息
代码语言:javascript复制package myioc.configbean;
import java.util.HashMap;
import java.util.Map;
/**
* Bean的定义信息
*/
public class BeanDefinationn {
private String id;//名称
private String clazz;//类型
private Boolean isSinglen;//是否单例
private Map<String, Object> properties = new HashMap<>();//非引用参数集合
private Map<String, Object> refs = new HashMap<>();//引用参数集合
public BeanDefinationn() {
}
@Override
public String toString() {
return "BeanDefinationn{"
"id='" id '''
", clazz='" clazz '''
", isSinglen=" isSinglen
", properties=" properties
", refs=" refs
'}';
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getClazz() {
return clazz;
}
public void setClazz(String clazz) {
this.clazz = clazz;
}
public Boolean getSinglen() {
return isSinglen;
}
public void setSinglen(Boolean singlen) {
isSinglen = singlen;
}
public Map<String, Object> getProperties() {
return properties;
}
public void setProperties(Map<String, Object> properties) {
this.properties = properties;
}
public Map<String, Object> getRefs() {
return refs;
}
public void setRefs(Map<String, Object> refs) {
this.refs = refs;
}
}
Book
代码语言:javascript复制package myioc.entity;
/**
* @author CBeann
* @create 2019-12-18 10:47
*/
public class Book {
public void speak(){
System.out.println("------Book-------");
}
}
Student
代码语言:javascript复制package myioc.entity;
/**
* @author CBeann
* @create 2019-12-18 9:57
*/
public class Student {
private String name;
private String age;
public Student() {
}
@Override
public String toString() {
return "Student{"
"name='" name '''
", age=" age
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
StudentDao
代码语言:javascript复制package myioc.entity;
/**
* @author CBeann
* @create 2019-12-18 10:06
*/
public class StudentDao {
public StudentDao() {
}
public void speak() {
System.out.println("-----StudentDao------");
}
}
StudentService
代码语言:javascript复制package myioc.entity;
/**
* @author CBeann
* @create 2019-12-18 10:06
*/
public class StudentService {
private StudentDao studentDao;
public void speak() {
System.out.println("-----StudentService------");
}
public StudentService() {
}
public StudentDao getStudentDao() {
return studentDao;
}
public void setStudentDao(StudentDao studentDao) {
this.studentDao = studentDao;
}
}
IOC工厂类
工厂接口
代码语言:javascript复制package myioc.factory;
/**
* @author CBeann
* @create 2019-12-18 9:46
*/
public interface IOCFactory {
/**
* 根据名称获得Bean
*/
public Object getBean(String beanName) throws Exception;
}
工厂实现类
代码语言:javascript复制package myioc.factory.impl;
import myioc.configbean.BeanDefinationn;
import myioc.factory.IOCFactory;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;
import org.jdom2.xpath.XPathExpression;
import org.jdom2.xpath.XPathFactory;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author CBeann
* @create 2019-12-18 10:08
*/
public class IOCFactoryImpl implements IOCFactory {
private static Object NO_SINGLEN = new Object();
//IOC容器
private Map<String, Object> iocMap = new HashMap<>();
//BeanDefination容器
private Map<String, BeanDefinationn> beanDefinationnMap = new HashMap<>();
public IOCFactoryImpl(String configPath) throws Exception {
try {
//解析配置文件
xmlParse(configPath);
//初始化Bean
prepareSingleBean();
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
/*解析XML方法*/
private void xmlParse(String configPath) throws Exception {
File file = new File(configPath);
SAXBuilder builder = new SAXBuilder();
Document document = builder.build(file);
// 创建XPath对象,反射获取XPath对象
XPathFactory factory = XPathFactory.instance();
XPathExpression expression = factory.compile("//bean");
List<Element> beans = expression.evaluate(document);
for (Element beanElement : beans) {
//获取id
String id = beanElement.getAttributeValue("id");
//获取类全路径
String clazz = beanElement.getAttributeValue("class");
//是否单例
String singleton = beanElement.getAttributeValue("scope");
//获取参数
List<Element> properties = beanElement.getChildren("property");
//初始化Bean定义对象
BeanDefinationn beanDefination = new BeanDefinationn();
beanDefination.setId(id);
beanDefination.setClazz(clazz);
beanDefination.setSinglen((singleton != null && "singleton".equals(singleton)));
for (Element property : properties) {
String name = property.getAttributeValue("name");
String value = property.getAttributeValue("value");
String ref = property.getAttributeValue("ref");
if (null != value) {
//如果是非引用类型
beanDefination.getProperties().put(name, value);
} else {
//如果是引用类型
beanDefination.getRefs().put(name, ref);
}
}
beanDefinationnMap.put(beanDefination.getId(), beanDefination);
}
}
//初始化单例类
private void prepareSingleBean() throws Exception {
//循环遍历Bean的定义信息
Set<Map.Entry<String, BeanDefinationn>> entries = beanDefinationnMap.entrySet();
for (Map.Entry<String, BeanDefinationn> entry : entries) {
//获取Bean的唯一ID名称
String id = entry.getKey();
BeanDefinationn value = entry.getValue();
//创建Bean
Object bean = getBean(id);
//如果是单例,放入IOC容器中
if (value.getSinglen()) {
iocMap.put(id, bean);
} else {
//非单例则放入一个静态类,如果放null,则容易和没有定义的类混淆
iocMap.put(id, NO_SINGLEN);
}
}
}
/*
获取Bean
如果单例,在IOC容器获取并且返回,如果获取不到,创建并且并且返回
*/
@Override
public Object getBean(String beanName) throws Exception {
BeanDefinationn beanDefinationn = beanDefinationnMap.get(beanName);
//如果是单例
if (beanDefinationn.getSinglen()) {
//如果容器中有该Bean,直接返回
if (null != iocMap.get(beanName)) {
return iocMap.get(beanName);
} else {
//如果容器中没有该Bean,则创建Bean
return doCreateBean(beanName);
}
} else {
//如果不是单例,直接创建,不在IOC容器中获取
return doCreateBean(beanName);
}
}
/*
创建Bean
*/
private Object doCreateBean(String beanName) throws Exception {
//获取Bean的定义信息
BeanDefinationn beanDefinationn = beanDefinationnMap.get(beanName);
// 反射拿到类的相应信息,首先是拿到类的实例对象
Class clazz = Class.forName(beanDefinationn.getClazz());
Object object = clazz.newInstance();
// 获取类的所有方法,然后通过set方法给这个对象设置属性值
Method[] methods = clazz.getDeclaredMethods();
//获取所有的参数和引用
Map<String, Object> properties = beanDefinationn.getProperties();
Map<String, Object> refs = beanDefinationn.getRefs();
//给对象封装引用参数和非引用参数
for (int i = 0; i < methods.length; i ) {
//获得方法的名称
String methodName = methods[i].getName();
// 属性名
String beanPropertyName = "";
// 这里检索set方法
if (methodName.startsWith("set")) {
// 根据set方法获取属性名->这里就只截取set方法的方法名并且转换为小写的名字
//setStudentDao--->studentDao
beanPropertyName = methodName.substring(3, 4).toLowerCase() methodName.substring(4);
if (properties.containsKey(beanPropertyName)) {
//如果这个参数是非引用参数
//在参数列表中获取value
Object proVal = properties.get(beanPropertyName);
//通过反射执行此方法
methods[i].invoke(object, proVal);
} else if (refs.containsKey(beanPropertyName)) {
//如果这个参数是引用参数
//在ioc容器中获取value
Object proVal = getBean(refs.get(beanPropertyName).toString());
//通过反射执行此方法
methods[i].invoke(object, proVal);
} else {
//什么也不做
}
}
}
//返回这个类型
return object;
}
}
myioc.xml
代码语言:javascript复制<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="student" class="myioc.entity.Student" scope="prototype">
<property name="name" value="CBeann"/>
<property name="age" value="18"/>
</bean>
<bean id="book" class="myioc.entity.Book" scope="singleton">
</bean>
<bean id="studentService" class="myioc.entity.StudentService" scope="singleton">
<property name="studentDao" ref="studentDao"/>
</bean>
<bean id="studentDao" class="myioc.entity.StudentDao" scope="singleton">
</bean>
</beans>
启动类
代码语言:javascript复制package myioc.app;
import myioc.entity.Book;
import myioc.entity.Student;
import myioc.entity.StudentDao;
import myioc.entity.StudentService;
import myioc.factory.IOCFactory;
import myioc.factory.impl.IOCFactoryImpl;
/**
* @author CBeann
* @create 2019-12-18 9:49
*/
public class Start {
public static void main(String[] args) throws Exception {
IOCFactory factory = new IOCFactoryImpl("E:\IntelliJ IDEA 2019.1.3Workspace\Demoo\demo\src\main\java\myioc\myioc.xml");
System.out.println("----单例----");
Book book1 = (Book) factory.getBean("book");
Book book2 = (Book) factory.getBean("book");
System.out.println(book1.hashCode());
System.out.println(book2.hashCode());
System.out.println("------非单例------");
Student student1 = (Student) factory.getBean("student");
Student student2 = (Student) factory.getBean("student");
System.out.println(student1.hashCode());
System.out.println(student2.hashCode());
System.out.println("-------依赖注入-------");
StudentService studentService = (StudentService) factory.getBean("studentService");
System.out.println(studentService.getStudentDao().hashCode());
StudentDao studentDao = (StudentDao) factory.getBean("studentDao");
System.out.println(studentDao.hashCode());
}
}
总结
(1)
代码语言:javascript复制 <property name="age" value="18"/>
如果上图的age是String类型,那运行正常;如果是int类型,那就会报错。现在还没有找到解决办法。。。
代码语言:javascript复制@Component
public class IntegerDemo {
@Value("#{18}")
private Integer age;
}
我看的Spring源码是最后通过BeanPostProcesser一层层调用最后到unsafe类
代码语言:javascript复制unsafe.putObject(var1, this.fieldOffset, var2);
debug发现var1是对象InegerDemo,var2是 18, this.fieldOffest(fieldOffest是传入age获得的)初步判断是插入编译后的字节码偏移量,而且这个方法在跟进去就是native方法
(2)
我认为大多数的手写都是模仿,因为物质决定意识,你见过的才会有这种思路,只有见的多了,才会有创建
(3)
可以看看Spring源码