设计模式-策略工厂

news2024/11/15 7:37:27

在介绍策略工厂的实现前,我们要先了解spring中beanFactory:

BeanFactory

作为IOC服务的提供者,通过XmlBeanFactory来得到实例

生产Bean的工厂,采用延迟初始化策略(只有在需要某个对象时,才进行初始化和依赖注入);通常会用xml文件来注册并管理各个业务对象之间的依赖关系

DefaultListableBeanFactory实现了BeanFactory接口和BeanDefinitionRegistry接口(负责Bean的注册管理)
在这里插入图片描述

属性键值对注入PropertyValue

这里的key:group,value:name

位于beans包下,是bean属性键值对的封装,缓存了对key-value解析相关的信息,避免重复解析

在这里插入图片描述

  • AttributeAccessor 可以访问对象的属性或将属性附加到对象上。
public interface AttributeAccessor {
	//增删改查
	void setAttribute(String name, @Nullable Object value);
	@Nullable
	Object getAttribute(String name);
	@SuppressWarnings("unchecked")
	default <T> T computeAttribute(String name, Function<String, T> computeFunction) {
		Assert.notNull(name, "Name must not be null");
		Assert.notNull(computeFunction, "Compute function must not be null");
		Object value = getAttribute(name);
		if (value == null) {
			value = computeFunction.apply(name);
			Assert.state(value != null,
					() -> String.format("Compute function must not return null for attribute named '%s'", name));
			setAttribute(name, value);
		}
		return (T) value;
	}
	@Nullable
	Object removeAttribute(String name);
	boolean hasAttribute(String name);
	String[] attributeNames();
}
  • BeanMetadataElement 持有属性信息的对象。
public interface BeanMetadataElement {

	@Nullable
	default Object getSource() {
		return null;
	}

}
  • BeanMetadataAttributeAccessor 实现了 AttributeAccessor和 BeanMetadataElement 两个接口,属性为 BeanMetadataAttribute 对象
public class BeanMetadataAttributeAccessor extends AttributeAccessorSupport implements BeanMetadataElement {

	@Nullable
	private Object source;

	public void setSource(@Nullable Object source) {
		this.source = source;
	}

	@Override
	@Nullable
	public Object getSource() {
		return this.source;
	}
}
  • PropertyValue 属性键值对
public class PropertyValue extends BeanMetadataAttributeAccessor implements Serializable {
	//属性名称
	private final String name;
	//属性值
	@Nullable
	private final Object value;
	//属性值是否是optional
	private boolean optional = false;
	//属性值是否进行了属性转换
	private boolean converted = false;
	//类型转换后的属性值
	@Nullable
	private Object convertedValue;
	//属性值是否需要进行转换
	@Nullable
	volatile Boolean conversionNecessary;
	//缓存解析后的属性名称
	@Nullable
	transient volatile Object resolvedTokens;

MutablePropertyValues

在这里插入图片描述

PropertyValues的默认实现类是MutablePropertyValues

MutablePropertyValues:

  • 内部维护了一个List<PropertyValue> propertyValueList将属性值转换为PropertyValue进行存储
    Bean的结构图:
    在这里插入图片描述
    每一个受管的对象,在容器中都会有一个BeanDefinition的实例与之对应,BeanDefinition存储对象的信息,包括:

  • 对应的对象的class类型,是否抽象类,构造方法参数及其他信息

  • beanName就是实例名

实现策略工厂:

注解StrategyAnnotation

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface StrategyAnnotation {
    /**
     * 策略类型名称,可以支持多个
     *
     * @return
     */
    String[] name() default "";

    /**
     * 默认组为: defaultGroup
     *
     * @return
     */
    String group() default "defaultGroup";

    /**
     * 是否默认类型
     *
     * @return
     */
    boolean isDefault() default false;
}

创建策略工厂实现类

管理所有的方法

/**
 * 策略工厂
 * 当你使用注解 StrategyAnnotation 在类上面
 * 那么会通过 RegisterMapDefinition 去自动创建策略工厂。
 *
 * 策略工厂的名称就是 StrategyAnnotation 定义的group.
 *
 * 支持的state 参数,就是 StrategyAnnotation 定义的 name
 *
 */
public class StrategyFactory<T> {
    //key是策略类型,value是具体策略
    Map<String, T> localMap;

    public T getObjectByState(String state) {
        return localMap.get(state);
    }

    public T defaultObject(String state) {
        T t = localMap.get(state);
        if (t == null) {
            t = localMap.get(null);
        }
        return t;
    }

    public T getObjectThrowException(String state) {
        T t = localMap.get(state);
        if (t == null) {
            throw new IllegalStateException("获取对象失败,状态:" + state);
        }
        return t;
    }

    public void setLocalMap(Map<String, T> localMap) {
        this.localMap = localMap;
    }

    public Map<String, T> getLocalMap() {
        return Collections.unmodifiableMap(this.localMap);
    }
}

RegisterMapDefinition

自动创建策略工厂

  1. 获取注解的group
  2. 首次registry这个groupBean
  3. 获取这个groupBean的BeanDefinition
  4. 遍历注解的name
  5. 通过定义的key(localMap)获得PropertyValue属性值
  6. 首次属性值为空,创建一个PropertyValue(以localMap为key,ManagedMap为value)
  7. 将localMap这个PropertyValue属性添加到propertyValues中即可
/**
 * 策略配置加载器
 */
@Component
public class RegisterMapDefinition implements BeanDefinitionRegistryPostProcessor {

    public static final String LOCAL_MAP_PROPERTY = "localMap";
    Logger logger = LoggerFactory.getLogger(getClass());

    /**
     * 本文加载有注解的bean为map 作为策略映射,
     *
     * @param beanFactory
     * @throws BeansException
     * @see StrategyAnnotation
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    }

    private void registerGroupMap(BeanDefinitionRegistry registry, StrategyAnnotation strategyAnnotation, String beanName, BeanDefinition beanDefinition) {
        String groupBean = strategyAnnotation.group();
        if (!registry.containsBeanDefinition(groupBean)) {
            RootBeanDefinition strategyFactoryDefinition = new RootBeanDefinition();
            strategyFactoryDefinition.setBeanClass(StrategyFactory.class);
            registry.registerBeanDefinition(groupBean, strategyFactoryDefinition);
        }
        BeanDefinition groupBeanDefinition = registry.getBeanDefinition(groupBean);

        String[] names = strategyAnnotation.name();
        for (String name : names) {
            MutablePropertyValues propertyValues = groupBeanDefinition.getPropertyValues();
            PropertyValue localMap = propertyValues.getPropertyValue(LOCAL_MAP_PROPERTY);
            if (localMap == null) {
                localMap = new PropertyValue(LOCAL_MAP_PROPERTY, new ManagedMap<>());
                propertyValues.addPropertyValue(localMap);
            }
            ManagedMap<TypedStringValue, BeanReference> stringObjectManagedMap =
                    (ManagedMap<TypedStringValue, BeanReference>) localMap.getValue();
            stringObjectManagedMap.put(new TypedStringValue(name), new RuntimeBeanReference(beanName));
            if (strategyAnnotation.isDefault()) {
                stringObjectManagedMap.put(null, new RuntimeBeanReference(beanName));
            }
            propertyValues.addPropertyValue(localMap);
        }
    }


    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        String op = "RegisterMapDefinition.postProcessBeanDefinitionRegistry";
        logger.info(Logs.op(op).msg("批量创建策略实例").toString());
        //获取所有的beanName
        String[] strategyAnnotationsArray = registry.getBeanDefinitionNames();
        //遍历每个beanName
        for (String beanName : strategyAnnotationsArray) {
            BeanDefinition beanDefinition = registry.getBeanDefinition(beanName);
            try {
                //获得bean的类名
                String beanClassName = beanDefinition.getBeanClassName();
                if (beanClassName == null) {
                    continue;
                }
				//找到类对象
                Class<?> clazz = Class.forName(beanClassName);
                //获取类对象上的StrategyAnnotations注解
                StrategyAnnotations annotation = AnnotationUtils.findAnnotation(clazz, StrategyAnnotations.class);
                //有StrategyAnnotations注解的进行注册
                if (annotation != null) {
                    for (StrategyAnnotation strategyAnnotation : annotation.value()) {
                        registerGroupMap(registry, strategyAnnotation, beanName, beanDefinition);
                    }
                }

                StrategyAnnotation strategyAnnotation = AnnotationUtils.findAnnotation(clazz, StrategyAnnotation.class);
                if(strategyAnnotation!=null){
                    registerGroupMap(registry, strategyAnnotation, beanName, beanDefinition);
                }

            } catch (ClassNotFoundException e) {
                logger.debug(Logs.op(op).msg("策略加载器加载指定类不存在").toString(), e);
            }

        }
    }
}

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

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

相关文章

网络安全如何从零基础到精通?

在看这篇文章之前&#xff0c;有个问题想确认一下&#xff0c;你现在自学网络安全是出于兴趣原因&#xff0c;还是说之后准备走网络安全这个方向&#xff1f; 因为目的不同&#xff0c;学习的方式和深度也会不一样。 今天我就围绕职业发展这个方向来和你聊聊。 如果你真的想通过…

全国青少年软件编程(Scratch)等级考试一级考试真题2023年5月——持续更新.....

一、单选题(共25题&#xff0c;共50分) 1.看图找规律&#xff0c;请问下图红框中是&#xff1f;&#xff08; &#xff09; A. B. C. D. 标准答案&#xff1a;D 试题解析&#xff1a;通过观察每种图形有两个&#xff0c;所以选择D 2.用一根绳子绕树一圈余30厘米&#x…

小说推文洗稿的工作流程

牙叔教程 简单易懂 第一步 找到十万赞以上的爆款视频 自己刷呗, 多刷一些, 最好是那种粉丝几万到几十万的作者, 点赞数量在万赞以上的作品, 十万赞就更好啦 第二步 提取视频的文案 我们分享视频的时候, 有一个复制链接的按钮, 然后把链接复制到 逗哥配音 , 就可以把文案提取…

【QQ界面展示-通知的发布2 Objective-C语言】

一、我再把这个通知的发布与监听给大家复习一下, 1.我们发布和监听通知, 1)第一,需要一个对象,通知的发布者 2)第二,需要一个对象,通知的监听者 只有它俩,还不够,一个是通知的发布者、一个是通知的监听者, 只有它俩,根本不够, 你要想进行通知的发布、和监听,…

leetcode329. 矩阵中的最长递增路径(java)

矩阵中的最长递增路径 矩阵中的最长递增路径题目描述 暴力递归代码演示 递归 缓存代码演示 动态规划专题 矩阵中的最长递增路径 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode.cn/problems/longest-increasing-path-in-a-matrix 题…

一文搞懂文件系统

目录 1.文件系统概述 2.文件命名 3.目录 3.1一级目录系统 3.2层次目录系统 4.文件系统的实现 4.1引导块 4.2超级块 4.3空闲空间块 4.3.1位图 4.3.2 使用链表进行管理 4.inode 5.记录文件所用磁盘块的方法 5.1连续分配 5.2链表分配 5.3inode 1.文件系统概述 文件系…

DC综合入门【待完善】

一、文件说明 工艺库 1、.db 格式&#xff1a;二进制工艺库文件&#xff1b;. lib 格式&#xff1a;可读工艺库文件&#xff08;包含 operating _ conditions ). 二、. synopsys _ dc . setup 搜索路径定义 1、set_search _ path [ list ./ home xxx(路径)] 2、多个地址可用&…

eclipse中创建一个maven父工程和几个模块(子工程)

示例&#xff1a;创建一个父工程和几个模块&#xff08;子工程&#xff09; 1&#xff09;、先创建一个父工程 注意&#xff1a;下面的Packaging选择pom&#xff1a; 点击Finish&#xff0c;父工程就创建好了&#xff1a; 2&#xff09;、再创建模块&#xff08;module&am…

软件测试用例三问,我的观点

背景 笔者最近换了新工作&#xff0c;可能是跟下属不熟悉的关系&#xff0c;昨天在会议上要求他们在用例中说清楚测试点。这句话引起了下属的一些情绪。我觉得这个问题有必要拿出来说一说&#xff0c;而且讨论这个问题的时候很容易从A变成B&#xff0c;这需要管理者警惕。 昨…

抖音如何查看自己上没上热门

抖音如何查看自己上没上热门 老铁&#xff0c;你的作品上热门了&#xff0c;你是不是还不知道呀&#xff1f; 如果说你还不知道怎么查看自己的作品上热门了&#xff0c;那么你一定要认真听我说。 首先呢&#xff0c;你的作品上热门播放量会比平时高几倍&#xff0c;几十倍&am…

@ConfigurationProperties 注解原理

前言 ConfigurationProperties注解是 SpringBoot 提供的一种更加便捷来处理配置文件中的属性值的方式&#xff0c;可以通过自动绑定和类型转换等机制&#xff0c;将指定前缀的属性集合自动绑定到一个Bean对象上。 加载原理 在 Springboot 启动流程加载配置的 prepareEnviron…

(2022,域邻近度)通过自适应感知核调制的 few-shot 图像生成

Few-shot Image Generation via Adaptation-Aware Kernel Modulation 公众号&#xff1a;EDPJ 目录 0. 摘要 1. 简介 2. 相关工作 3. 通过源-目标域接近度的视角重新审视 FSIG 3.1 源-目标域邻近度分析 3.2 临近假设松弛下的 FSIG 方法 4. 自适应感知核调制 5. 实证研…

js实现日历效果

使用js实现日历效果&#xff0c;主要用到了元素的创建以及添加 对应的方法是document.createElement()和document.appendChild() 主要实现思路&#xff1a; 用div布局把日历的页面框架搭建出来依次遍历上月&#xff0c;本月&#xff0c;下月的天数切换月份的时候首先清空所有日…

在服务器安装mysql步骤以及mysql数据库连接报错:is not allowed to connect to this mysql server

mysql xxx is not allowed to connect to this MySQL server 服务器上面安装的mysql数据库在本地连接的时候报错&#xff1a;is not allowed to connect to this MySQL server 出现这种情况的原因是因为&#xff1a; mysql数据库只允许自身所在的本机器连接&#xff0c;不允许…

排序算法——直接选择排序

直接选择排序 以升序排序为例 文章目录 直接选择排序算法步骤动图演示实现代码改进算法&#xff08;双指针&#xff09;具体步骤处理特殊情况&#xff1a;实现代码 时间复杂度 算法步骤 方法一&#xff1a;直接交换数组元素 将第一个元素与其他元素进行比较&#xff0c;若其…

初识网络之再看tcp协议

目录 一、tcp协议段格式 二、tcp协议的解包 三、tcp协议的分用 四、TCP可靠性问题 1. 不可靠存在原因 2. 常见的不可靠问题 3. 如何保证可靠性 4. 确认应答机制 5. 序号 五、tcp报头其余字段 1. 16位窗口大小 2. tcp的6个标记位 2.1 SYN 2.2 FIN 2.3 ACK 2.4 P…

【Linux】C语言中多线程的创建、退出、回收、分离

概述 线程是轻量级的进程&#xff08;LWP&#xff1a;light weight process&#xff09;&#xff0c;在 Linux 环境下线程的本质仍是进程。在计算机上运行的程序是一组指令及指令参数的组合&#xff0c;指令按照既定的逻辑控制计算机运行。操作系统会以进程为单位&#xff0c;…

【Spring AOP】面向切面编程

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 1. 什么是Spring AOP&#xff1f; 2. 为什么要…

NFC type 12345 tag介绍

NFC(近场通信)被称为短距离无线技术&#xff0c;是一套通信协议&#xff0c;NFC技术将非接读卡器/Reader、非接标签/Tag和点对点(Peer-to-Peer)数据交换的功能设计融为一体!使电子设备之间能够进行简单、安全的双向交互。为推动NFC技术发展&#xff0c;2004年&#xff0c;诺基亚…

Stable-Diffusion环境搭建

硬件可以采用DELL R7525 搭配L4 或者T4 等等企业级显卡 环境如下&#xff1a; 可以看到有相应的GPU卡信息 esxi 7.u3 信息 设置GPU穿透方式 查看相应的虚拟机参数信息 PCI 设备加载穿透GPU信息 启动uefi 设置相应的参数信息 https://docs.nvidia.com/grid/latest/grid-vgpu-re…