实现bean的自动创建
本次主要是对ApplicationContext applicationContext = new MyClassPathXmlApplicationContext(“spring-ioc.xml”);进行底层解析
能够更深度理解机制
思路:(实际上就是工厂模式)
1、根据需求编写XML文件,配置需要创建的bean
2、编写程序读取XML文件,获取bean相关信息,比如id、name、类、属性
3、根据第二步获取到的信息,结合反射机制动态创建对象,同时完成属性的赋值。
4、将创建好的bean存入Map集合中,设置key-value映射,key就是bean的id值,value就是bean对象
5、提供方法从Map中通过id获取到对应的value。
这个思路很重要
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
">
<bean id="car" class="com.linko.entity.Car">
<property name="num" value="1"></property>
<property name="brand" value="奥迪"></property>
<property name="price" value="30.5"></property>
</bean>
</beans>
Car实体类
package com.linko.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Car {
private Integer num;
private String brand;
private Double price;
}
MyClassPathXmlApplicationContext
里面有很多函数是没有用到的,是接口所要实现的,我们主要是调用getBean函数,所以只需要使用这一个即可
package com.linko.ioc;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.context.NoSuchMessageException;
import org.springframework.core.ResolvableType;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.xml.sax.SAXException;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.SQLOutput;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
public class MyClassPathXmlApplicationContext implements ApplicationContext {
private Map<String,Object> iocMap;
public MyClassPathXmlApplicationContext(String path){
iocMap = new HashMap<String, Object>();
//解析XML
parseXML(path);
}
public void parseXML(String path){
SAXReader saxReader = new SAXReader();
try {
Document document = saxReader.read("src/main/resources/" + path);
//拿到bean
Element root = document.getRootElement();//找到bean
Iterator<Element> rootIter = root.elementIterator();//迭代bean文件
while (rootIter.hasNext()) {
Element bean = rootIter.next();
//获取id啥的
String idStr = bean.attributeValue("id");
String className = bean.attributeValue("class");
// System.out.println(idStr);
// System.out.println(className);
//反射动态创建对象
Class clazz = Class.forName(className);
//获取无参构造
Constructor constructor = clazz.getConstructor();
// System.out.println(constructor);
//创建对象
Object object = constructor.newInstance();
// System.out.println(object);//表明我们已经创建好了,接下来就要放到容器了。
//bean容器中我们采用Map的形式去存储实体类里的信息
//给属性赋值,所以我们要读取bean里面的property
Iterator<Element> beanInter = bean.elementIterator();
while(beanInter.hasNext()){
Element property = beanInter.next();
// System.out.println(property);
String propertyName = property.attributeValue("name");
String propertyValue = property.attributeValue("value");
// System.out.println(propertyName + "-" + propertyValue);
//通过set方法赋值,获取setter方法
//num-setNum,brand-setBrand
String methodName = "set" + propertyName.substring(0,1).toUpperCase() + propertyName.substring(1);
// System.out.println(methodName);
//获取属性
// Field field = clazz.getField(propertyName);//这个只能是获取公有的public
Field field = clazz.getDeclaredField(propertyName);//这个是获取具有访问权限的
// System.out.println(field.getType());//获取参数类型
Method method = clazz.getMethod(methodName,field.getType());//后面是属性对应的类型,如Integer
//调用invoke,这个函数有两个参数,第一个是对象,第二个是属性值,有...是表明是可变参数
//类型转换,因为我们读到的是String类型,但是实体类是有它自己的类型,所以需要转化
Object value= propertyValue;//这个是属性的值,然后不同值是通过多重循环得到的
if(field.getType().getName() == "java.lang.Integer"){
value = Integer.parseInt(propertyValue);
}else if(field.getType().getName() == "java.lang.Double"){
value = Double.parseDouble(propertyValue);
}
method.invoke(object,value);
System.out.println(method);
}
//存入Map
iocMap.put(idStr,object);
//然后ClassPathXmlApplicationContext本身含有getBean函数,所以我们只需要使用即可
}
// System.out.println(document);
} catch (DocumentException e) {
e.printStackTrace();
}catch (ClassNotFoundException e) {
e.printStackTrace();
}catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}catch (NoSuchFieldException e) {
e.printStackTrace();
}
/*不建议使用这种方式,因为不利于排查错误
catch (Exception e){
e.printStackTrace();
}*/
}
public String getId() {
return null;
}
public String getApplicationName() {
return null;
}
public String getDisplayName() {
return null;
}
public long getStartupDate() {
return 0;
}
public ApplicationContext getParent() {
return null;
}
public AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException {
return null;
}
public BeanFactory getParentBeanFactory() {
return null;
}
public boolean containsLocalBean(String s) {
return false;
}
public boolean containsBeanDefinition(String s) {
return false;
}
public int getBeanDefinitionCount() {
return 0;
}
public String[] getBeanDefinitionNames() {
return new String[0];
}
public <T> ObjectProvider<T> getBeanProvider(Class<T> aClass, boolean b) {
return null;
}
public <T> ObjectProvider<T> getBeanProvider(ResolvableType resolvableType, boolean b) {
return null;
}
public String[] getBeanNamesForType(ResolvableType resolvableType) {
return new String[0];
}
public String[] getBeanNamesForType(ResolvableType resolvableType, boolean b, boolean b1) {
return new String[0];
}
public String[] getBeanNamesForType(Class<?> aClass) {
return new String[0];
}
public String[] getBeanNamesForType(Class<?> aClass, boolean b, boolean b1) {
return new String[0];
}
public <T> Map<String, T> getBeansOfType(Class<T> aClass) throws BeansException {
return null;
}
public <T> Map<String, T> getBeansOfType(Class<T> aClass, boolean b, boolean b1) throws BeansException {
return null;
}
public String[] getBeanNamesForAnnotation(Class<? extends Annotation> aClass) {
return new String[0];
}
public Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> aClass) throws BeansException {
return null;
}
public <A extends Annotation> A findAnnotationOnBean(String s, Class<A> aClass) throws NoSuchBeanDefinitionException {
return null;
}
public Object getBean(String s) throws BeansException {
return iocMap.get(s);
}
public <T> T getBean(String s, Class<T> aClass) throws BeansException {
return null;
}
public Object getBean(String s, Object... objects) throws BeansException {
return null;
}
public <T> T getBean(Class<T> aClass) throws BeansException {
return null;
}
public <T> T getBean(Class<T> aClass, Object... objects) throws BeansException {
return null;
}
public <T> ObjectProvider<T> getBeanProvider(Class<T> aClass) {
return null;
}
public <T> ObjectProvider<T> getBeanProvider(ResolvableType resolvableType) {
return null;
}
public boolean containsBean(String s) {
return false;
}
public boolean isSingleton(String s) throws NoSuchBeanDefinitionException {
return false;
}
public boolean isPrototype(String s) throws NoSuchBeanDefinitionException {
return false;
}
public boolean isTypeMatch(String s, ResolvableType resolvableType) throws NoSuchBeanDefinitionException {
return false;
}
public boolean isTypeMatch(String s, Class<?> aClass) throws NoSuchBeanDefinitionException {
return false;
}
public Class<?> getType(String s) throws NoSuchBeanDefinitionException {
return null;
}
public Class<?> getType(String s, boolean b) throws NoSuchBeanDefinitionException {
return null;
}
public String[] getAliases(String s) {
return new String[0];
}
public void publishEvent(Object event) {
}
public String getMessage(String code, Object[] args, String defaultMessage, Locale locale) {
return null;
}
public String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException {
return null;
}
public String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException {
return null;
}
public Environment getEnvironment() {
return null;
}
public Resource[] getResources(String s) throws IOException {
return new Resource[0];
}
public Resource getResource(String s) {
return null;
}
public ClassLoader getClassLoader() {
return null;
}
}
Test测试类
package com.linko.ioc;
import com.linko.entity.Car;
import org.springframework.context.ApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext = new MyClassPathXmlApplicationContext("spring-ioc.xml");
Car car = (Car)applicationContext.getBean("car");
System.out.println(car);
}
}