实践
项目目录结构
项目下载
https://github.com/cbeann/Demoo/tree/master/ioc-demo
pom
<!--解析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的定义信息
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
package myioc.entity; /** * @author CBeann * @create 2019-12-18 10:47 */ public class Book { public void speak(){ System.out.println("------Book-------"); } }
Student
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
package myioc.entity; /** * @author CBeann * @create 2019-12-18 10:06 */ public class StudentDao { public StudentDao() { } public void speak() { System.out.println("-----StudentDao------"); } }
StudentService
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工厂类
工厂接口
package myioc.factory; /** * @author CBeann * @create 2019-12-18 9:46 */ public interface IOCFactory { /** * 根据名称获得Bean */ public Object getBean(String beanName) throws Exception; }
工厂实现类
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
<?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>
启动类
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)
<property name="age" value="18"/>
如果上图的age是String类型,那运行正常;如果是int类型,那就会报错。现在还没有找到解决办法。。。
@Component public class IntegerDemo { @Value("#{18}") private Integer age; }
我看的Spring源码是最后通过BeanPostProcesser一层层调用最后到unsafe类
unsafe.putObject(var1, this.fieldOffset, var2);
debug发现var1是对象InegerDemo,var2是 18, this.fieldOffest(fieldOffest是传入age获得的)初步判断是插入编译后的字节码偏移量,而且这个方法在跟进去就是native方法
(2)
我认为大多数的手写都是模仿,因为物质决定意识,你见过的才会有这种思路,只有见的多了,才会有创建
(3)
可以看看Spring源码