简单的springIOC案例

一、文档介绍

1. 模块依赖

在这里插入图片描述要做好相关准备工作之前,首先要定义好各模块,说的通俗一点,主要有下面4个模块构成:
1.定义bean相关的pojo类
pojo类

PropertyValue类:

PropertyValue通俗来讲是单个bean下的单个property标签,存放该标签中的属性值,例如下图中PropertyValue存放了property标签中的各属性值(nameref或者value

    <bean id="userDao" class="com.zhkucst.dao.impl.UserDaoImpl"></bean>


    <bean id="userService" class="com.zhkucst.service.impl.UserServiceImpl">
        <property name="userDao" ref="userDao"></property>
    </bean>

MutablePropertyValues类:

MutablePropertyValues通俗来讲就是所有property标签,即可以说是PropertyValue的一个集合列表List,实现了Iterable接口,可以使用该接口下的一些实现子类的方法,从而便于对所有PropertyValue的遍历和其他CRUD操作

BeanDefinition类:

BeanDefinition通俗来讲是一个bean标签,当中包含了id属性、name属性和标签下的property标签,所以MutablePropertyValues作为了它的成员变量

2.定义注册表相关类
在这里插入图片描述
注册表相关类的实现很简单,由一个接口和它的实现类就可以了

BeanDefinitionRegistry接口:

BeanDefinitionRegistry主要是对上边的BeanDefinition类的存放和获取,即作为了BeanDefinition的一个容器

SimpleBeanDefinitionRegistry类:

SimpleBeanDefinitionRegistry是对BeanDefinitionRegistry接口方法的实现,用它来存放BeanDefinition,用的是哈希表HashMap来存放,方法的实现就是对哈希表的操作

3.定义解析器相关类
在这里插入图片描述
解析器的实现也非常简单,一个读取配置文件和获取注册表的接口,和一个实现该接口的子实现类

BeanDefinitionReader接口:

BeanDefinitionReader接口主要向外提供读取配置文件和获取注册表的方法

XmlBeanDefinitionReade实现类:

BeanDefinitionReader是用来读取配置文件,将读取到的数据封装给上面的注册表,注册表存放的数据是所有的bean对象,可以通俗地说,beanpojo类就是一个数据,而注册表registry就是一个存放数据的仓库,而解析器就是一个将数据拿到仓库的工具,涉及到数据怎么拿?怎么放到仓库?所以每一个解析器都有自己独特的获取数据和存放数据的方式

4.定义IOC容器相关类
在这里插入图片描述
顶层接口是BeanFactory,子接口是ApplicationContext,抽象类是AbstractApplicationContext,具体实现子类是AbstractApplicationContext

BeanFactory接口:

提供获取bean对象的两种抽象方法

ApplicationContext子接口:

继承顶级接口,提供加载配置文件和初始化容器的抽象方法

AbstractApplicationContext抽象实现类:

调用BeanDefinitionReader接口加载bean配置文件和获取注册表的方法,对加载配置文件和初始化容器方法的简单封装,不去实例化bean对象,只调用了抽象方法,加载后bean对象会存放到注册表中

ClassPathXmlApplicationContext继承类:

做完初始化操作,即注册表中有了bean对象的数据后,实现BeanDefinitionReader父类中调用抽象实例化bean对象的方法

2. 各模块详细uml图

1.bean相关的pojo类
在这里插入图片描述
2.注册表相关类
在这里插入图片描述
3.解析器相关类
在这里插入图片描述
4.IOC容器相关类
在这里插入图片描述

二、代码演示

工程目录:
在这里插入图片描述
其中在实例化中需要将获取到的实例名拼接为具体的方法名,从而通过setter调用实现自动实例化bean对象,这里把代码封装到utils包下的StringUtils类中

package com.itheima.framework.utils;

/**
 * @version v1.0
 * @ClassName: StringUtils
 * @Description: TODO
 * @Author: fyp
 * @data: 2021年 09月 30日 12:26
 */
public class StringUtils {
    private StringUtils() {

    }

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

}

1.bean相关的pojo类

propertyValue类:

package com.itheima.framework.beans;

/**
 * @version v1.0
 * @ClassName: PropertyValue
 * @Description: 用来封装bean标签下的property标签的属性
 *               name属性
 *               ref属性
 *               value属性:给基本数据类型及String类型数据赋的值
 * @Author: fyp
 * @data: 2021年 09月 28日 23:29
 */
public class PropertyValue {

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

    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;
    }
}

MutablePropertyValues类:

package com.itheima.framework.beans;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * @version v1.0
 * @ClassName: MutablePropertyValues
 * @Description: 用来存储和管理多个对象
 * @Author: fyp
 * @data: 2021年 09月 28日 23:35
 */
public class MutablePropertyValues implements Iterable<PropertyValue> {

    private final List<PropertyValue> propertyValueList;

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

    public MutablePropertyValues(List<PropertyValue> propertyValueList) {
        if(propertyValueList == null){
            this.propertyValueList = new ArrayList<PropertyValue>();
        }else{
            this.propertyValueList = propertyValueList;
        }
    }

    public PropertyValue[] getPropertyValues(){
        return propertyValueList.toArray(new PropertyValue[0]);
    }

    public PropertyValue getPropertyValue(String propertyName){
        for (PropertyValue propertyValue : propertyValueList) {
            if(propertyValue.getName().equals(propertyName)){
                return propertyValue;
            }
        }
        return null;
    }

    public boolean isEmpty(){
        return propertyValueList.isEmpty();
    }

    public MutablePropertyValues addPropertyValue(PropertyValue pv){
        for (int i = 0; i < propertyValueList.size(); i++) {
            PropertyValue currentPv = propertyValueList.get(i);
            if(currentPv.getName().equals(pv.getName())){
                propertyValueList.set(i,pv);
                return this;//实现链式编程
            }
        }
        this.propertyValueList.add(pv);
        return this;//实现链式编程
    }

    public boolean contains(String propertyName){
        return getPropertyValue(propertyName) != null;
    }

    public Iterator<PropertyValue> iterator(){
        return propertyValueList.iterator();
    }
}

BeanDefinition类:

package com.itheima.framework.beans;

/**
 * @version v1.0
 * @ClassName: BeanDefinition
 * @Description: 用来封装bean标签数据
 *              id属性
 *              class属性
 *              property子标签的数据
 * @Author: fyp
 * @data: 2021年 09月 29日 20:16
 */
public class BeanDefinition {

    private String id;
    private String className;

    private MutablePropertyValues propertyValues;

    public BeanDefinition() {
        this.propertyValues = 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 getPropertyValues() {
        return propertyValues;
    }

    public void setPropertyValues(MutablePropertyValues propertyValues) {
        this.propertyValues = propertyValues;
    }
}

2.注册表相关类

BeanDefinitionRegistry接口:

package com.itheima.framework.beans.factory.support;

import com.itheima.framework.beans.BeanDefinition;

/**
 * @version v1.0
 * @ClassName: BeanDefinitionRegistry
 * @Description: 注册表对象
 * @Author: fyp
 * @data: 2021年 09月 29日 21:21
 */
public interface BeanDefinitionRegistry {

    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition);

    void removeBeanDefinition(String beanName) throws Exception;

    BeanDefinition getBeanDefinition(String beanName) throws Exception;

    boolean containsBeanDefinition(String beanName);

    int getBeanDefinitionCount();

    String[] getBeanDefinitionNames();

}

SimpleBeanDefinitionRegistry实现类:

package com.itheima.framework.beans.factory.support;

import com.itheima.framework.beans.BeanDefinition;

import java.util.HashMap;
import java.util.Map;

/**
 * @version v1.0
 * @ClassName: SimpleBeanDefinitionRegistry
 * @Description: TODO
 * @Author: fyp
 * @data: 2021年 09月 29日 21:24
 */
public class SimpleBeanDefinitionRegistry implements BeanDefinitionRegistry{

    private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<String, BeanDefinition>();

    public void registerBeanDefinition(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]);
    }
}

3.解析器相关类

BeanDefinitionReader接口:

package com.itheima.framework.beans.factory.support;

/**
 * @version v1.0
 * @ClassName: BeanDefinitionReader
 * @Description: 用来解析配置文件的,而该接口只是定义了规范
 * @Author: fyp
 * @data: 2021年 09月 29日 21:46
 */
public interface BeanDefinitionReader {

    BeanDefinitionRegistry getRegistry();

    void loadBeanDefinitions(String configLocation) throws Exception;
}

XmlBeanDefinitionReader实现类:

package com.itheima.framework.beans.factory.xml;

import com.itheima.framework.beans.BeanDefinition;
import com.itheima.framework.beans.PropertyValue;
import com.itheima.framework.beans.factory.support.BeanDefinitionReader;
import com.itheima.framework.beans.factory.support.BeanDefinitionRegistry;
import com.itheima.framework.beans.factory.support.SimpleBeanDefinitionRegistry;
import com.itheima.framework.beans.MutablePropertyValues;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.InputStream;
import java.util.List;

/**
 * @version v1.0
 * @ClassName: XmlBeanDefinitionReader
 * @Description: 针对xml配置文件进行解析的类
 * @Author: fyp
 * @data: 2021年 09月 29日 21:48
 */
public class XmlBeanDefinitionReader implements BeanDefinitionReader {

    private BeanDefinitionRegistry registry;

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

    public BeanDefinitionRegistry getRegistry() {
        return registry;
    }

    public void loadBeanDefinitions(String configLocation) throws Exception {
        SAXReader reader = new SAXReader();

        InputStream is = XmlBeanDefinitionReader.class.getClassLoader().getResourceAsStream(configLocation);

        Document document = reader.read(is);

        Element rootElement = document.getRootElement();


        List<Element> beanElements = rootElement.elements("bean");
        for (Element beanElement : beanElements) {

            String id = beanElement.attributeValue("id");
            String className = beanElement.attributeValue("class");

            BeanDefinition beanDefinition = new BeanDefinition();
            beanDefinition.setId(id);
            beanDefinition.setClassName(className);

            MutablePropertyValues mutablePropertyValues = new MutablePropertyValues();

            List<Element> propertyElements = beanElement.elements("property");
            for (Element propertyElement : propertyElements) {
                String name = propertyElement.attributeValue("name");
                String ref = propertyElement.attributeValue("ref");
                String value = propertyElement.attributeValue("value");
                PropertyValue propertyValue = new PropertyValue(name, ref, value);
                mutablePropertyValues.addPropertyValue(propertyValue);
            }

            beanDefinition.setPropertyValues(mutablePropertyValues);

            registry.registerBeanDefinition(id, beanDefinition);
        }


    }
}

4.IOC容器相关类

BeanFactory接口:

package com.itheima.framework.beans.factory;

/**
 * @version v1.0
 * @ClassName: BeanFactory
 * @Description: IOC容器父接口
 * @Author: fyp
 * @data: 2021年 09月 29日 22:24
 */
public interface BeanFactory {

    Object getBean(String name) throws Exception;

    <T> T getBean(String name, Class<? extends T> clazz) throws Exception;
}

ApplicationContext子接口:

package com.itheima.framework.context;

import com.itheima.framework.beans.factory.BeanFactory;

/**
 * @version v1.0
 * @ClassName: ApplicationContext
 * @Description: 定义非延时加载功能
 * @Author: fyp
 * @data: 2021年 09月 29日 22:34
 */
public interface ApplicationContext extends BeanFactory {
    void refresh() throws Exception;
}

AbstractApplicationContext抽象实现类:

package com.itheima.framework.context.support;

import com.itheima.framework.beans.factory.support.BeanDefinitionReader;
import com.itheima.framework.beans.factory.support.BeanDefinitionRegistry;
import com.itheima.framework.context.ApplicationContext;

import java.util.HashMap;
import java.util.Map;

/**
 * @version v1.0
 * @ClassName: AbstractApplicationContext
 * @Description: ApplicationContext接口的子实现类,用于立即加载
 * @Author: fyp
 * @data: 2021年 09月 30日 11:54
 */
public abstract class AbstractApplicationContext implements ApplicationContext {

    protected BeanDefinitionReader beanDefinitionReader;

    protected Map<String, Object> singletonObjects = new HashMap<String, Object>();

    protected String configLocation;

    public void refresh() throws Exception {

        beanDefinitionReader.loadBeanDefinitions(configLocation);

        finishBeInitialization();
    }

    private void finishBeInitialization() throws Exception {
        BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();

        String[] beanNames = registry.getBeanDefinitionNames();

        for (String beanName : beanNames) {
            getBean(beanName);
        }

    }

}

ClassPathXmlApplicationContext继承类:

package com.itheima.framework.context.support;

import com.itheima.framework.beans.BeanDefinition;
import com.itheima.framework.beans.MutablePropertyValues;
import com.itheima.framework.beans.PropertyValue;
import com.itheima.framework.beans.factory.support.BeanDefinitionRegistry;
import com.itheima.framework.beans.factory.xml.XmlBeanDefinitionReader;
import com.itheima.framework.utils.StringUtils;

import java.lang.reflect.Method;

/**
 * @version v1.0
 * @ClassName: ClassPathXmlApplicationContext
 * @Description: IOC容器具体的子实现类
 *                 用于加载类路径下的xml格式的配置文件
 * @Author: fyp
 * @data: 2021年 09月 30日 12:06
 */
public class ClassPathXmlApplicationContext extends AbstractApplicationContext{

    public ClassPathXmlApplicationContext(String configLocation) {

        this.configLocation = configLocation;
        beanDefinitionReader = new XmlBeanDefinitionReader();
        try {
            this.refresh();
        }catch (Exception e) {

        }
    }

    public Object getBean(String name) throws Exception {

        Object obj = singletonObjects.get(name);
        if(obj != null) {
            return obj;
        }

        BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();
        BeanDefinition beanDefinition = registry.getBeanDefinition(name);
        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)){
                Object bean = getBean(ref);
                String methodName = StringUtils.getSetterMethodByFieldName(propertyName);
                Method[] methods = clazz.getMethods();
                for (Method method : methods) {
                    if(methodName.equals(method.getName())){
                        method.invoke(beanObj, bean);//beanObj:调用的该底层方法的对象,bean:调用该方法的参数
                    }
                }
            }

            if(value != null && !"".equals(value)){
                String methodName = StringUtils.getSetterMethodByFieldName(propertyName);
                Method method = clazz.getMethod(methodName, String.class);
                method.invoke(beanObj, value);
            }

        }

        singletonObjects.put(name, beanObj);

        return beanObj;
    }

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

就这些吧
算了算了,再写个实例给大家验证下吧

controller代码:

package com.zhkucst.controller;

import com.itheima.framework.context.ApplicationContext;
import com.itheima.framework.context.support.ClassPathXmlApplicationContext;
import com.zhkucst.service.UserService;

/**
 * @version v1.0
 * @ClassName: UserController
 * @Description: TODO
 * @Author: fyp
 * @data: 2021年 09月 23日 22:08
 */
public class UserController {
    public static void main(String[] args) throws Exception {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //XmlBeanFactory xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
        //UserService userService = xmlBeanFactory.getBean("userService", UserService.class);
        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.add();
    }
}

Userdao代码:

package com.zhkucst.dao.impl;

import com.zhkucst.dao.UserDao;

/**
 * @version v1.0
 * @ClassName: UserDaoImpl
 * @Description: TODO
 * @Author: fyp
 * @data: 2021年 09月 23日 21:59
 */
public class UserDaoImpl implements UserDao {

    private String username;
    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public UserDaoImpl(){
        System.out.println("userDao被创建了");
    }

    @Override
    public void add() {
        System.out.println("UserDao:" + username + "==" + password);
    }
}

UserService代码:

package com.zhkucst.service.impl;

import com.zhkucst.dao.UserDao;
import com.zhkucst.service.UserService;
import sun.security.util.Password;

/**
 * @version v1.0
 * @ClassName: UserServiceImpl
 * @Description: TODO
 * @Author: fyp
 * @data: 2021年 09月 23日 21:59
 */
public class UserServiceImpl implements UserService {

    private UserDao userDao;

    public UserServiceImpl() {
        System.out.println("userService被创建了");
    }

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

    @Override
    public void add() {
        System.out.println("UserService...");
        userDao.add();
    }
}

配置文件applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans>

    <!--spring配置文件: 声明service, dao, 工具类等对象-->

    <bean id="userDao" class="com.zhkucst.dao.impl.UserDaoImpl">
        <property name="username" value="zs"></property>
        <property name="password" value="123456"></property>
    </bean>

    <bean id="userService" class="com.zhkucst.service.impl.UserServiceImpl">
        <property name="userDao" ref="userDao"></property>
    </bean>



</beans>

结果:
在这里插入图片描述

最后说明:
本文是对B站博主黑马程序员的设计模式中案例的使用,并且对其做了总结,链接:https://www.bilibili.com/video/BV1Np4y1z7BU?p=154
以及自己对案例的看法和解释
如有冒犯,请联系作者

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嗝屁小孩纸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值