清朝云资源网

作者: 清朝云

  • 11月04日,星期一, 每天60秒读懂全世界!

    百度热搜新闻

    新闻来源:百度热搜榜

    1. 郑州大学生“夜袭”开封

    2. 张本智和淘汰 北京时间11月3日,WTT法兰克福冠军赛男单1/16决赛中,张本智和与阿鲁纳展开对决,最终2比3被淘汰出局。

    3. 欢迎神十八航天员回家 据中国载人航天工程办公室消息,神舟十八号载人飞船与空间站组合体成功分离。航天员叶光富、李聪、李广苏踏上回家之旅。

    4. 奶奶把外婆给娃的金吊坠熔了自己戴 近日,湖北一女子发现外婆送给孩子的生肖吊坠,被奶奶拿走换了条大项链戴在脖子上,孩子奶奶称:反正孩子不戴,我就自己先戴上。

    5. 隐形战机苏57降落太原

    6. 新房被陌生人开派对满地计生用品

    7. 巴菲特疯狂囤现金

    8. 杭州马拉松冠军变亚军 痛失21万

    9. 周深把自己反锁在了卫生间

    10. 飞天茅台价格全线飙升

    —- 百度热搜新闻 End —-

    知乎新闻

    新闻来源:知乎日榜

    标题: 「抽象画」是不是起源于画得难看的人的借口?
    链接: https://daily.zhihu.com/story/9776560
    ———————-
    标题: 为什么乐理和数学如此不同?
    链接: https://daily.zhihu.com/story/9776563
    ———————-
    标题: 氦为什么不能形成化合物?
    链接: https://daily.zhihu.com/story/9776567
    ———————-
    标题: 地球上重力值最小的部位在哪?
    链接: https://daily.zhihu.com/story/9776571
    ———————-

    —- 知乎新闻 End —-

    IT之家新闻

    新闻来源:ITHome之家科技新闻

    标题: 华为鸿蒙 HarmonyOS NEXT 系统获推 5.0.0.102 新版本升级,新增碰一碰分享、多人群发等功能
    发布时间: 2024-11-03T07:34:25.47
    新闻简介: 华为鸿蒙 HarmonyOS NEXT 系统现获推 5.0.0.102 新版本升级(各机型新系统的尾缀有所不同),新增碰一碰分享等功能,适配机型包括平板、手机。
    ———————-
    标题: 部分地区再开 8 折补贴:M4 版 Mac mini 实付 3565 元低过教育优惠
    发布时间: 2024-11-03T15:20:21.883
    新闻简介: 苹果 2024 款 Mac mini 搭载 M4 / M4 Pro 芯片,内存 16GB 起步,售价 4499 元起。
    ———————-
    标题: 微信纯血鸿蒙 1.0.1.34 版上线尝鲜,新增个人名片、位置等功能
    发布时间: 2024-11-03T15:49:36.73
    新闻简介: 微信纯血鸿蒙 1.0.1.34 版现已上线华为应用商店尝鲜区,增加了个人名片、位置等功能,同时支持了各类文件的收取、查看功能。
    ———————-
    标题: 2024 阿里巴巴全球数学竞赛获奖名单公布,86 名选手获奖
    发布时间: 2024-11-03T10:12:32.443
    新闻简介: 阿里巴巴达摩院今日公布了 2024 阿里巴巴全球数学竞赛获奖名单。
    ———————-
    标题: 苹果官网 70/96/140W USB-C 电源适配器技术规格更新,删除 Mac mini / iMac
    发布时间: 2024-11-03T12:14:31.857
    新闻简介: IT之家注意到,苹果官网现“悄悄”删除了对 Mac mini / iMac 设备的支持。由此来看,2024 款 Mac mini 与 iMac 均不支持 USB-C 接口供电。
    ———————-
    标题: 关闭哨兵模式等功能后,特斯拉 Model Y 停放 10 天仅掉电 1%
    发布时间: 2024-11-03T16:02:33.283
    新闻简介: 一位特斯拉车主本周分享了一个发现:特斯拉 Model Y 在机场停放 10 天后,几乎没怎么掉电。测试结果显示,第一天电量下降了 1% 至 79%。车主最初认为每天 1% 的电量消耗是可以接受的。然而接下来的几天,电量一直保持在 79% 不变。即使 10 天后返回美国,车辆的电量仍然是 79%。
    ———————-
    标题: 小米 15 系列手机维修备件价格公布:显示屏 670 元起,主板 2640 元起
    发布时间: 2024-11-03T08:17:18.073
    新闻简介: 小米 15 系列手机发布于 10 月 29 日,定价 4499 元起。现在这款新机的维修备件价格已经在小米官网公布。
    ———————-
    标题: 8999 元 → 6399 元:16G 苹果 M3 版 MacBook Air 立减 2600 元
    发布时间: 2024-11-03T13:59:53.447
    新闻简介: MacBook Air M3 版 16+256G 版售价 8999 元,今日除京东直降 1000 元外,部分地区支持叠加 8 折整补贴。
    ———————-
    标题: 小米 15 手机赠“尊享服务权益”活动延长至双 11,含 1 年碎屏保、5 年电池保等
    发布时间: 2024-11-03T18:07:34.58
    新闻简介: 小米 15 系列手机首销期(10 月 29 日-11 月 1 日)免费送价值 1396 元尊享服务,京东平台显示这一活动时间已经更新为 11 月 2 日 0:00-11 月 11 日 23:59。
    ———————-
    标题: 宝马:纯血鸿蒙版 My BMW App 预计 12 月发布
    发布时间: 2024-11-03T08:45:43.883
    新闻简介: 官方表示,由于技术限制,预计 12 月发布的 My BMW App 版本的部分页面及功能相对现有安卓版本的 My BMW App 有所减少,预计在后续 1-2 个版本进行所有功能的完善。
    ———————-
    标题: 国产手机操作系统的沧桑往事
    发布时间: 2024-11-03T12:07:11.32
    新闻简介: 今天这篇文章,我们来聊聊国产手机操作系统的发展史。
    ———————-
    标题: 华为限时 8.8 折手机内存升级活动时间延长至 2025 年 3 月 31 日
    发布时间: 2024-11-03T21:21:07.84
    新闻简介: 以 Mate 50 机型 8GB+128GB 版本为例,主板如果没有故障,升级为 8GB+256GB 需 492 元(原价 659 元,限时优惠价 559 元),主板有故障的话需要 692 元(原价 909 元,限时优惠价 759 元)。
    ———————-

    —- IT之家新闻 End —-

  • SpringBean 的生命周期以及如何解决循环引用


    共计 1388 个字符,预计需要花费 4 分钟才能阅读完成。

    1. SpringBean的生命周期

    Spring Bean 的生命周期从 Bean 实例化开始,即通过反射创建对象,到 Bean 成为一个完整的对象,最终存储到单例池中。整个过程被称为 Spring Bean 的生命周期,大致分为三个阶段。

    第一阶段是 Bean 的实例化。Spring 框架根据 BeanDefinition 的信息判断 Bean 的范围是否是 singleton,是否延迟加载,是否为 FactoryBean 等。最终,通过反射实例化一个普通的 singleton Bean。

    第二阶段是 Bean 的初始化。在 Bean 创建之后,它仍然是一个”半成品”,需要对 Bean 实例的属性进行填充,执行一些 Aware 接口方法,执行 BeanPostProcessor 的方法,执行 InitializingBean 接口的初始化方法,以及执行自定义的初始化方法。这个阶段是 Spring 中最具技术含量和复杂度的阶段,包括 AOP 增强功能和后续要学习的 Spring 注解功能。同时,这个阶段也是解决 Spring Bean 循环引用问题的关键。

    第三阶段是 Bean 的完成。经过初始化阶段,Bean 成为一个完整的 Spring Bean,并被存储到单例池中,即完成了整个 Spring Bean 的生命周期。

    2. 循环依赖的解决

    以下为 spring 的三级缓存源码:

    public class DefaultSingletonBeanRegistry ... {
        // 1. 存储已完成初始化的单例Bean的容器,即存储实例化和初始化都完成的Bean,称为一级缓存
        private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
    
        // 2. 存储早期Bean单例的缓存,即存储半成品对象,且当前对象已被其他对象引用,称为二级缓存
        private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);
    
        // 3. 存储单例Bean的工厂池,即存储半成品对象,对象未被引用,使用时通过工厂创建Bean,称为三级缓存
        private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
    }

    接下来,以 UserService 和 UserDao 的循环依赖为例,结合上述三级缓存描述整个过程:

    • UserService 被实例化但尚未初始化,将 UserService 存储到三级缓存。

    • UserService 属性注入需要 UserDao,但在缓存中找不到 UserDao。

    • UserDao 被实例化但尚未初始化,将 UserDao 存储到三级缓存。

    • UserDao 属性注入需要 UserService,从三级缓存中获取 UserService,并将 UserService 从三级缓存移至二级缓存。

    • UserDao 执行其他生命周期过程,并最终成为一个完整的 Bean,存储到一级缓存,并删除二、三级缓存。

    • UserService 注入 UserDao。

    • UserService 执行其他生命周期过程,并最终成为一个完整的 Bean,存储到一级缓存,并删除二、三级缓存。

    通过以上步骤,UserService 和 UserDao 的循环依赖得到解决,两个 Bean 都成功完成了初始化阶段,并存储在一级缓存中。

    3. 源码查看

    SpringBean 的生命周期以及如何解决循环引用

    提醒:本文发布于421天前,文中所关联的信息可能已发生改变,请知悉!

    />

    Tips:清朝云网络工作室

  • Spirng 是如何解析第三方 xml 标签的


    共计 11925 个字符,预计需要花费 30 分钟才能阅读完成。

    本文主要了解 Spring 是如何解析第三方 xml 标签的,为什么我们引入了对应的名称空间和指定相应的 xsd 文件就可以使用第三方标签。

    xsd 的全称是 XML Schema Definition,它是一种用于定义 XML 文档结构的语言。XSD 是一种基于 XML 的规范,用于描述 XML 文档中元素的结构、数据类型和约束。

    这里以 spring-context 为例。

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                               http://www.springframework.org/schema/beans/spring-beans.xsd
                               http://www.springframework.org/schema/context
                               http://www.springframework.org/schema/context/spring-context.xsd">
    
        <context:property-placeholder location="mysql.properties"/>
    </beans>

    需要使用 spring-context 的前提必然是引入其 jar 包,然后 xmlns:context 声明名称空间,后面可以使用 context: 前缀来限定属于该命名空间的元素。xsi:schemaLocation 指定了 context 名称空间 xsd 文件位置。

    目前就算配置好了这些,那么 spring 是如何开始解析的呢?

    那这里就要进入到源码查看,这里步骤较多,指出关键的几步。

    首先 ClassPathXmlApplicationContext 先调用自身的 refresh 方法,实际调用的是AbstractApplicationContext 的 refresh 方法,这个方法也就是 spring 容器的初始化的入口方法。

    而解析 xml 的方法在 obtainFreshBeanFactory 方法中调用,这个方法实际也就是获取 bean 工厂。

    public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            this.prepareRefresh();
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);
    
            try {
                this.postProcessBeanFactory(beanFactory);
                this.invokeBeanFactoryPostProcessors(beanFactory);
                this.registerBeanPostProcessors(beanFactory);
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                this.onRefresh();
                this.registerListeners();
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }
    
                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }
    
        }
    }

    obtainFreshBeanFactory 方法里面会调用 refreshBeanFactory 方法。

    protected final void refreshBeanFactory() throws BeansException {
        if (this.hasBeanFactory()) {
            this.destroyBeans();
            this.closeBeanFactory();
        }
    
        try {
            DefaultListableBeanFactory beanFactory = this.createBeanFactory();
            beanFactory.setSerializationId(this.getId());
            this.customizeBeanFactory(beanFactory);
            this.loadBeanDefinitions(beanFactory);
            this.beanFactory = beanFactory;
        } catch (IOException var2) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var2);
        }
    }

    这个方法里面可以看见 loadBeanDefinitions 方法,之前讲过 spring 会将 xml 里面的标签解析成一个个 BeanDefinitions,那么就是这个方法了。

    点进去会发现需要一直往下找 loadBeanDefinitions 方法,直到执行到 XmlBeanDefinitionReader 的 doLoadBeanDefinitions 方法。

    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
        try {
            Document doc = this.doLoadDocument(inputSource, resource);
            int count = this.registerBeanDefinitions(doc, resource);
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Loaded " + count + " bean definitions from " + resource);
            }
    
            return count;
        } catch (BeanDefinitionStoreException var5) {
            throw var5;
        } catch (SAXParseException var6) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + var6.getLineNumber() + " in XML document from " + resource + " is invalid", var6);
        } catch (SAXException var7) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", var7);
        } catch (ParserConfigurationException var8) {
            throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, var8);
        } catch (IOException var9) {
            throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, var9);
        } catch (Throwable var10) {
            throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, var10);
        }
        }

    这个方法里面会执行 registerBeanDefinitions,同样一直执行往下找相同的方法,直到执行到 DefaultBeanDefinitionDocumentReader 的 doRegisterBeanDefinitions 方法。

    protected void doRegisterBeanDefinitions(Element root) {
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = this.createDelegate(this.getReaderContext(), root, parent);
        if (this.delegate.isDefaultNamespace(root)) {
            String profileSpec = root.getAttribute("profile");
            if (StringUtils.hasText(profileSpec)) {
                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; ");
                if (!this.getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + this.getReaderContext().getResource());
                    }
    
                    return;
                }
            }
        }
    
        this.preProcessXml(root);
        this.parseBeanDefinitions(root, this.delegate);
        this.postProcessXml(root);
        this.delegate = parent;
    }

    可以看见该方法执行了 parseBeanDefinitions 方法,这个方法就是执行解析的关键了。

    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        if (delegate.isDefaultNamespace(root)) {
            NodeList nl = root.getChildNodes();
    
            for(int i = 0; i < nl.getLength(); ++i) {
                Node node = nl.item(i);
                if (node instanceof Element) {
                    Element ele = (Element)node;
                    // 判断是否为默认名称空间
                    if (delegate.isDefaultNamespace(ele)) {
                        this.parseDefaultElement(ele, delegate);
                    } else {
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        } else {
            delegate.parseCustomElement(root);
        }
    }

    这里判断是否为默认命名空间,如果是默认名称空间就执行自身的 parseDefaultElement 方法进行解析。

    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        if (delegate.nodeNameEquals(ele, "import")) {
            this.importBeanDefinitionResource(ele);
        } else if (delegate.nodeNameEquals(ele, "alias")) {
            this.processAliasRegistration(ele);
        } else if (delegate.nodeNameEquals(ele, "bean")) {
            this.processBeanDefinition(ele, delegate);
        } else if (delegate.nodeNameEquals(ele, "beans")) {
            this.doRegisterBeanDefinitions(ele);
        }
    }

    可以看见默认的标签就这几种。如果判断非默认的命名空间,那么 spring 自身肯定解析不了,因为它并不了解标签的含义,此时会调用 delegate 的 parseCustomElement 方法,接下来会执行到 BeanDefinitionParserDelegate 的 parseCustomElement 方法。

    @Nullable
    public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
        String namespaceUri = this.getNamespaceURI(ele);
        if (namespaceUri == null) {
            return null;
        } else {
            NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
            if (handler == null) {
                this.error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
                return null;
            } else {
                return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
            }
        }
    }

    可以看见 namespaceUri 是在 xml 文件定义命名空间时设置的内容。

    Spirng 是如何解析第三方 xml 标签的

    />

    这里会通过 namespaceUri 去获取 NamespaceHandler,NamespaceHandler 就是自定义的处理器,获取到自定义处理器自然就可以将自定义的标签进行解析了。

    这里首先获取到 NamespaceHandlerResolver,然后调用 resolve 方法,最终会进入到 DefaultNamespaceHandlerResolver 的 resolve 方法。

    @Nullable
    public NamespaceHandler resolve(String namespaceUri) {
        Map<String, Object> handlerMappings = this.getHandlerMappings();
        Object handlerOrClassName = handlerMappings.get(namespaceUri);
        if (handlerOrClassName == null) {
            return null;
        } else if (handlerOrClassName instanceof NamespaceHandler) {
            return (NamespaceHandler)handlerOrClassName;
        } else {
            String className = (String)handlerOrClassName;
    
            try {
                Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
                if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
                    throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri + "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
                } else {
                    NamespaceHandler namespaceHandler = (NamespaceHandler)BeanUtils.instantiateClass(handlerClass);
                    namespaceHandler.init();
                    handlerMappings.put(namespaceUri, namespaceHandler);
                    return namespaceHandler;
                }
            } catch (ClassNotFoundException var7) {
                throw new FatalBeanException("Could not find NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "]", var7);
            } catch (LinkageError var8) {
                throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "]", var8);
            }
        }
    }

    可以看见它是通过 map 去获取的,那么这个 handlerMappings 又是哪里来的呢?

    可以看见 DefaultNamespaceHandlerResolver 的构造方法如下:

    public DefaultNamespaceHandlerResolver() {
        this((ClassLoader)null, "META-INF/spring.handlers");
    }
    
    public DefaultNamespaceHandlerResolver(@Nullable ClassLoader classLoader) {
        this(classLoader, "META-INF/spring.handlers");
    }
    
    public DefaultNamespaceHandlerResolver(@Nullable ClassLoader classLoader, String handlerMappingsLocation) {
        this.logger = LogFactory.getLog(this.getClass());
        Assert.notNull(handlerMappingsLocation, "Handler mappings location must not be null");
        this.classLoader = classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader();
        this.handlerMappingsLocation = handlerMappingsLocation;
    }

    这里是直接传递了一个 handlerMapping 的地址 META-INF/spring.handlers,这个就是在自己 jar 包中定义的 handlerMapping 的相关信息。

    Spirng 是如何解析第三方 xml 标签的

    />

    同时,这里可以看见 spring.schemas 文件,由 org.springframework.beans.factory.xml.PluggableSchemaResolver 类加载,主要是对 xml 标签的一些约束。

    Spirng 是如何解析第三方 xml 标签的

    />

    这里可以看见 http://www.springframework.org/schema/context 名称空间对应的 NamespaceHandler 路径是 org.springframework.context.config.ContextNamespaceHandler。

    那么又回到刚刚 DefaultNamespaceHandlerResolver 的 resolve 方法,这里获取到 NamespaceHandler 以后,执行了它的 init 方法,以 ContextNamespaceHandler 为例。

    public class ContextNamespaceHandler extends NamespaceHandlerSupport {
        public ContextNamespaceHandler() {
        }
    
        public void init() {
            this.registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
            this.registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
            this.registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
            this.registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
            this.registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
            this.registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
            this.registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
            this.registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
        }
    }

    可以看见这里都是注入标签的解析器,不同的标签使用不同的标签解析器。

    然后又回到 BeanDefinitionParserDelegate 的 parseCustomElement 方法,可以看见返回了handler.parse,点击进入到 NamespaceHandlerSupport 的 parse 方法。

    @Nullable
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        BeanDefinitionParser parser = this.findParserForElement(element, parserContext);
        return parser != null ? parser.parse(element, parserContext) : null;
    }

    这个方法会根据标签去寻找对应的解析器,这里以 PropertyPlaceholderBeanDefinitionParser 为例,这是一个实现了 BeanDefinitionParser 接口的类。

    提示:PropertyPlaceholderBeanDefinitionParser 是刚刚 ContextNamespaceHandler 的 init 方法注册的类。

    class PropertyPlaceholderBeanDefinitionParser extends AbstractPropertyLoadingBeanDefinitionParser {
        private static final String SYSTEM_PROPERTIES_MODE_ATTRIBUTE = "system-properties-mode";
        private static final String SYSTEM_PROPERTIES_MODE_DEFAULT = "ENVIRONMENT";
    
        PropertyPlaceholderBeanDefinitionParser() {
        }
    
        protected Class<?> getBeanClass(Element element) {
            return "ENVIRONMENT".equals(element.getAttribute("system-properties-mode")) ? PropertySourcesPlaceholderConfigurer.class : PropertyPlaceholderConfigurer.class;
        }
    
        protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
            super.doParse(element, parserContext, builder);
            builder.addPropertyValue("ignoreUnresolvablePlaceholders", Boolean.valueOf(element.getAttribute("ignore-unresolvable")));
            String systemPropertiesModeName = element.getAttribute("system-properties-mode");
            if (StringUtils.hasLength(systemPropertiesModeName) && !systemPropertiesModeName.equals("ENVIRONMENT")) {
                builder.addPropertyValue("systemPropertiesModeName", "SYSTEM_PROPERTIES_MODE_" + systemPropertiesModeName);
            }
    
            if (element.hasAttribute("value-separator")) {
                builder.addPropertyValue("valueSeparator", element.getAttribute("value-separator"));
            }
    
            if (element.hasAttribute("trim-values")) {
                builder.addPropertyValue("trimValues", element.getAttribute("trim-values"));
            }
    
            if (element.hasAttribute("null-value")) {
                builder.addPropertyValue("nullValue", element.getAttribute("null-value"));
            }
    
        }
    }

    可以看见这里首先调用父类的 doParse 方法,如果有些属性父类不能解析再由自己解析,大致的流程就是这样了。

    总结:

    • 将自定义标签的约束与物理约束文件与网络约束名称的约束以键值对形式存储到一个 spring.schemas 文件里,该文件存储在类加载路径的 META-INF 里,Spring 会自动加载到

    • 将自定义命名空间的名称与自定义命名空间的处理器映射关系以键值对形式存在到一个叫 spring.handlers 文件里,该文件存储在类加载路径的 META-INF 里,Spring 会自动加载到

    • 准备好 NamespaceHandler,如果命名空间只有一个标签,那么直接在 parse 方法中进行解析即可,一般解析结果就是注册该标签对应的 BeanDefinition。如果命名空间里有多入标签,那么可以在 init 方法中为每个标签都注册一个 BeanDefinitionParser,在执行 NamespaceHandler 的 parse 方法时在分流给不同的 BeanDefinitionParser 进行解析(重写 doParse 方法即可)

    其实一般在 doParse 方法中,无非干两件事,一是向容器里面注入一个 Bean,二是注入一个 BeanPostProcessor,作用于 bean 的生命周期。

    提醒:本文发布于419天前,文中所关联的信息可能已发生改变,请知悉!

    Tips:清朝云网络工作室

  • Spring 创建自定义命名空间和自定义标签


    共计 3785 个字符,预计需要花费 10 分钟才能阅读完成。

    之前有了解过 Spirng 是如何解析第三方 xml 标签的,那么可以根据该原理写一个自定义命名空间和自定义标签,有助于我们学习其他相关框架。

    接下来就自定义一个命名空间下的 mybean 标签,往容器中存放 mybean 配置的对象对象。

    一、自定义命名空间和标签

    通常分为以下几个步骤:

    • 1.确定命名空间名称、schema 虚拟路径、标签名称
    • 2.编写标签约束文件和映射
    • 3.编写处理器映射文件和处理器
    • 4.编写标签解析器

    1. 确定相关名称和路径

    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:amjun="https://www.qcyqq.com/amjun"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                               http://www.springframework.org/schema/beans/spring-beans.xsd
                               https://www.qcyqq.com/amjun
                               https://www.qcyqq.com/amjun/amjun-mybean.xsd">
    
        <amjun:mybean id="userService" class="com.amjun.ioc4.service.impl.UserServiceImpl"/>
    </beans>

    这里用 xml 里面的配置文件里面的来说明以下,指定命名空间为 https://www.qcyqq.com/amjun,对应的 schema 虚拟路径为 https://www.qcyqq.com/amjun/amjun-mybean.xsd,标签名为

    2. 编写标签约束文件和映射

    上面指定了 schema 的虚拟路径为 https://www.qcyqq.com/amjun/amjun-mybean.xsd,所以需要在 resource 目录下的 META-INF 文件夹下新建文件 spring.schemas。

    这里的目录以及文件名称都是定死的,如果不了解请参考开头说的那篇文章

    spring.schemas:

    http\://www.qcyqq.com/amjun/amjun-mybean.xsd=com/amjun/ioc4/config/amjun-mybean.xsd

    这里指定了约束文件放在 resource 目录下的 com/amjun/ioc4/config/ 下,注意这里是多级目录而不是一级。

    amjun-mybean.xsd:

    <?xml version="1.0" encoding="UTF-8"?>
    <xs:schema xmlns="https://www.qcyqq.com/amjun"
               xmlns:xs="http://www.w3.org/2001/XMLSchema"
               targetNamespace="https://www.qcyqq.com/amjun">
    
        <xs:element name="mybean">
            <xs:complexType>
                <xs:attribute name="id" type="xs:string" use="optional"/>
                <xs:attribute name="class" type="xs:string" use="required"/>
            </xs:complexType>
        </xs:element>
    </xs:schema>

    这里定义了 mybean 标签的一些约束,比如可以配置属性 id 和 class, 但是 id 十四可选的,class 是必须的,并且类型都为字符串。

    3. 编写处理器映射文件和处理器

    同样,这里需要配置 spring.handlers,键为命名空间虚拟路径:https://www.qcyqq.com/amjun

    spring.handlers:

    http\://www.qcyqq.com/amjun=com.amjun.ioc4.config.AmjunNamespaceHandler

    可以看见,这里指定了名称空间的处理器。

    AmjunNamespaceHandler:

    
    public class AmjunNamespaceHandler extends NamespaceHandlerSupport {
        @Override
        public void init() {
    
            this.registerBeanDefinitionParser("mybean", new MybeanBeanDefinitionParser());
        }
    }

    自定义的处理器需要继承自 NamespaceHandlerSupport,并在初始化中注册标签解析器。

    4. 编写标签解析器

    MybeanBeanDefinitionParser.java

    public class MybeanBeanDefinitionParser implements BeanDefinitionParser {
        @Override
        public BeanDefinition parse(Element element, ParserContext parserContext) {
            String beanName = element.getAttribute("id");
            String className = element.getAttribute("class");
    
            if (beanName.isEmpty()) {
                // 如果 id 属性为空,则使用类名的作为 Bean 名称
                beanName = extractClassName(className);
            }
    
            // 创建一个通用的 Bean 定义
            RootBeanDefinition beanDefinition = new RootBeanDefinition();
            beanDefinition.setBeanClassName(className);
    
            // 将 Bean 定义注册到 Spring 的 Bean 工厂中
            parserContext.getRegistry().registerBeanDefinition(beanName, beanDefinition);
            return beanDefinition;
        }
    
        /**
         * 获取类名
         * @param fullyQualifiedClassName
         * @return
         */
        private String extractClassName(String fullyQualifiedClassName) {
            int lastIndex = fullyQualifiedClassName.lastIndexOf('.');
            if (lastIndex != -1 && lastIndex < fullyQualifiedClassName.length() - 1) {
                return fullyQualifiedClassName.substring(lastIndex + 1);
            }
            return fullyQualifiedClassName;
        }
    }

    标签解析器的作用是,解析每个标签配置的内容。mybean 标签的作用就是注册对象,所以会获取 id 和 class 属性,id 属性作为在容器里面的名称,class 是需要创建的对象。

    因为标签中 id 是可选的,这里做了特殊处理的是,id 如果为空,就取类名作为名称。

    二、自定义命名空间的使用

    使用就比较简单了,只需要如下操作即可。

    • 1.在配置文件中引入命名空间
    • 2.在配置文件中使用自定义的标签
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:amjun="https://www.qcyqq.com/amjun"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                               http://www.springframework.org/schema/beans/spring-beans.xsd
                               https://www.qcyqq.com/amjun
                               https://www.qcyqq.com/amjun/amjun-mybean.xsd">
    
        <amjun:mybean id="userService" class="com.amjun.ioc4.service.impl.UserServiceImpl"/>
    </beans>

    测试文件:

    public class ApplicationContextTest {
    
        public static void main(String[] args) {
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
            System.out.println(applicationContext.getBean("userService", UserServiceImpl.class));
        }
    }

    创建容器后,可以正常在容器中获取到对象,说明整个过程没问题。

    提醒:本文发布于411天前,文中所关联的信息可能已发生改变,请知悉!

    Tips:清朝云网络工作室

  • 11月03日,星期日, 每天60秒读懂全世界!

    百度热搜新闻

    新闻来源:百度热搜榜

    1. T1击败BLG夺冠 北京时间11月3号,英雄联盟S14总决赛,T1鏖战五局3-2击败BLG,拿下今年的世界冠军!Faker也实现五冠王的荣誉。

    2. 全网老公都在回答吃几个瑞士卷 近日,网上一位全职妈妈因吃瑞士卷遭丈夫责备引发关注,看到这个视频的已婚女士都去问自己的老公,自己能不能吃瑞士卷。

    3. 这就是秋天里的大美中国 深秋时节,各地秋色浓郁,宛若画卷,这就是秋天里的大美中国。

    4. 特朗普美国大选前再现暴论 当地时间11月1日,特朗普在一场竞选活动中再爆“我摧毁了北溪”、“9枪齐射我的批评者”等疯狂言论。

    5. 刘德华在台唱《中国人》 绿营破防 刘德华在台演唱热门歌曲《中国人》,不过此事接连引发民进党政客酸言酸语,“靠背哥”王义川还质疑他演唱《中国人》有政治意味。

    6. 女生捡手机像孙悟空一样被压山下 近日,山东一女生为捡手机卡石缝下出不来,无奈求助消防救援,意外还原孙悟空被压五指山画面。

    7. 刀迷因刀郎演唱会被骗40多万

    8. Faker 五冠大魔王 11月3号,在英雄联盟S14总决赛上,Faker领衔T1击败BLG获得冠军。同时,这也是Faker职业生涯第五座S赛奖杯。

    9. 郑钦文0比2不敌萨巴伦卡 北京时间11月2日,2024年WTA年终总决赛,郑钦文迎战老对手萨巴伦卡。最终郑钦文0比2不敌萨巴伦卡,未拿下小组赛首胜。

    10. 美国大选后富人集体“出逃”? 据悉,移民律师表示,在11月5日美国大选前夕,越来越多富人计划离开美国,因为许多人担心无论谁获胜,都会出现政治和社会动荡。

    —- 百度热搜新闻 End —-

    知乎新闻

    新闻来源:知乎日榜

    标题: 笔记本电脑是一直插着电源好,还是应该每次等电池用没电再充好?
    链接: https://daily.zhihu.com/story/9776557
    ———————-
    标题: 中国古代为何没有公共广场?
    链接: https://daily.zhihu.com/story/9776541
    ———————-
    标题: 蜜蜂天天吃蜂蜜为什么不得糖尿病?
    链接: https://daily.zhihu.com/story/9776551
    ———————-
    标题: 中国古代的诗词格律如此复杂,古人是如何创作出那么多意境优美的诗词的?
    链接: https://daily.zhihu.com/story/9776553
    ———————-

    —- 知乎新闻 End —-

    IT之家新闻

    新闻来源:ITHome之家科技新闻

    标题: 告别 60Hz,供应链消息称 iPhone 17 全系配 LTPO 120Hz ProMotion 面板
    发布时间: 2024-11-02T06:39:44.957
    新闻简介: 韩媒 ETNews 昨日于 10 月 27 日发布博文,基于供应链消息,苹果公司计划在明年推出的 iPhone 17 系列中,全系部署“低温多晶氧化物(LTPO)”面板。
    ———————-
    标题: 小米汽车回应 SU7 Ultra 征战纽北动力中断:落叶遮挡速度传感器后,系统主动降低扭矩
    发布时间: 2024-11-02T07:47:25.23
    新闻简介: 小米汽车回应冲刺纽北赛道时出现“看似动力中断(no power)”的情况时表示,测试当天因为气候原因赛道路面大量落叶,判断是因为落叶遮挡速度传感器后,牵引力控制系统主动降低扭矩,并非动力中断。
    ———————-
    标题: 国补后仅需 8 折:华为 Pura 70 手机 512G 版 4385 元京东破冰新低
    发布时间: 2024-11-02T09:21:31.553
    新闻简介: 国补后仅需 8 折:华为 Pura 70 手机 512G 版 4385 元京东破冰新低
    ———————-
    标题: 到底什么是“无网通信”?
    发布时间: 2024-11-02T12:36:05.11
    新闻简介: 最近这个月,智能手机市场迎来了一波发布热潮。

    除了联发科、高通相继发布旗舰 SoC 芯片之外,包括 vivo、OPPO、荣耀、小米等在内的手机厂商,也纷纷发布了新的旗舰手机新品。
    ———————-
    标题: 小米澎湃 OS 2 Beta 首批机型开启推送:含小米 14 系列、Redmi K70 至尊版等
    发布时间: 2024-11-02T08:24:55.263
    新闻简介: 小米澎湃OS官微昨天深夜宣布,小米澎湃OS 2 Beta版即日起开始推送,首批面向已通过Beta版招募的用户,更多机型正陆续招募中。
    ———————-
    标题: 赛力斯汽车发布《关于昆明市问界 M9 事故的声明》
    发布时间: 2024-11-02T19:25:15.583
    新闻简介: 赛力斯表示,正全力配合属地交管部门及用户处理相关事宜,具体情况请以官方发布为准。#赛力斯回应昆明问界M9事故#
    ———————-
    标题: 三只羊被罚 6894.91 万元后续:已全额缴纳罚款
    发布时间: 2024-11-02T20:02:58.04
    新闻简介: 9 月 26 日,合肥市联合调查组发布通报称,因合肥三只羊网络科技有限公司(以下简称“三只羊公司”)存在直播中进行虚假宣传等行为,拟决定对三只羊公司没收违法所得、罚款共计 6894.91 万元。据大河报《看见》报道,11 月 1 日,三只羊公司客服回应记者称,他们已按照要求全额缴纳完成。
    ———————-
    标题: 比亚迪仰望 U7 豪华轿车白色版实车曝光:首搭云辇-Z,年底前上市
    发布时间: 2024-11-02T11:34:21.31
    新闻简介: 博主“蜗牛同学 LX”今天上午发布了一组仰望 U7 豪华轿车的白色版实车谍照。仰望 U7 已经于今年 4 月的 2024 本届车展期间亮相,定位百万级新能源旗舰轿车,将于下半年(即年底)正式上市。
    ———————-
    标题: 小米发布“苹果生态互联功能的使用说明”:须升级至澎湃 OS 2
    发布时间: 2024-11-02T15:29:29.383
    新闻简介: 公告称,使用苹果生态互联功能,须将小米手机升级至小米澎湃 OS 2,同时确保“跨屏协同服务”“小米互传”已经更新至以下版本。
    ———————-
    标题: 天玑 9300 + 处理器:vivo X100s 手机 12+256G 版 2906 元探新低
    发布时间: 2024-11-02T08:41:02.207
    新闻简介: 天玑 9300 + 处理器:vivo X100s 手机 12+256G 版 2906 元探新低
    ———————-
    标题: 可免费检修:苹果发布 iPhone 14 Plus 服务计划,解决后置相机问题
    发布时间: 2024-11-02T07:15:06.303
    新闻简介: 苹果公司昨日(11 月 1 日)发布公告,针对 iPhone 14 Plus 机型,推出新服务计划,用于解决后置相机问题。
    ———————-
    标题: 阿维塔 12 双动力上市:增程版 25.99 万元起,纯电版 27.99 万元起
    发布时间: 2024-11-02T17:55:17.807
    新闻简介: 全新阿维塔 12 双动力车型今日迎来上市,全国建议零售价增程版 26.99 万元起,纯电版 28.99 万元起,限时权益价优惠一万元。
    ———————-

    —- IT之家新闻 End —-

  • IntelliJ IDEA 2023 最新版安装教程


    共计 290 个字符,预计需要花费 1 分钟才能阅读完成。

    1. 正常安装

    正常安装是指解压后双击 exe 文件进行安装,这里不用多说,可以修改安装路径啥的。安装以后选择 I want to manually reboot later

    2. 破解

    双击进入压缩包解压后的 Crack 文件夹,进入 jetbra 下 的 script 文件夹,双击运行 install-current-user.vbs,这里可能要等很久才会出现完成。

    3. 填写激活码

    等待出现 Done 的弹窗,双击安装好的 exe 文件,打开Crack文件夹,复制密钥填写为 Activate 即可。

    IntelliJ IDEA 2023 最新版安装教程

    />

    下载地址

    idea:https://pan.baidu.com/s/1VlQbvTasoIGi3S3S9e1e3Q?pwd=akak

    提醒:本文发布于410天前,文中所关联的信息可能已发生改变,请知悉!

    Tips:清朝云网络工作室

  • Java 的日志框架体系以及 slf4j 的整合


    共计 889 个字符,预计需要花费 3 分钟才能阅读完成。

    1. 日志框架

    Java 的日志框架分为日志门面和日志实现,这样的好处是为了解耦,配置更灵活,且通过日志门面可以以一种统一的方式输出日志。

    常见的日志框架有以下几种:

    日志门面 日志实现
    JCL SLF4j jboss-logging log4j jul log4j2 logback

    日志门面有三种:

    • JCL: Jakarta Commons Logging,是 apache 的 Jakarta 小组开发的日志门面,但是已经很久没有更新了。

    • SLF4j: 全称 Simple Logging Facade for Java,和日志实现 log4j、logback 是同一作者。

    • jboss-logging:是专门为 jboss 开发的。

    日志实现有四种:

    • Log4j: Log4j 是一个广泛使用的 Java 日志框架,提供了丰富的配置选项和灵活的日志记录功能。它支持多种输出目标(如控制台、文件、数据库等),可以根据日志级别过滤日志消息,并具有可插入的日志记录器。

    • JUL: 全称 Java Util Logging,可以通过配置文件或编程方式进行配置。尽管功能相对较简单,但仍然被广泛使用。

    • Log4j2: Log4j2 是 Log4j 的升级版本,由 apache 开发。

    • Logback: Logback 是由 Log4j 作者创造的一个高性能日志框架,旨在成为 Log4j 的继任者。它支持 SLF4J 接口,并提供了许多先进的日志功能,如异步日志记录、按时间和大小滚动的日志文件等。

    2. slf4j的使用

    需要注意的是在早期版本中,Spring 使用的是 Jakarta Commons Logging (JCL) 作为默认的日志门面,但是没有绑定具体的日志实现。在 Spring 5.x 版本中,改为了使用 SLF4J。并且对于 SpringMVC 和 SpringBoot,它们也会继承 Spring 的默认日志框架。

    以 SLF4J 为例,整合其它日志实现,大致情况如下图:

    Java 的日志框架体系以及 slf4j 的整合

    />

    可以看见 SLF4J 配合 log4j 和 jul 时,需要导入相应的适配层 jar 包。

    但是当引入的框架比较多时,可能很多框架的日志门面都不相同,此时需要先将原来的 jar 包排除掉。然后引入 slf4j 的覆盖包,其实还是调用的 SLF4J 接口,然后再调用具体的实现

    Java 的日志框架体系以及 slf4j 的整合

    提醒:本文发布于407天前,文中所关联的信息可能已发生改变,请知悉!

    />

    Tips:清朝云网络工作室

  • 11月02日,星期六, 每天60秒读懂全世界!

    百度热搜新闻

    新闻来源:百度热搜榜

    1. 中方决定对韩国等9国试行免签 11月1日,外交部发言人林剑表示:中方决定自2024年11月8日至2025年12月31日,对韩国等9国试行免签。

    2. 吕梁民政局:别为了领1500结婚又离婚 近日,吕梁市政府发布通告称:山西吕梁女性35岁前初婚奖励1500元。民政局回应:别为了领1500结婚又离婚。

    3. 全国秋粮收购超4000万吨 11月1日,全国秋粮收购全面展开。截至目前,主产区各类粮食企业累计收购秋粮超4000万吨,其中中晚稻收购超2300万吨。

    4. 13岁女孩遭强迫卖淫 3名公职人员获刑 日前,湖南新化一13岁女孩遭强迫卖淫案引起关注。犯案者中有3人为公职人员。目前涉案人员均已获刑,涉案公职人员也均被开除。

    5. 中学年薪50万招老师 干6年送房 10月30日,神木市实验中学公示校招教师录取名单,获聘教师均来自名校,其“50万年薪,免费提供住房”的待遇引发网友热议。

    6. 德国总统道歉:请求你们原谅

    7. 主持人王冠官宣婚讯

    8. 女大学生神似刘亦菲被围观合影 近日,燕京理工学院一女生“撞脸”刘亦菲,在校园内被围观拍照。网友:终于知道莞莞类卿的威力了。

    9. 黑老大财产被拍卖 2块表值8000万 10月31日,深圳市中级人民法院对两块百达翡丽腕表进行司法拍卖,引发网友关注。据悉,仅单块手表市场估价就超4000万元

    10. 男子辅导女儿作业被气进抢救室

    —- 百度热搜新闻 End —-

    知乎新闻

    新闻来源:知乎日榜

    标题: 冰毒是如何从军需药品发展成为新一代毒品之王的?
    链接: https://daily.zhihu.com/story/9776515
    ———————-
    标题: 为什么不把路由器集成在计算机里?
    链接: https://daily.zhihu.com/story/9776518
    ———————-
    标题: 自然界有哪些很残酷的现象?
    链接: https://daily.zhihu.com/story/9776524
    ———————-
    标题: 瞎扯 · 如何正确地吐槽
    链接: https://daily.zhihu.com/story/9776531
    ———————-

    —- 知乎新闻 End —-

    IT之家新闻

    新闻来源:ITHome之家科技新闻

    标题: 2025 款奥迪 A8L 轿车上市:升级高通骁龙 8150 芯片,78.98 万元起
    发布时间: 2024-11-01T11:24:35.967
    新闻简介: 2025 款奥迪 A8L 系列车型现已上市,该车提供 5 款版本可选,指导价格为 78.98 万元起。
    ———————-
    标题: 雷军谈小米 15 定价:打破了 3999 元的“心魔”
    发布时间: 2024-11-01T20:31:48.587
    新闻简介: 雷军称,这次在精致度上多投一点钱,“做高端手机第一条就是高端要无短板,第二条要从简单的参数比较进化到体验、感受和审美。”#雷军再回应小米15涨价##雷军说小米15破除了3999元心魔#
    ———————-
    标题: 苹果 M4 Pro 芯片跑分曝光:单核比 M3 Pro 高 25%、多核高 45%
    发布时间: 2024-11-01T10:02:02.003
    新闻简介: 科技媒体 AppleInsider 今天(11 月 1 日)发布博文,报道称苹果 M4 Pro 芯片的 GeekBench 跑分已曝光,单核得分为 3925,多核得分为 22669。
    ———————-
    标题: 库克发喜报:苹果 iPhone 同期销量节节攀升,16>15>14 系列
    发布时间: 2024-11-01T07:18:07.883
    新闻简介: 苹果公布 2024 财年第 4 财季财报(对应截至 9 月 28 日的第 3 季度)后,公司首席执行官蒂姆・库克(Tim Cook)接受 CNBC 采访时表示:“iPhone 15 的销售比同期 14 系列更强,而 16 系列的销售又比 15 强”。
    ———————-
    标题: 3698 元 + 24 期免息:小米 14 手机 16G+512G 京东自营新低
    发布时间: 2024-11-01T12:00:33.883
    新闻简介: 3698 元 + 24 期免息:小米 14 手机 16G+512G 京东自营新低
    ———————-
    标题: 多口设计:华为 66W 氮化镓充电器 79 元拼团购(上市 379 元)
    发布时间: 2024-11-01T16:49:21.74
    新闻简介: 3 口设计:华为 66W 氮化镓充电器69元拼团购(上市379元)
    ———————-
    标题: 部分地区不定时补货:M4 版 Mac mini 国补后 3565 元,支持 6 期免息
    发布时间: 2024-11-01T20:59:50.517
    新闻简介: 苹果 2024 款 Mac mini 于 10 月 29 日发布,搭载 M4 / M4 Pro 芯片,内存 16GB 起步。
    ———————-
    标题: 腾讯互娱再离职一员大将,内部通报为高压线事件
    发布时间: 2024-11-01T17:55:52.317
    新闻简介: 腾讯互娱天美 L1 工作室电竞发展中心总经理张易加已于近期从腾讯离职。凤凰网科技从多位不同信源方面获知,或为高压线事件,一位接近腾讯互娱的内部人士称,“内部邮件通报中写的是供应商贪腐”。(凤凰网科技)
    ———————-
    标题: 小米 SU7 汽车 10 月实现单月交付量首破 20000 ,预计本月提前完成全年目标
    发布时间: 2024-11-01T08:55:16.187
    新闻简介: 小米汽车今天上午宣布,2024年10月,小米SU7交付量超过20000台。这是小米汽车单月交付量首次突破2万台,预计本月将提前完成10万台全年交付目标。
    ———————-
    标题: 小米 SU7 Ultra 原型车首次冲击纽北纪录片,《6′46″874》完整版上映
    发布时间: 2024-11-01T12:15:17.363
    新闻简介: 小米汽车今天午间宣布,名为《6′46″874》的小米 SU7 Ultra 原型车首次冲击纽北纪录片完整版正式上映。“向纽北官方、国内同行、i-Pool 联盟,致以最诚挚的敬意。”
    ———————-
    标题: 全球首次,首架 C919 交付机“换心”成功
    发布时间: 2024-11-01T18:08:03.563
    新闻简介: 据中国民航网报道,10 月 25 日,随着停靠在西安咸阳国际机场 202 机位的东航首架 C919 国产大飞机试车各项参数正常,标志着 C919 全球首架交付机首次换发工作圆满完成。
    ———————-
    标题: 雷军:小米 SU7 车主里有 56% 是苹果 iPhone 用户
    发布时间: 2024-11-01T21:03:37.047
    新闻简介: 雷军今年 4 月公布的SU7数据显示:当时 BBA 用户购买者占比 29%,苹果用户购买者占比 51.9%。
    ———————-

    —- IT之家新闻 End —-

  • 11月02日,星期六, 每天60秒读懂全世界!

    百度热搜新闻

    新闻来源:百度热搜榜

    1. 中方决定对韩国等9国试行免签 11月1日,外交部发言人林剑表示:中方决定自2024年11月8日至2025年12月31日,对韩国等9国试行免签。

    2. 吕梁民政局:别为了领1500结婚又离婚 近日,吕梁市政府发布通告称:山西吕梁女性35岁前初婚奖励1500元。民政局回应:别为了领1500结婚又离婚。

    3. 全国秋粮收购超4000万吨 11月1日,全国秋粮收购全面展开。截至目前,主产区各类粮食企业累计收购秋粮超4000万吨,其中中晚稻收购超2300万吨。

    4. 13岁女孩遭强迫卖淫 3名公职人员获刑 日前,湖南新化一13岁女孩遭强迫卖淫案引起关注。犯案者中有3人为公职人员。目前涉案人员均已获刑,涉案公职人员也均被开除。

    5. 中学年薪50万招老师 干6年送房 10月30日,神木市实验中学公示校招教师录取名单,获聘教师均来自名校,其“50万年薪,免费提供住房”的待遇引发网友热议。

    6. 德国总统道歉:请求你们原谅

    7. 主持人王冠官宣婚讯

    8. 女大学生神似刘亦菲被围观合影 近日,燕京理工学院一女生“撞脸”刘亦菲,在校园内被围观拍照。网友:终于知道莞莞类卿的威力了。

    9. 黑老大财产被拍卖 2块表值8000万 10月31日,深圳市中级人民法院对两块百达翡丽腕表进行司法拍卖,引发网友关注。据悉,仅单块手表市场估价就超4000万元

    10. 男子辅导女儿作业被气进抢救室

    —- 百度热搜新闻 End —-

    知乎新闻

    新闻来源:知乎日榜

    标题: 冰毒是如何从军需药品发展成为新一代毒品之王的?
    链接: https://daily.zhihu.com/story/9776515
    ———————-
    标题: 为什么不把路由器集成在计算机里?
    链接: https://daily.zhihu.com/story/9776518
    ———————-
    标题: 自然界有哪些很残酷的现象?
    链接: https://daily.zhihu.com/story/9776524
    ———————-
    标题: 瞎扯 · 如何正确地吐槽
    链接: https://daily.zhihu.com/story/9776531
    ———————-

    —- 知乎新闻 End —-

    IT之家新闻

    新闻来源:ITHome之家科技新闻

    标题: 2025 款奥迪 A8L 轿车上市:升级高通骁龙 8150 芯片,78.98 万元起
    发布时间: 2024-11-01T11:24:35.967
    新闻简介: 2025 款奥迪 A8L 系列车型现已上市,该车提供 5 款版本可选,指导价格为 78.98 万元起。
    ———————-
    标题: 雷军谈小米 15 定价:打破了 3999 元的“心魔”
    发布时间: 2024-11-01T20:31:48.587
    新闻简介: 雷军称,这次在精致度上多投一点钱,“做高端手机第一条就是高端要无短板,第二条要从简单的参数比较进化到体验、感受和审美。”#雷军再回应小米15涨价##雷军说小米15破除了3999元心魔#
    ———————-
    标题: 苹果 M4 Pro 芯片跑分曝光:单核比 M3 Pro 高 25%、多核高 45%
    发布时间: 2024-11-01T10:02:02.003
    新闻简介: 科技媒体 AppleInsider 今天(11 月 1 日)发布博文,报道称苹果 M4 Pro 芯片的 GeekBench 跑分已曝光,单核得分为 3925,多核得分为 22669。
    ———————-
    标题: 库克发喜报:苹果 iPhone 同期销量节节攀升,16>15>14 系列
    发布时间: 2024-11-01T07:18:07.883
    新闻简介: 苹果公布 2024 财年第 4 财季财报(对应截至 9 月 28 日的第 3 季度)后,公司首席执行官蒂姆・库克(Tim Cook)接受 CNBC 采访时表示:“iPhone 15 的销售比同期 14 系列更强,而 16 系列的销售又比 15 强”。
    ———————-
    标题: 3698 元 + 24 期免息:小米 14 手机 16G+512G 京东自营新低
    发布时间: 2024-11-01T12:00:33.883
    新闻简介: 3698 元 + 24 期免息:小米 14 手机 16G+512G 京东自营新低
    ———————-
    标题: 多口设计:华为 66W 氮化镓充电器 79 元拼团购(上市 379 元)
    发布时间: 2024-11-01T16:49:21.74
    新闻简介: 3 口设计:华为 66W 氮化镓充电器69元拼团购(上市379元)
    ———————-
    标题: 部分地区不定时补货:M4 版 Mac mini 国补后 3565 元,支持 6 期免息
    发布时间: 2024-11-01T20:59:50.517
    新闻简介: 苹果 2024 款 Mac mini 于 10 月 29 日发布,搭载 M4 / M4 Pro 芯片,内存 16GB 起步。
    ———————-
    标题: 腾讯互娱再离职一员大将,内部通报为高压线事件
    发布时间: 2024-11-01T17:55:52.317
    新闻简介: 腾讯互娱天美 L1 工作室电竞发展中心总经理张易加已于近期从腾讯离职。凤凰网科技从多位不同信源方面获知,或为高压线事件,一位接近腾讯互娱的内部人士称,“内部邮件通报中写的是供应商贪腐”。(凤凰网科技)
    ———————-
    标题: 小米 SU7 汽车 10 月实现单月交付量首破 20000 ,预计本月提前完成全年目标
    发布时间: 2024-11-01T08:55:16.187
    新闻简介: 小米汽车今天上午宣布,2024年10月,小米SU7交付量超过20000台。这是小米汽车单月交付量首次突破2万台,预计本月将提前完成10万台全年交付目标。
    ———————-
    标题: 小米 SU7 Ultra 原型车首次冲击纽北纪录片,《6′46″874》完整版上映
    发布时间: 2024-11-01T12:15:17.363
    新闻简介: 小米汽车今天午间宣布,名为《6′46″874》的小米 SU7 Ultra 原型车首次冲击纽北纪录片完整版正式上映。“向纽北官方、国内同行、i-Pool 联盟,致以最诚挚的敬意。”
    ———————-
    标题: 全球首次,首架 C919 交付机“换心”成功
    发布时间: 2024-11-01T18:08:03.563
    新闻简介: 据中国民航网报道,10 月 25 日,随着停靠在西安咸阳国际机场 202 机位的东航首架 C919 国产大飞机试车各项参数正常,标志着 C919 全球首架交付机首次换发工作圆满完成。
    ———————-
    标题: 雷军:小米 SU7 车主里有 56% 是苹果 iPhone 用户
    发布时间: 2024-11-01T21:03:37.047
    新闻简介: 雷军今年 4 月公布的SU7数据显示:当时 BBA 用户购买者占比 29%,苹果用户购买者占比 51.9%。
    ———————-

    —- IT之家新闻 End —-

  • Spring 的事件与监听机制以及实际应用


    共计 2640 个字符,预计需要花费 7 分钟才能阅读完成。

    一、简介

    Spring框架提供了事件与监听机制,用于实现松耦合和事件驱动的编程模型。这个机制基于观察者设计模式,其中包含三个重要组件:事件(Event)、事件发布器(Event Publisher)和监听器(Listener)。

    1. 事件(Event)

    事件是系统中发生的特定动作或状态变化的表示。在Spring中,事件通常被定义为Java类,可以包含事件相关的数据和操作,并且该类需要继承 ApplicationEvent 类。

    例如,可以定义一个名为 AuthUpdateEvent 的事件,表示更新权限的动作,这个动作在很多情况下都会触发,比如用户更新了角色,角色更新了菜单等等。

    2. 监听器(Listener)

    监听器是用于监听特定类型事件并在事件发生时执行相应操作的组件。在Spring中,可以通过实现 ApplicationListener 接口或使用 @EventListener 注解来定义监听器。监听器需要注册到事件发布器中,以便接收并处理相应的事件。

    例如,定义 AuthUpdateListener,当监听到 AuthUpdateEvent 事件时,就执行其 onApplicationEvent 方法。

    3. 事件发布器(Event Publisher)

    事件发布器负责发布事件,即将事件通知给所有对该事件感兴趣的监听器。在Spring中,可以通过ApplicationContext或ApplicationEventPublisher接口来实现事件的发布。事件发布器会将事件传递给注册的监听器。

    二、实际使用

    1. 流程

    • 定义事件:创建一个继承自 ApplicationEvent 的事件类,表示一个特定的事件。

    • 注册监听器:创建一个实现了 ApplicationListener 接口的监听器类,并将其注册到Spring 容器中。可以通过实现接口的方式或使用 @EventListener 注解的方式进行注册。

    • 发布事件:在需要的地方,通过 ApplicationEventPublisher接口的实例(如ApplicationContext或通过依赖注入获得的实例)发布事件。

    • 监听事件并处理:注册的监听器会接收到发布的事件,并执行相应的操作。监听器需要实现onApplicationEvent 方法,在该方法中编写事件处理逻辑。

    2. 代码

    接下来实现用户更新角色后,更新权限的问题。

    2.1 定义事件

    public class AuthUpdateEvent extends ApplicationEvent {
    
        private User user;
    
        public AuthUpdateEvent(Object source, User user) {
            super(source);
            this.user = user;
        }
    
        public User getUser() {
            return user;
        }
    }

    定义一个事件,事件里面包含一个 User 对象作为事件的数据。

    @Data
    public class User {
    
        int age;
    
        String username;
    }

    2.2 定义监听器

    @Component
    public class AuthUpdateListener implements ApplicationListener<AuthUpdateEvent> {
    
        @Override
        public void onApplicationEvent(AuthUpdateEvent event) {
            User user = event.getUser();
            // 更新用户权限
            System.out.println("实现接口方式===========监听事件执行,更新用户"+ user.getUsername() + "的权限");
        }
    }

    定义一个监听器,监听到事件发布后指定 onApplicationEvent 方法。

    定义监听器还可以通过另外一种方式,这种方式使用 @EventListener 注解。

    @Component
    public class AuthUpdateListener2 {
    
        @EventListener
        public void onApplicationEvent(AuthUpdateEvent event) {
            User user = event.getUser();
            // 更新用户权限
            System.out.println("注解方式===========监听事件执行,更新用户"+ user.getUsername() + "的权限");
        }
    }

    2.3 定义事件发布器

    事件发布一般都在业务层,这里定义一个 UserService。

    接口类:

    public interface UserService {
    
        void updateUserRole(User user);
    }

    实现类:

    @Service
    public class UserServiceImpl implements UserService {
    
        @Autowired
        private ApplicationEventPublisher eventPublisher;
    
        @Override
        public void updateUserRole(User user) {
            System.out.println("UserService执行更新角色操作");
            eventPublisher.publishEvent(new AuthUpdateEvent(this, user));
        }
    }

    2.4 测试

    由于这里是 spring 测试环境,所以还需要将上面的组件注册到容器中,需要定义一个 Spring 配置类,并进行组件扫描。

    @Configuration
    @ComponentScan("com.amjun.extend.event")
    public class SpringConfig {
        // 由于只做组件扫描,没有其他的代码
    }

    测试类如下:

    public class ApplicationContextTest {
    
        public static void main(String[] args) {
            AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
            UserService userService = applicationContext.getBean(UserService.class);
            User user = new User();
            user.setUsername("zhangsan");
            userService.updateUserRole(user);
        }
    }
    

    提醒:本文发布于405天前,文中所关联的信息可能已发生改变,请知悉!

    Tips:清朝云网络工作室