栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

简易Spring IOC实现

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

简易Spring IOC实现

本代码来自https://www.bilibili.com/video/BV1Np4y1z7BU?p=137

spring IOC相关接口分析 BeanFactory解析

BeanFactory是最基础的一个接口,他之定义了IOC容器的基本规范,但是不规定具体要生产那些产品,具体的生产步骤交给该接口的子实现类去实现。

public interface BeanFactory {


	String FACTORY_BEAN_PREFIX = "&";
	
    // 根据beanName获取IOC容器中的对象
	Object getBean(String name) throws BeansException;
	
	// 根据beanName获取IOC容器中的对象,并且强转成requiredType类型
	 T getBean(String name, Class requiredType) throws BeansException;

	
	Object getBean(String name, Object... args) throws BeansException;

	
	 T getBean(Class requiredType) throws BeansException;

	
	 T getBean(Class requiredType, Object... args) throws BeansException;

	
	 ObjectProvider getBeanProvider(Class requiredType);

	
	 ObjectProvider getBeanProvider(ResolvableType requiredType);

	// 判断容器中是否包含指定名称的bean对象
	boolean containsBean(String name);

	// 判断相应beanName的bean对象是否是单例的
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

	
	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

	
	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

	
	boolean isTypeMatch(String name, Class typeToMatch) throws NoSuchBeanDefinitionException;

	
	@Nullable
	Class getType(String name) throws NoSuchBeanDefinitionException;

	
	String[] getAliases(String name);

}

我们在使用spring的时候通常都是用ClassPathXmlApplicationContext来生成一个容器

public class Application {
    @Test
    public void test(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
        UserController userController = (UserController) applicationContext.getBean("userController");
        userController.add();
    }
}

下面我们来看一下ClassPathXmlApplicationContext的具体内容

public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {

	@Nullable
	private Resource[] configResources;

	// 无参构造
	public ClassPathXmlApplicationContext() {
	}

	// 调用父类初始化
	public ClassPathXmlApplicationContext(ApplicationContext parent) {
		super(parent);
	}
	
    // 传入xml的文件目录,最后会跳转到核心方法
	public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
		this(new String[] {configLocation}, true, null);
	}
	
	public ClassPathXmlApplicationContext(String... configLocations) throws BeansException {
		this(configLocations, true, null);
	}


	public ClassPathXmlApplicationContext(String[] configLocations, @Nullable ApplicationContext parent)
			throws BeansException {

		this(configLocations, true, parent);
	}


	public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException {
		this(configLocations, refresh, null);
	}

	
    // 这是构造方法中的核心方法,其中调用了refresh,这个方法就是非延时加载
	public ClassPathXmlApplicationContext(
			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {

		super(parent);
		setConfigLocations(configLocations);
		if (refresh) {
			refresh();
		}
	}



	public ClassPathXmlApplicationContext(String path, Class clazz) throws BeansException {
		this(new String[] {path}, clazz);
	}


	public ClassPathXmlApplicationContext(String[] paths, Class clazz) throws BeansException {
		this(paths, clazz, null);
	}


	public ClassPathXmlApplicationContext(String[] paths, Class clazz, @Nullable ApplicationContext parent)
			throws BeansException {

		super(parent);
		Assert.notNull(paths, "Path array must not be null");
		Assert.notNull(clazz, "Class argument must not be null");
		this.configResources = new Resource[paths.length];
		for (int i = 0; i < paths.length; i++) {
			this.configResources[i] = new ClassPathResource(paths[i], clazz);
		}
		refresh();
	}


	@Override
	@Nullable
	protected Resource[] getConfigResources() {
		return this.configResources;
	}

}
BeanDefinition解析

spring IOC容器中使用BeanDefinition来定义Bean对象

public interface BeanDefinition extends AttributeAccessor, BeanmetadataElement {

	
	String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;

	
	String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

	
	int ROLE_APPLICATION = 0;

	
	int ROLE_SUPPORT = 1;

	
	int ROLE_INFRASTRUCTURE = 2;

	
	void setParentName(@Nullable String parentName);

	
	@Nullable
	String getParentName();

	
	void setBeanClassName(@Nullable String beanClassName);

	
	@Nullable
	String getBeanClassName();

	
	void setScope(@Nullable String scope);

	
	@Nullable
	String getScope();

	
	void setLazyInit(boolean lazyInit);

	
	boolean isLazyInit();

	
	void setDependsOn(@Nullable String... dependsOn);

	
	@Nullable
	String[] getDependsOn();

	
	void setAutowireCandidate(boolean autowireCandidate);

	
	boolean isAutowireCandidate();

	
	void setPrimary(boolean primary);

	
	boolean isPrimary();

	
	void setFactoryBeanName(@Nullable String factoryBeanName);

	
	@Nullable
	String getFactoryBeanName();

	
	void setFactoryMethodName(@Nullable String factoryMethodName);

	
	@Nullable
	String getFactoryMethodName();

	
	ConstructorArgumentValues getConstructorArgumentValues();

	
	default boolean hasConstructorArgumentValues() {
		return !getConstructorArgumentValues().isEmpty();
	}

	
	MutablePropertyValues getPropertyValues();

	
	default boolean hasPropertyValues() {
		return !getPropertyValues().isEmpty();
	}

	
	void setInitMethodName(@Nullable String initMethodName);

	
	@Nullable
	String getInitMethodName();

	
	void setDestroyMethodName(@Nullable String destroyMethodName);

	
	@Nullable
	String getDestroyMethodName();

	
	void setRole(int role);

	
	int getRole();

	
	void setDescription(@Nullable String description);

	
	@Nullable
	String getDescription();


	
	boolean isSingleton();

	
	boolean isPrototype();

	
	boolean isAbstract();

	
	@Nullable
	String getResourceDescription();

	
	@Nullable
	BeanDefinition getOriginatingBeanDefinition();

}
BeanDefinitionReader解析

BeanDefinitionReader主要完成Bean的解析

public interface BeanDefinitionReader {


    // 这个方法是重点方法,获取注册表
	BeanDefinitionRegistry getRegistry();


	@Nullable
	ResourceLoader getResourceLoader();

	@Nullable
	ClassLoader getBeanClassLoader();


	BeanNameGenerator getBeanNameGenerator();


	// 加载配置文件,并解析成BeanDefinitions
	int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;
	int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;
	int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;
	int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException;

}
BeanDefinitionRegistry解析

这类接口用来封装BeanDefinition

public interface BeanDefinitionRegistry extends AliasRegistry {

	// 往注册表中注册bean
	void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException;

	// 从注册表中删除指定名称的bean
	void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

	// 获取注册表中指定名称的bean
	BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

	// 判断注册表中是否一定注册了指定名称的bean
	boolean containsBeanDefinition(String beanName);

	// 获取注册表中所有bean的名称
	String[] getBeanDefinitionNames();

	// 获取注册表中已经注册的bean数量
	int getBeanDefinitionCount();

	
	boolean isBeanNameInUse(String beanName);

}

这个接口中的子实现类中最简单是SimpleBeanDefinitionRegistry

public class SimpleBeanDefinitionRegistry extends SimpleAliasRegistry implements BeanDefinitionRegistry {

	
	private final Map beanDefinitionMap = new ConcurrentHashMap<>(64);


	@Override
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

		Assert.hasText(beanName, "'beanName' must not be empty");
		Assert.notNull(beanDefinition, "BeanDefinition must not be null");
		this.beanDefinitionMap.put(beanName, beanDefinition);
	}

	@Override
	public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
		if (this.beanDefinitionMap.remove(beanName) == null) {
			throw new NoSuchBeanDefinitionException(beanName);
		}
	}

	@Override
	public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
		BeanDefinition bd = this.beanDefinitionMap.get(beanName);
		if (bd == null) {
			throw new NoSuchBeanDefinitionException(beanName);
		}
		return bd;
	}

	@Override
	public boolean containsBeanDefinition(String beanName) {
		return this.beanDefinitionMap.containsKey(beanName);
	}

	@Override
	public String[] getBeanDefinitionNames() {
		return StringUtils.toStringArray(this.beanDefinitionMap.keySet());
	}

	@Override
	public int getBeanDefinitionCount() {
		return this.beanDefinitionMap.size();
	}

	@Override
	public boolean isBeanNameInUse(String beanName) {
		return isAlias(beanName) || containsBeanDefinition(beanName);
	}

}
创建容器

我们调用ClassPathXmlApplicationContext创建容器的时候是调用refresh()方法,该方法是由AbstractXmlApplicationContext具体实现的。

public abstract class AbstractApplicationContext extends DefaultResourceLoader
		implements ConfigurableApplicationContext {
    // ...
    
    // 这个方法非常重要,主要的创建bean对象的步骤都在里面
 	@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}   
    // ...
}
自制spring IOC容器 PropertyValue

我们首先需要定义一个PropertyValue类来存储bean标签中的property标签,其中有三个属性:name,ref和value,分别用来存储property标签的属性。

public class PropertyValue {

    private String name;
    private String ref;
    private String value;

    public PropertyValue() {}

    public PropertyValue(String name, String ref, String value) {
        this.name = name;
        this.ref = ref;
        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 String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return "PropertyValue{" +
                "name='" + name + ''' +
                ", ref='" + ref + ''' +
                ", value='" + value + ''' +
                '}';
    }
}
MutablePropertyValues

由于一个bean标签可以有多个子标签,因此我们需要定义一个MutablePropertyValues类来存储和管理多个PropertyValue类

public class MutablePropertyValues implements Iterator {

    // 定义一个容器,用来存放PropertyValue对象
    private final List propertyValueList;

    public MutablePropertyValues(){
        this.propertyValueList = new ArrayList();
    }

    public MutablePropertyValues(List propertyValueList) {
        if(propertyValueList == null){
            this.propertyValueList = new ArrayList();
            return;
        }
        this.propertyValueList = propertyValueList;
    }

    // 将PropertyValues的内容以数组的形式返回
    public PropertyValue[] getPropertyValues(){
        return propertyValueList.toArray(new PropertyValue[0]);
    }

    // 根据name属性值获取PropertyValue对象
    public PropertyValue getPropertyValueByName(String name){
        for(PropertyValue propertyValue : propertyValueList){
            if(propertyValue.getName().equals(name)){
                return propertyValue;
            }
        }
        //throw new RuntimeException("没有[name="+name+"]的PropertyValue对象");
        return null;
    }

    // 判断集合是否为空
    public boolean isEmpty(){
        return propertyValueList.size()==0 ? true : false;
    }

    // 添加PropertyValue对象
    public MutablePropertyValues addPropertyValue(PropertyValue pv){
        // 判断传入的PropertyValue对象是否已经在容器中
        // 如果是,那么直接覆盖;如果不是,那么就将pv对象添加到容器中
        for(int i=0; i 
BeanDefinition 

BeanDefinition用来存储bean信息,主要包括id,class还有子标签property数据

public class BeanDefinition {

    private String id;
    private String className;

    private MutablePropertyValues mutablePropertyValues;


    public BeanDefinition(){
        this.mutablePropertyValues = new MutablePropertyValues();
    }

    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 MutablePropertyValues getMutablePropertyValues() {
        return mutablePropertyValues;
    }

    public void setMutablePropertyValues(MutablePropertyValues mutablePropertyValues) {
        this.mutablePropertyValues = mutablePropertyValues;
    }
}
BeanDefinitionRegistry接口

BeanDefinitionRegistry接口定义注册表的相关操作,包括

注册BeanDefinition对象到注册表中

从注册表中删除指定名称的BeanDefinition对象

根据名称从注册表中获取BeanDefinition对象

判断注册表中是否包含指定名称的BeanDefinition对象

获取注册表中BeanDefinition对象的个数

获取注册表中所有的BeanDefinition的名称

public interface BeanDefinitionRegistry {


    // 注册BeanDefinition对象到注册表中
    void registerBeanDefinitin(String beanName, BeanDefinition beanDefinition);

    // 从注册表中删除指定名称的BeanDefinition对象
    void removeBeanDefinition(String beanName) throws Exception;

    // 根据名称从注册表中获取BeanDefinition对象
    BeanDefinition getBeanDefinition(String beanName) throws Exception;

    // 判断注册表中是否包含指定名称的BeanDefinition对象
    boolean containsBeanDefinition(String beanName);

    // 获取注册表中BeanDefinition对象的个数
    int getBeanDefinitionCount();

    // 获取注册表中所有的BeanDefinition的名称
    String[] getBeanDefinitionNames();

}
SimpleBeanDefinitionRegistry

SimpleBeanDefinitionRegistry是BeanDefinitionRegistry的一个子实现类

public class SimpleBeanDefinitionRegistry implements BeanDefinitionRegistry{

    // 定义一个容器,用来存储BeanDefinition对象
    private Map beanDefinitionMap = new HashMap();


    public void registerBeanDefinitin(String beanName, BeanDefinition beanDefinition) {
        beanDefinitionMap.put(beanName, beanDefinition);
    }

    public void removeBeanDefinition(String beanName) throws Exception {
        beanDefinitionMap.remove(beanName);
    }

    public BeanDefinition getBeanDefinition(String beanName) throws Exception {
        return beanDefinitionMap.get(beanName);
    }

    public boolean containsBeanDefinition(String beanName) {
        return beanDefinitionMap.containsKey(beanName);
    }

    public int getBeanDefinitionCount() {
        return beanDefinitionMap.size();
    }

    public String[] getBeanDefinitionNames() {
        return beanDefinitionMap.keySet().toArray(new String[0]);
    }
}
BeanDefinitionReader接口

BeanDefinitionReader用来解析配置文件,并在注册表中注册bean信息,定义了两个规范

获取注册表

加载配置文件并注册bean信息

public interface BeanDefinitionReader {

    // 获取注册表
    BeanDefinitionRegistry getRegistry();

    // 加载配置文件,并注册bean信息
    void loadBeanDefinitions(String configLocation) throws Exception;
    
}
XmlBeanDefinitionReader

XmlBeanDefinitionReader是BeanDefinitionReader的子实现类,使用dom4j解析xml配置文件

public class XmlBeanDefinitionReader implements BeanDefinitionReader {

    // 声明注册表对象
    private BeanDefinitionRegistry registry;

    public XmlBeanDefinitionReader(){
        registry = new SimpleBeanDefinitionRegistry();
    }

    public BeanDefinitionRegistry getRegistry() {
        return registry;
    }


    public void loadBeanDefinitions(String configLocation) throws Exception {
        // 使用dom4j进行配置文件解析
        SAXReader reader = new SAXReader();
        // 获取类路径下的配置文件
        InputStream resourceAsStream = XmlBeanDefinitionReader.class.getClassLoader().getResourceAsStream(configLocation);
        document document = reader.read(resourceAsStream);
        // 根据document对象获取根标签对象(beans)
        Element rootElement = document.getRootElement();
        // 获取根标签下所有的bean标签对象(bean)
        List beanElements = rootElement.elements("bean");
        // 遍历集合
        for(Element bean : beanElements){
            // 获取id属性
            String id = bean.attributevalue("id");
            // 获取class属性
            String className = bean.attributevalue("class");
            // 将id属性和class属性封装到BeanDefinition对象中
            // 创建BeanDefinition
            BeanDefinition beanDefinition = new BeanDefinition();
            beanDefinition.setId(id);
            beanDefinition.setClassName(className);
            // 获取property对象
            List propertyElements = bean.elements("property");
            MutablePropertyValues mutablePropertyValues = new MutablePropertyValues();
            for(Element property : propertyElements){
                String name = property.attributevalue("name");
                String ref = property.attributevalue("ref");
                String value = property.attributevalue("value");
                PropertyValue propertyValue = new PropertyValue(name, ref, value);
                mutablePropertyValues.addPropertyValue(propertyValue);
            }
            beanDefinition.setMutablePropertyValues(mutablePropertyValues);
            // 将BeanDefinition对象注册到注册表中
            registry.registerBeanDefinitin(id, beanDefinition);
        }
    }
}
BeanFactory接口

在该接口中定义IOC容易的统一规范,即获取bean对象

public interface BeanFactory {

    Object getBean(String name) throws Exception;

     T getBean(String name, Class clazz) throws Exception;
}
ApplicationContext接口

在该接口中定义refresh()方法,该接口主要完成两个功能

加载配置文件根据注册表中的BeanDefinition对象封装的数据进行bean的创建

public interface ApplicationContext extends BeanFactory {

    void refresh() throws Exception;

}
AbstractApplicationContext

该类是ApplicationContext的子实现类,可以实现非延时加载。需要在类中定义一个Map容器,用来存储bean对象声明BeanDefinitionReader类型的变量,用来进行配置文件的解析

public abstract class AbstractApplicationContext implements ApplicationContext {

    // xml解析器
    protected BeanDefinitionReader beanDefinitionReader;

    // 存放bean对象的容器
    protected Map singletonObject = new HashMap();

    // 配置文件类路径的变量
    protected String ConfigLocation;


    public void refresh() throws Exception {
        // 加载BeanDefinition对象
        beanDefinitionReader.loadBeanDefinitions(ConfigLocation);
        // 初始化bean
        finishBeanInitialization();
    }

    // 初始化bean
    private void finishBeanInitialization() throws Exception{
        // 获取注册表
        BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();

        // 获取BeanDefinition对象
        String[] beanNames = registry.getBeanDefinitionNames();
        // 进行bean的初始化
        for(String beanName : beanNames){
            getBean(beanName);
        }
    }
}
ClassPathXmlApplicationContext

该类加载类路径下的配置文件,并进行bean对象的创建,主要完成一下功能

在构造方法中创建BeanDefinitionReader对象在构造方法中调用refresh()方法重写父接口中的getbean()方法,并实现依赖注入操作

public class ClassPathXmlApplicationContext extends AbstractApplicationContext{

    public ClassPathXmlApplicationContext(String ConfigLocation){
        this.ConfigLocation = ConfigLocation;
        // 构建解析器对象
        beanDefinitionReader = new XmlBeanDefinitionReader();
        try{
            refresh();
        } catch (Exception e){

        }
    }


    // 根据bean对象的名称获取bean对象
    public Object getBean(String name) throws Exception {
        // 判断对象容器中是否包含指定名称的bean对象
        // 如果包含直接返回;如果不含包,需要自行创建
        Object obj = singletonObject.get(name);
        if(obj != null){
            return obj;
        }
        // 获取BeanDefinition对象
        BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();
        BeanDefinition beanDefinition = registry.getBeanDefinition(name);
        // 获取bean信息中的className
        String className = beanDefinition.getClassName();
        // 通过反射创建对象
        Class clazz = Class.forName(className);
        Object beanObj = clazz.newInstance();

        // 依赖注入
        MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
        for(PropertyValue propertyValue : propertyValues){
            String propertyName = propertyValue.getName();
            String value = propertyValue.getValue();
            String ref = propertyValue.getRef();
            if(ref!=null && !"".equals(ref)){
                // 获取依赖的bean对象
                Object bean = getBean(ref);
                // 拼接方法名
                String methodName = StringUtils.getSetMethodByFieldName(propertyName);
                // 获取所有的方法对象
                Method[] methods = clazz.getMethods();
                for(Method method : methods){
                    if(method.getName().equals(methodName)){
                        // 执行该方法
                        method.invoke(beanObj, bean);
                    }
                }
            }
            if(value!=null && !"".equals(value)){
                // 拼接方法名
                String methodName = StringUtils.getSetMethodByFieldName(propertyName);
                // 获取method对象
                Method method = clazz.getMethod(methodName);
                method.invoke(beanObj, value);
            }
        }

        // 在返回beanObj对象前将该对象存储到map容器中
        singletonObject.put(name, beanObj);

        return beanObj;
    }

    public  T getBean(String name, Class clazz) throws Exception {
        Object bean = getBean(name);
        if(bean == null){
            return null;
        }
        return clazz.cast(bean);
    }
}

上面的代码用到了StringUtils工具类

public class StringUtils {

    private StringUtils(){}

    public static String getSetMethodByFieldName(String FieldName){
        String methodName = "set" + FieldName.substring(0,1).toUpperCase() + FieldName.substring(1);
        return methodName;
    }

}

项目的完整架构如下

测试代码

我们编写一个简单的项目进行测试

项目分为controller层,service层和dao层,整体架构如下

public interface UserDao {

    // 添加方法
    public void add();

}
public class UserDaoImpl implements UserDao {

    public UserDaoImpl(){
        System.out.println("UserDaoImpl init ...");
    }

    public void add() {
        System.out.println("UserDao add ...");
    }
}
public interface UserService {

    public void add();

}
public class UserServiceImpl implements UserService {

    UserDao userDao;

    public UserServiceImpl(){
        System.out.println("UserServiceImpl init ...");
    }


    public UserDao getUserDao() {
        return userDao;
    }

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void add() {
        System.out.println("UserService add ...");
        userDao.add();
    }
}
public class UserController {

    UserService userService;

    public UserController(){
        System.out.println("UserController init ...");
    }

    public UserService getUserService() {
        return userService;
    }

    public void setUserService(UserService userService) {
        this.userService = userService;
    }


    public void add(){
        System.out.println("UserController add ...");
        userService.add();
    }

}

最后编写一个测试类Application进行测试

public class Application {
    @Test
    public void test() throws Exception{
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
        UserController userController = (UserController) applicationContext.getBean("userController");
        userController.add();
    }

}

测试结果如下所示

总结

该项目看起来十分复杂,但是将其简化后,调理还是较为清晰的。

首先,总体上可以分成以下几个部分

用来封装Bean标签的BeanDefinition,该对象里面有MutablePropertyValues对象,MutablePropertyValues又是由PropertyValue组成用来存放BeanDefinition的注册表接口BeanDefinitionRegistry,该接口的子实现类为SimpleBeanDefinitionRegistry用来进行配置文件解析的BeanDefinitionReader接口,该接口中包含有一个BeanDefinitionRegistry属性,其子实现类XmlBeanDefinitionReader实现了loadBeanDefinitions()方法,该方法解析配置文件,并且将标签的内容封装成BeanDefinition对象注册到注册表中最后就是我们进行非延时加载的容器ApplicationContext,最后我们使用的是ClassPathXmlApplicationContext,这一系列的继承实现关系较为复杂,可以用下面一张图表示。

上图就是容器对象的继承实现关系,其中有几个点是非常重要的。AbstractApplicationContext这个类中定义了xml解析器BeanDefinitionReader,该解析器的子实现类XmlBeanDefinitionReader中有注册表BeanDefinitionRegistry,进行实例化的时候,用的是注册表的子实现类SimpleBeanDefinitionRegistry。

AbstractApplicationContext中还有存放bean对象的容器Map singletonObject,实例化后的bean对象都存放到这里。

refresh()完成bean对象的创建,其步骤为:1)加载所有的BeanDefinition对象。2)获取BeanDefinition对象,生成相应的bean对象并且注册到注册表中。

public abstract class AbstractApplicationContext implements ApplicationContext {

    // xml解析器
    protected BeanDefinitionReader beanDefinitionReader;

    // 存放bean对象的容器
    protected Map singletonObject = new HashMap();

    // 配置文件类路径的变量
    protected String ConfigLocation;


    public void refresh() throws Exception {
        // 加载BeanDefinition对象
        beanDefinitionReader.loadBeanDefinitions(ConfigLocation);
        // 初始化bean
        finishBeanInitialization();
    }

    // 初始化bean
    private void finishBeanInitialization() throws Exception{
        // 获取注册表
        BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();

        // 获取BeanDefinition对象
        String[] beanNames = registry.getBeanDefinitionNames();
        // 进行bean的初始化
        for(String beanName : beanNames){
            getBean(beanName);
        }
    }
}

refresh()方法中用到了finishBeanInitialization()方法,其中有一个getBean()方法,该方法的具体实现是在ClassPathXmlApplicationContext中完成的。

public class ClassPathXmlApplicationContext extends AbstractApplicationContext{
	//...


    // 根据bean对象的名称获取bean对象
    public Object getBean(String name) throws Exception {
        // 判断对象容器中是否包含指定名称的bean对象
        // 如果包含直接返回;如果不含包,需要自行创建
        Object obj = singletonObject.get(name);
        if(obj != null){
            return obj;
        }
        // 获取BeanDefinition对象
        BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();
        BeanDefinition beanDefinition = registry.getBeanDefinition(name);
        // 获取bean信息中的className
        String className = beanDefinition.getClassName();
        // 通过反射创建对象
        Class clazz = Class.forName(className);
        Object beanObj = clazz.newInstance();

        // 依赖注入
        MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
        for(PropertyValue propertyValue : propertyValues){
            String propertyName = propertyValue.getName();
            String value = propertyValue.getValue();
            String ref = propertyValue.getRef();
            if(ref!=null && !"".equals(ref)){
                // 获取依赖的bean对象
                Object bean = getBean(ref);
                // 拼接方法名
                String methodName = StringUtils.getSetMethodByFieldName(propertyName);
                // 获取所有的方法对象
                Method[] methods = clazz.getMethods();
                for(Method method : methods){
                    if(method.getName().equals(methodName)){
                        // 执行该方法
                        method.invoke(beanObj, bean);
                    }
                }
            }
            if(value!=null && !"".equals(value)){
                // 拼接方法名
                String methodName = StringUtils.getSetMethodByFieldName(propertyName);
                // 获取method对象
                Method method = clazz.getMethod(methodName);
                method.invoke(beanObj, value);
            }
        }

        // 在返回beanObj对象前将该对象存储到map容器中
        singletonObject.put(name, beanObj);

        return beanObj;
    }

    public  T getBean(String name, Class clazz) throws Exception {
        Object bean = getBean(name);
        if(bean == null){
            return null;
        }
        return clazz.cast(bean);
    }
}

以上代码已经非常复杂了,但是相对于spring源码来说还是小巫见大巫。可见,读源码还是一件非常困难的工作,想要写出spring这种级别的代码是需要长时间的学习和积累的。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/704920.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号