设计模式---综合应用-自定义Spring框架-自定义Spring IOC-定义解析器、IOC容器相关类

news2024/11/21 0:33:16

3 定义解析器相关类

3.1 BeanDefinitionReader接口

 

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

  • 获取注册表的功能,让外界可以通过该对象获取注册表对象。

  • 加载配置文件,并注册bean数据。

/**
 * @version v1.0
 * @ClassName: BeanDefinitionReader
 * @Description:
 *      用来解析配置文件的,而该接口只是定义了规范
 */
public interface BeanDefinitionReader {
​
    //获取注册表对象
    BeanDefinitionRegistry getRegistry();
    //加载配置文件并在注册表中进行注册
    void loadBeanDefinitions(String configLocation) throws Exception;
}

3.2 XmlBeanDefinitionReader类

XmlBeanDefinitionReader类是专门用来解析xml配置文件的。该类实现BeanDefinitionReader接口并实现接口中的两个功能。

/**
 * @version v1.0
 * @ClassName: XmlBeanDefinitionReader
 * @Description: 针对xml配置文件进行解析的类
 */
public class XmlBeanDefinitionReader implements BeanDefinitionReader {
​
    //声明注册表对象
    private BeanDefinitionRegistry registry;
​
    public XmlBeanDefinitionReader() {
        this.registry = new SimpleBeanDefinitionRegistry();
    }
​
    @Override
    public BeanDefinitionRegistry getRegistry() {
        return registry;
    }
​
    public void loadBeanDefinitions(String configLocation) throws Exception {
        //使用dom4j进行xml配置文件的解析   须需在pom文件里面引入dom4j 1.6.1版本
        SAXReader reader = new SAXReader();
        //获取类路径下的配置文件
        InputStream is = XmlBeanDefinitionReader.class.getClassLoader().getResourceAsStream(configLocation);
        Document document = reader.read(is);
        //根据Document对象获取根标签对象 (beans)
        Element rootElement = document.getRootElement();
        //获取根标签下所有的bean标签对象
        List<Element> beanElements = rootElement.elements("bean");
        //遍历集合
        for (Element beanElement : beanElements) {
            //获取id属性
            String id = beanElement.attributeValue("id");
            //获取class属性
            String className = beanElement.attributeValue("class");
​
            //将id属性和class属性封装到BeanDefinition对象中
            //1,创建BeanDefinition
            BeanDefinition beanDefinition = new BeanDefinition();
            beanDefinition.setId(id);
            beanDefinition.setClassName(className);
​
            //创建MutablePropertyValues对象
            MutablePropertyValues mutablePropertyValues = new MutablePropertyValues();
​
            //获取bean标签下所有的property标签对象
            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);
            }
            //将mutablePropertyValues对象封装到BeanDefinition对象中
            beanDefinition.setPropertyValues(mutablePropertyValues);
​
            //将beanDefinition对象注册到注册表中
            registry.registerBeanDefinition(id,beanDefinition);
        }
        
    }
}

4 IOC容器相关类

4.1 BeanFactory接口

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

public interface BeanFactory {
    //根据bean对象的名称获取bean对象
    Object getBean(String name) throws Exception;
    //根据bean对象的名称获取bean对象,并进行类型转换
    <T> T getBean(String name, Class<? extends T> clazz) throws Exception;
}

4.2 ApplicationContext接口

该接口的所以的子实现类对bean对象的创建都是非延时的,所以在该接口中定义 refresh() 方法,该方法主要完成以下两个功能:

  • 加载配置文件。

  • 根据注册表中的BeanDefinition对象封装的数据进行bean对象的创建。

//定义非延时加载功能
public interface ApplicationContext extends BeanFactory {
    //进行配置文件加载并进行对象创建
    void refresh() throws IllegalStateException, Exception;
}

4.3 AbstractApplicationContext类

  • 作为ApplicationContext接口的子类,所以该类也是非延时加载,所以需要在该类中定义一个Map集合,作为bean对象存储的容器。

  • 声明BeanDefinitionReader类型的变量,用来进行xml配置文件的解析,符合单一职责原则。

    BeanDefinitionReader类型的对象创建交由子类实现,因为只有子类明确到底创建BeanDefinitionReader哪儿个子实现类对象。

public abstract class AbstractApplicationContext implements ApplicationContext {
​
    protected BeanDefinitionReader beanDefinitionReader;
    //用来存储bean对象的容器   key存储的是bean的id值,value存储的是bean对象
    protected Map<String, Object> singletonObjects = new HashMap<String, Object>();
​
    //存储配置文件的路径
    protected String configLocation;
​
    public void refresh() throws IllegalStateException, Exception {
​
        //加载BeanDefinition
        beanDefinitionReader.loadBeanDefinitions(configLocation);
​
        //初始化bean
        finishBeanInitialization();
    }
​
    //bean的初始化
    private void finishBeanInitialization() throws Exception {
        //获取注册表对象
        BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();
​
        //获取BeanDefinition对象
        String[] beanNames = registry.getBeanDefinitionNames();
        for (String beanName : beanNames) {
            //进行bean的初始化
            getBean(beanName);
        }
    }
}

注意:该类finishBeanInitialization()方法中调用getBean()方法使用到了模板方法模式。

4.4 ClassPathXmlApplicationContext类

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

  • 在构造方法中,创建BeanDefinitionReader对象。

  • 在构造方法中,调用refresh()方法,用于进行配置文件加载、创建bean对象并存储到容器中。

  • 重写父接口中的getBean()方法,并实现依赖注入操作。

/**
 * @version v1.0
 * @ClassName: ClassPathXmlApplicationContext
 * @Description: IOC容器具体的子实现类
 *          用于加载类路径下的xml格式的配置文件
 */
public class ClassPathXmlApplicationContext extends AbstractApplicationContext {
​
    public ClassPathXmlApplicationContext(String configLocation) {
        this.configLocation = configLocation;
        //构建解析器对象
        beanDefinitionReader = new XmlBeanDefinitionReader();
        try{
            this.refresh();
        } catch (Exception e) {
​
        }
    }
​
    //根据bean对象的名称获取bean对象
    public Object getBean(String name) throws Exception {
        //判断对象容器中是否包含指定名称的bean对象,如果包含,直接返回即可,如果不包含,需要自行创建
        Object obj = singletonObjects.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) {
            //获取name属性值
            String propertyName = propertyValue.getName();
            //获取value属性
            String value = propertyValue.getValue();
            //获取ref属性
            String ref = propertyValue.getRef();
            if(ref != null && !"".equals(ref)) {
                //获取依赖的bean对象
                Object bean = getBean(ref);
                //拼接方法名
                String methodName = StringUtils.getSetterMethodByFieldName(propertyName);
                //获取所有的方法对象
                Method[] methods = clazz.getMethods();
                for (Method method : methods) {
                    if (methodName.equals(method.getName())) {
                        //执行该setter方法
                        method.invoke(beanObj,bean);
                    }
                }
            }
​
            if(value != null && !"".equals(value)) {
                //拼接方法名
                String methodName = StringUtils.getSetterMethodByFieldName(propertyName);
                //获取method对象
                Method method = clazz.getMethod(methodName, String.class);
                method.invoke(beanObj,value);
            }
        }
​
        //在返回beanObj对象之前,将该对象存储到map容器中
        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);
    }
}
​
​
/**
 * @version v1.0
 * @ClassName: StringUtils
 */
public class StringUtils {
    private StringUtils() {
​
    }
​
    // userDao   ==>   setUserDao
    public static String getSetterMethodByFieldName(String fieldName) {
        String methodName = "set" + fieldName.substring(0,1).toUpperCase() + fieldName.substring(1);
        return methodName;
    }
}
​

如此已经完成,只需对这个工程执行mvn install打包成一个jar,通过pom文件引入到其他工程(例如:spring使用回顾)中即可进行测试。

// 这是另外一个工程
// 引用的类均来自于前面自定义的类
public static void main(String[] args) throws Exception {
        //1,创建spring的容器对象
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
        //2,从容器对象中获取userService对象
        UserService userService = applicationContext.getBean("userService", UserService.class);
        //3,调用userService方法进行业务逻辑处理
        userService.add();
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/790483.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

提示工程101|与 AI 交谈的技巧和艺术

随着 ChatGPT 的问世&#xff0c;人工智能&#xff08;AI&#xff09;新时代也正式开启。ChatGPT 是一种语言模型。它与用户进行对话交互&#xff0c;以便用户输入问题或提示&#xff0c;模型响应&#xff0c;然后对话可以继续来回进行&#xff0c;类似于在消息传递应用程序上向…

docker容器日志大小限制

docker的日志随着时间推移越来越大&#xff0c;我们可以做出一些限制。 docker的日志驱动设置有两种方式&#xff0c;一种是全局配置&#xff0c;一种是特定容器的限制。 这里我选择特定容器限制更加的符合生产环境。全局配置下&#xff0c;需要重启docker。 参考官方文档&am…

在Chrome(谷歌浏览器)中安装Vue.js devtools开发者工具及解决Vue.js not detected报错

文章目录 一、Vue.js devtools开发者工具安装1.打开谷歌浏览器——点击扩展程序——选择管理扩展程序2.先下载添加一个谷歌助手到扩展程序中&#xff08;根据提示进行永久激活&#xff09;3.点击谷歌浏览器的应用商店4.输入Vue.js devtools——搜索——选择下载 二、解决Vue.js…

10.python设计模式【代理模式】

内容&#xff1a;为其他对象提供一种代理一控制对这个对象的访问 应用场景&#xff1a; 远程代理&#xff1a; 为远程的对象提供代理虚代理&#xff1a;根据需要创建很大的对象保护代理&#xff1a;控制对原始对象的访问&#xff0c;用于对象有不同访问权限时 UML图 举个例…

vue中Cascader 级联选择器实现-修改实现

vue 的cascader研究了好长时间&#xff0c;看了官网给的示例&#xff0c;上网查找了好多信息&#xff0c;才解决修改时回显的问题&#xff0c;现将方法总结如下&#xff1a; vue代码&#xff1a; <el-form-item label"芯片" prop"firmware"> <…

redis中使用bloomfilter的白名单功能解决缓存穿透问题

一 缓存预热 1.1 缓存预热 将需要的数据提前缓存到缓存redis中&#xff0c;可以在服务启动时候&#xff0c;或者在使用前一天完成数据的同步等操作。保证后续能够正常使用。 1.2 缓存穿透 在redis中&#xff0c;查询redis缓存数据没有内容&#xff0c;接着查询mysql数据库&…

63、故障处理之快速恢复数据

数据丢失快速恢复的重要性 目的&#xff1a;尽快修复数据&#xff0c;恢复业务 快速恢复相关技术对比 常用备份恢复技术 数据快速恢复原理 MVCC 是TiDB数据库原生的一项功能&#xff0c;默认使用无需配置&#xff0c;它使用多个历史快照的方式来维护数据在某个时间点对并…

Python案例|使用Scikit-learn进行房屋租金回归分析

回归分析是一种预测性的建模技术&#xff0c;研究的是因变量&#xff08;目标&#xff09;和自变量&#xff08;预测器&#xff09;之间的关系。回归分析是建模和分析数据的重要工具。比如预测股票价格走势、预测居民收入、预测微博互动量等等。常用的有线性回归、逻辑回归、岭…

软路由r2s简单刷固件openwrt教程

r2s软件介绍 NanoPi R2S 是 FriendlyELEC&#xff08;友善电子&#xff09;推出的一款单板计算机&#xff0c;它是 NanoPi 系列的一部分。NanoPi R2S 是一款小型高性能的嵌入式系统&#xff0c;适用于网络路由、家庭网关、嵌入式应用和网络安全等场景。 r2s软件特点 特性描述…

前端学习——Vue (Day4)

组件的三大组成部分 组件的样式冲突 scoped <template><div class"base-one">BaseOne</div> </template><script> export default {} </script><style scoped> /* 1.style中的样式 默认是作用到全局的2.加上scoped可以让样…

MySQL - 安装、连接、简单介绍

1、安装 MySQL8.0 安装MySQL 8.0的步骤&#xff0c;以 Windows 为例&#xff1a; 1.1 下载MySQL Installer&#xff1a; 需要从MySQL官方网站下载MySQL Installer。在下载页面中&#xff0c;选择适用于Windows的MySQL Installer并下载。 1.2 运行MySQL Installer&#xff1…

银河麒麟安装nginx及配置(附常见问题解析)

下载并安装nginx 去官网下载所需安装包nginx: download 解压 tar -zxvf nginx-xxx.tar.gz 进入nginx目录下&#xff0c;输入命令 ./configure 此处可能报错 原因为未下载gcc编译器 输入以下命令解决 sudo apt-get install -y build-essential git-core bison openssl libr…

《价值流动》从项目到产品: 到底是什么应该流经软件价值流?| IDCF

译者&#xff1a;无敌哥 原文地址: https://www.tasktop.com/blog/what-flows-through-a-software-value-stream/ 本文翻译仅供学习交流之用。 原文作者 Mik Kersten 出版了《Project to Product》 本系列共四篇文章&#xff0c;分别是 01 从项目到产品&#xff1a;软件需要…

web服务器(Tomcat)

一、web服务器 1. 常见web服务器 Tomcat&#xff1a;由Apache组织提供的一种Web服务器&#xff0c;提供对jsp和Servlet的支持。它是一种轻量级的javaWeb容器&#xff08;服务器&#xff09;&#xff0c;也是当前应用最广的JavaWeb服务器&#xff08;免费&#xff09;。 Jbos…

看了2023年的一线互联网公司时薪排行榜!值得思考

前言 根据最近针对国内的一线互联网企业做的调研&#xff0c;汇总了他们的平均时薪水平&#xff0c;最终出了一个排行榜&#xff01; 首先我们来看下&#xff0c;排行榜分哪几个Level&#xff0c;分别为初级、中级、高级、资深、专家/架构这五个&#xff0c;主要根据工程师的…

【044】深入探索STL:解密set与multiset容器的神秘力量

解密set与multiset容器的神秘力量 引言一、set和 multiset容器概述二、set容器常用API三、multiset的常用API四、对组 pair4.1、概念4.2、创建对组 pair 的方式 五、使用示例5.1、重定义排序规则5.2、队组pair的使用 总结 引言 &#x1f4a1; 作者简介&#xff1a;一个热爱分享…

【GeoDa实用技巧100例】016:制作(三维)散点图

文章目录 一、散点图介绍二、加载实验数据三、散点图制作四、剔除回归样本五、3D散点图一、散点图介绍 散点图是一种以点的分布反映变量之间相关情况的统计图。根据散点图中各点的分布走向和密度,可以大致判断变量之间相互关系。根据反映变量的维度可分为二维(亦称2D)和三维(…

数据结构第六天(7.20)双向链表逆置

DoubleLink rev_double(DoubleLink L,int n) {if(LNULL||L->nextNULL)return L;DoubleLink pL;LL->next;p->nextNULL;DoubleLink t;printf("%d",n);for(int i0;i<n-1;i){tL;LL->next;t->nextp;p->prevt;t->prevNULL;pt;}return p; }

【kubernetes系列】flannel之vxlan模式原理

概述 在Kubernetes中要保证容器之间网络互通&#xff0c;网络至关重要。而Kubernetes本身并没有自己实现容器网络&#xff0c;而是而是借助CNI标准&#xff0c;通过插件化的方式自由接入进来。在容器网络接入进来需要满足如下基本原则&#xff1a; Pod无论运行在任何节点都可…