Spring扩展点系列-InstantiationAwareBeanPostProcessor

news2024/11/13 11:30:26

文章目录

    • 简介
    • 测试一
      • 1、配置文件Bean注册
      • 2、单元测试方法
      • 3、测试类
      • 4、输出结果
      • 结论
    • 测试二
      • 1、测试类
      • 2、输出结果
      • 结论
    • 源码解析
      • postProcessProperties
        • CommonAnnotationBeanPostProcessor
        • AnnotationInjectedBeanPostProcessor
    • 总结

简介

spring容器中Bean的生命周期内所有可扩展的点的调用顺序
扩展接口 实现接口
ApplicationContextlnitializer initialize
AbstractApplicationContext refreshe
BeanDefinitionRegistryPostProcessor postProcessBeanDefinitionRegistry
BeanDefinitionRegistryPostProcessor postProcessBeanFactory
BeanFactoryPostProcessor postProcessBeanFactory
instantiationAwareBeanPostProcessor postProcessBeforelnstantiation
SmartlnstantiationAwareBeanPostProcessor determineCandidateConstructors
MergedBeanDefinitionPostProcessor postProcessMergedBeanDefinition
InstantiationAwareBeanPostProcessor postProcessAfterlnstantiation
SmartInstantiationAwareBeanPostProcessor getEarlyBeanReference
BeanFactoryAware postProcessPropertyValues
ApplicationContextAwareProcessor invokeAwarelnterfaces
BeanNameAware setBeanName
InstantiationAwareBeanPostProcessor postProcessBeforelnstantiation
@PostConstruct
InitializingBean afterPropertiesSet
FactoryBean getobject
SmartlnitializingSingleton afterSingletonslnstantiated
CommandLineRunner run
DisposableBeandestroy

从源码中我们可以获知InstantiationAwareBeanPostProcessor接口除了具有父接口中的两个方法以外还自己额外定义了三个方法。所以该接口一共定义了5个方法,这5个方法的作用分别是

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
	@Nullable
	default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		return null;
	}

	default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
		return true;
	}
	
	@Nullable
	default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
			throws BeansException {

		return null;
	}

public interface BeanPostProcessor {
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
}
方法描述
postProcessBeforeInitialization方法将在Bean实例的afterPropertiesSet方法或者自定义的init方法被调用前调用,此时Bean属性已经被赋值。方法返回原始Bean实例或者包装后的Bean实例,如果返回null,则后续的后置处理方法不再被调用。
postProcessAfterInitialization方法将在Bean实例的afterPropertiesSet方法或者自定义的init方法被调用后调用,此时Bean属性已经被赋值。方法返回原始Bean实例或者包装后的Bean实例,如果返回null,则后续的后置处理方法不再被调用。
postProcessBeforeInstantiation方法作用为:在Bean实例化前调用该方法,返回值可以为代理后的Bean,以此代替Bean默认的实例化过程。返回值不为null时,后续只会调用BeanPostProcessor的 postProcessAfterInitialization方法,而不会调用别的后续后置处理方法(如postProcessAfterInitialization、postProcessBeforeInstantiation等方法);返回值也可以为null,这时候Bean将按默认方式初始化。
postProcessAfterInstantiation方法作用为:当Bean通过构造器或者工厂方法被实例化后,当属性还未被赋值前,该方法会被调用,一般用于自定义属性赋值。方法返回值为布尔类型,返回true时,表示Bean属性需要被赋值;返回false表示跳过Bean属性赋值,并且InstantiationAwareBeanPostProcessor的postProcessProperties方法不会被调用。

Instantiation为实例化的意思,Initialization为初始化的意思。在Spring Bean生命周期中,实例化指的是创建Bean的过程,初始化指的是Bean创建后,对其属性进行赋值(populate bean)、后置处理等操作的过程,所以Instantiation执行时机先于Initialization。

测试一

简单测试一下,看看每个方法的执行顺序

1、配置文件Bean注册

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       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">

    <bean class="cn.mycode.chen.myunit.config.springextend.TestAutowired" id="testAutowired" init-method="init">
        <property name="testName" value="若曼底登陆"></property>
    </bean>

    <!-- 注册InstantiationAwareBeanPostProcessor对象 -->
    <bean class="cn.mycode.chen.myunit.config.springextend.ExtendInstantiationAwareBeanPostProcessor"></bean>
</beans>

2、单元测试方法

@Test
public void test2() {
    ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    TestAutowired testAutowired = ac.getBean(TestAutowired.class);
    System.out.println(testAutowired);
    // 关闭销毁
    ac.registerShutdownHook();
}

3、测试类

一个业务类TestAutowired

@Slf4j
@Component
public class TestAutowired {

    private String testName ;

    public TestAutowired(){
        log.info("TestAutowired构造方法实例化------run");
    }


    public void setTestName(String testName) {
        log.info("设置属性:"+testName);
        this.testName = testName;
    }

    @PostConstruct
    public void init() {
        log.info("init bean执行 ");
        this.testName = "若曼底登陆";
    }

    public void start() {
        log.info("TestAutowired init-method run" );
    }
}

InstantiationAwareBeanPostProcessor的实现测试类

@Slf4j
@Configuration
public class ExtendInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    /**
     * BeanPostProcessor接口中的方法
     * 在Bean的自定义初始化方法之前执行
     * Bean对象已经存在了
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // TODO Auto-generated method stub
        log.info(">>postProcessBeforeInitialization");
        return bean;
    }

    /**
     * BeanPostProcessor接口中的方法
     * 在Bean的自定义初始化方法执行完成之后执行
     * Bean对象已经存在了
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        log.info("<<postProcessAfterInitialization");
        return bean;
    }

    /**
     * InstantiationAwareBeanPostProcessor中自定义的方法
     * 在方法实例化之前执行  Bean对象还没有
     */
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        log.info("--->postProcessBeforeInstantiation");
        return null;
    }

    /**
     * InstantiationAwareBeanPostProcessor中自定义的方法
     * 在方法实例化之后执行  Bean对象已经创建出来了
     */
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        log.info("<---postProcessAfterInstantiation");
        return true;
    }

    /**
     * InstantiationAwareBeanPostProcessor中自定义的方法
     * 可以用来修改Bean中属性的内容
     */
    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean,
                                                    String beanName) throws BeansException {
        log.info("<---postProcessPropertyValues--->");
        return pvs;
    }
}

4、输出结果

执行测试方法,输出如下结果

springextend.ExtendInstantiationAwareBeanPostProcessor - --->postProcessBeforeInstantiation
springextend.TestAutowired - TestAutowired构造方法实例化------run
springextend.ExtendInstantiationAwareBeanPostProcessor - <---postProcessAfterInstantiation
springextend.ExtendInstantiationAwareBeanPostProcessor - <---postProcessPropertyValues--->
springextend.TestAutowired - 设置属性:若曼底登陆
ExtendInstantiationAwareBeanPostProcessor - >>postProcessBeforeInitialization
springextend.TestAutowired - init bean执行 
springextend.ExtendInstantiationAwareBeanPostProcessor - <<postProcessAfterInitialization

结论

通过打印结果可以看到五个方法全部都执行,并且清楚它们的执行顺序

测试二

基于测试一的代码,更改postProcessBeforeInstantiation方法内部返回

1、测试类

postProcessBeforeInstantiation方法代码

@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
    log.info("--->postProcessBeforeInstantiation");
    return new TestAutowired();
}

2、输出结果

从打印结果看,该方法返回的结果如果为null,后面的方法都正常执行了,但是如果postProcessBeforeInstantiation方法返回实例对象后跳过了对象的初始化操作,直接执行了postProcessAfterInitialization(该方法在自定义初始化方法执行完成之后执行),跳过了postProcessAfterInstantiation,postProcessPropertyValues以及自定义的初始化方法

springextend.ExtendInstantiationAwareBeanPostProcessor - --->postProcessBeforeInstantiation
springextend.TestAutowired - TestAutowired构造方法实例化------run
springextend.ExtendInstantiationAwareBeanPostProcessor - <<postProcessAfterInitialization

结论

postProcessBeforeInstantiation方法是最先执行的方法,它在目标对象实例化之前调用,该方法的返回值类型是Object,我们可以返回任何类型的值。由于这个时候目标对象还未实例化,所以这个返回值可以用来代替原本该生成的目标对象的实例(比如代理对象)。如果该方法的返回值代替原本该生成的目标对象,后续只有postProcessAfterInitialization方法会调用,其它方法不再调用;否则按照正常的流程走

源码解析

postProcessProperties

  • CommonAnnotationBeanPostProcessor : 注册带有 @Resource 注解的属性
  • AutowiredAnnotationBeanPostProcessor : 处理带有 @Value、@Autowired、@Inject、@Lookup 注解的属性
CommonAnnotationBeanPostProcessor
static {
		//将需要解析的注解 都先加载进来  @Resource必须加载,@WebServiceRef和@EJB按条件加载
		resourceAnnotationTypes.add(Resource.class);

		webServiceRefClass = loadAnnotationType("javax.xml.ws.WebServiceRef");
		if (webServiceRefClass != null) {
			resourceAnnotationTypes.add(webServiceRefClass);
		}

		ejbClass = loadAnnotationType("javax.ejb.EJB");
		if (ejbClass != null) {
			resourceAnnotationTypes.add(ejbClass);
		}
	}

postProcessProperties方法的逻辑就是找到对应的带有注解的元数据Metadata ,然后注入进去

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
	InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
	try {
		metadata.inject(bean, beanName, pvs);
	}
	catch (Throwable ex) {
		throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
	}
	return pvs;
}

findResourceMetadata方法主要就是查询元数据信息

private InjectionMetadata findResourceMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
		// 首先优先用beanName 作为缓存的Key,没有beanName回退到类名作为缓存键
		String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
		// 首先快速检查并发映射(从缓存里面获取,是否已经存在)
		InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
		// needsRefresh判断是否为null ,为null就重新创建, 这里是一个双重检查
		if (InjectionMetadata.needsRefresh(metadata, clazz)) {
			synchronized (this.injectionMetadataCache) {
				metadata = this.injectionMetadataCache.get(cacheKey);
				if (InjectionMetadata.needsRefresh(metadata, clazz)) {
					// 如果不为null ,先清除一下
					if (metadata != null) {
						metadata.clear(pvs);
					}
					// 这里开始创建,并放入缓存,详细在下面分析
					metadata = buildResourceMetadata(clazz);
					this.injectionMetadataCache.put(cacheKey, metadata);
				}
			}
		}
		return metadata;
	}

buildResourceMetadata类的大概逻辑主要是对字段,方法遍历,看是否带有 @Resource,@WebServiceRef,@EJB 注解 ,如果有就对 其进行解析, 然后再将结果放入一个list

private InjectionMetadata buildResourceMetadata(Class<?> clazz) {
		if (!AnnotationUtils.isCandidateClass(clazz, resourceAnnotationTypes)) {
			return InjectionMetadata.EMPTY;
		}

		List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
		Class<?> targetClass = clazz;

		do {
			final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();

			ReflectionUtils.doWithLocalFields(targetClass, field -> {
				if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
					if (Modifier.isStatic(field.getModifiers())) {
						throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields");
					}
					currElements.add(new WebServiceRefElement(field, field, null));
				}
				else if (ejbClass != null && field.isAnnotationPresent(ejbClass)) {
					if (Modifier.isStatic(field.getModifiers())) {
						throw new IllegalStateException("@EJB annotation is not supported on static fields");
					}
					currElements.add(new EjbRefElement(field, field, null));
				}
				else if (field.isAnnotationPresent(Resource.class)) {
					if (Modifier.isStatic(field.getModifiers())) {
						throw new IllegalStateException("@Resource annotation is not supported on static fields");
					}
					if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
						currElements.add(new ResourceElement(field, field, null));
					}
				}
			});
			
			//如果方法上面有 @Resource,@WebServiceRef,@EJB 注解 ,就放入list
			ReflectionUtils.doWithLocalMethods(targetClass, method -> {
				Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
				if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
					return;
				}
				if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
					if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {
						if (Modifier.isStatic(method.getModifiers())) {
							throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");
						}
						if (method.getParameterCount() != 1) {
							throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method);
						}
						PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
						currElements.add(new WebServiceRefElement(method, bridgedMethod, pd));
					}
					else if (ejbClass != null && bridgedMethod.isAnnotationPresent(ejbClass)) {
						if (Modifier.isStatic(method.getModifiers())) {
							throw new IllegalStateException("@EJB annotation is not supported on static methods");
						}
						if (method.getParameterCount() != 1) {
							throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);
						}
						PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
						currElements.add(new EjbRefElement(method, bridgedMethod, pd));
					}
					else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
						if (Modifier.isStatic(method.getModifiers())) {
							throw new IllegalStateException("@Resource annotation is not supported on static methods");
						}
						Class<?>[] paramTypes = method.getParameterTypes();
						if (paramTypes.length != 1) {
							throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);
						}
						if (!this.ignoredResourceTypes.contains(paramTypes[0].getName())) {
							PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
							currElements.add(new ResourceElement(method, bridgedMethod, pd));
						}
					}
				}
			});

			elements.addAll(0, currElements);
			targetClass = targetClass.getSuperclass();
		}
		while (targetClass != null && targetClass != Object.class);

		return InjectionMetadata.forElements(elements, clazz);
	}

inject方法获取里面的 InjectedElement 列表 ,然后开始遍历注入

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
	Collection<InjectedElement> checkedElements = this.checkedElements;
	Collection<InjectedElement> elementsToIterate =
			(checkedElements != null ? checkedElements : this.injectedElements);
	if (!elementsToIterate.isEmpty()) {
		for (InjectedElement element : elementsToIterate) {
			element.inject(target, beanName, pvs);
		}
	}
}
AnnotationInjectedBeanPostProcessor

AnnotationInjectedBeanPostProcessor大体的逻辑也是一样,但是针对的注解主要是@Value,@Autowired, @Inject

@Override
public PropertyValues postProcessPropertyValues(
        PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {

    InjectionMetadata metadata = findInjectionMetadata(beanName, bean.getClass(), pvs);
    try {
        metadata.inject(bean, beanName, pvs);
    } catch (BeanCreationException ex) {
        throw ex;
    } catch (Throwable ex) {
        throw new BeanCreationException(beanName, "Injection of @" + getAnnotationType().getName()
                + " dependencies is failed", ex);
    }
    return pvs;
}

总结

在这里插入图片描述

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

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

相关文章

Apache DolphinScheduler大规模任务调度系统对大数据实时Flink任务支持

转载自神龙大侠 我是用olphinScheduler 3.2.1版本做源代码编译部署&#xff08;部署方式参考我的另外一篇文档《源代码编译&#xff0c;Apache DolphinScheduler前后端分离部署解决方案》&#xff09; 二进制文件部署本文也适用&#xff0c;只需要修改相对应的配置即可。 资…

科普小课堂:中等硬度的床垫,合适的睡姿,通过日常力量练习提升自身能力以支撑脊柱形态。

文章目录 引言I 选择合适床垫的指标3:1 原则睡得舒服与否II 日常力量练习翻书-胸椎活动度练习猫式-脊柱整体活动度练习III 知识扩展人体脊柱“S”型生理曲线软床垫对腰椎的影响硬床垫对腰椎的影响合适的睡姿引言 女性瘦型体型人群脊柱曲线相对较明显,尤其是腰部曲线,需选择承…

优化LabVIEW中TCP通信速度的方法

在LabVIEW中&#xff0c;TCP通信速度较慢可能由多种因素导致&#xff0c;如数据包处理延迟、阻塞式读取或数据解析效率低等。通过调整读取模式、优化数据处理逻辑、以及使用并行处理结构&#xff0c;可以显著提升TCP通信的速度&#xff0c;使其接近第三方调试工具的表现。LabVI…

DNS介绍(hosts文件,域名结构),面试题(输入url后会发生什么)

目录 DNS 引入 hosts文件 域名 主域名 结构 www 公司/组织/个人名称 后缀 面试题 简单回答 部分https 细节 DNS 引入 域名介绍,url的介绍原理特殊字符的处理,网络行为,http协议请求/响应的格式结构,状态码介绍,临时/永久重定向,http报头常见字段(长/短连接介绍,lo…

阿里云身份证二要素详细使用

初步&#xff1a; 先登录阿里云&#xff08;找官网链接&#xff09; 2、云市场搜索身份证二要素 看个人需求选择 3、我选择的是下边这个 4、接下来看文档具体调用&#xff08;在请求示例中有选择语言的代码 我选择的就是java&#xff09; 5、在控制台看appcode码 放入代码中…

如何解决企业防盗版/防勒索病毒?一个方案五步搞定!

SPN&#xff08;Sandbox Proxy Network&#xff09;解决方案通过创建一个隔离的沙盒环境&#xff0c;为企业提供了一个安全、受控的互联网访问方式。该方案特别适用于防止盗版软件的骚扰和勒索病毒的攻击&#xff0c;确保企业数据和网络环境的安全。 1. 核心功能 物理隔离&…

u盘数据如何恢复,数据恢复技巧分享

在数字化时代&#xff0c;U盘作为便携的数据存储设备&#xff0c;广泛应用于工作、学习和生活中。然而&#xff0c;误删文件、格式化错误或物理损坏等意外情况时有发生&#xff0c;导致重要数据丢失。本文将为你提供一套全面的U盘数据恢复指南&#xff0c;从基础方法到进阶技巧…

Unity(2022.3.41LTS) - UI详细介绍-画布

目录 零. 简介 一、图像的基本属性 二、图像的类型 三、图像的使用方法 四、代码控制图像 五、优化和注意事项 零. 简介 在 Unity 中&#xff0c;图像&#xff08;Image&#xff09;是一种常用的 UI 元素&#xff0c;用于显示静态图片或 Sprite&#xff08;精灵图&#…

美杜莎(Medusa)勒索软件如何把你的文件变成了“石头”

写在前面的话 近期&#xff0c;Unit 42的研究人员在分析Medusa&#xff08;美杜莎&#xff09;勒索软件活动时&#xff0c;发现该活动的升级和勒索策略发生了很大变化。 Medusa勒索软件活动在2023年初上线了一个名为“Medusa Blog”的专用数据泄露网站&#xff0c;而该活动背…

利用Go语言模拟实现Raft协议

近来学习到区块链&#xff0c;想要模拟实现 Raft 协议。但是发现网上教程很杂&#xff0c;或者说很多教程并不适合于新手从零开始进行实现。 本文将从头开始复现个人模拟实现 Raft 的过程&#xff0c;完成后整个模拟后&#xff0c;读者应该学会 Go 语言的基本语法、Rpc 编程的基…

路由器内部到底是啥结构?不懂不算网工人

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部 下午好&#xff0c;我的网工朋友。 在现代互联网中&#xff0c;路由器作为连接不同网络的枢纽&#xff0c;发挥着至关重要的作用。无论是简单的家…

通用文字识别API如何通过Java进行调用?(一)

一、什么是通用文字识别&#xff1f; 通用文字识别又叫通用文字OCR识别&#xff0c;文字识别&#xff0c;文字图片识别&#xff0c;通用文字识别是一种算法识别技术&#xff0c;它能够将图像中的文字转换为可编辑的文本格式&#xff0c;可支持多种类型图片类型。 二、通用文字…

java 基于Swing的随机点名

由于教学的原因&#xff0c;编写的一个随机点名程序&#xff0c;废话不多说&#xff0c;直接上代码&#xff1a; package org.example;import java.awt.Color; import java.awt.Font; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.…

CAN(江科大CAN学习)

1.CAN CAN简介 • CAN 总线&#xff08; Controller Area Network Bus &#xff09;控制器局域网总线 CAN总线构建的是一种局域网网络&#xff0c;每个挂载在can总线上的设备&#xff0c;都可以利用这个局域网去发送自己的信息&#xff0c;也可以接受局域网的各种消息&#x…

Unity中保存数据的方法

一、概述 Unity中可用于持久化的方式有&#xff1a; 1&#xff09;通过ScriptableObject在可编辑模式下保存数据 2&#xff09;通过excel、json等文件实现数据的可持久化 二、ScriptableObject的使用 1、使用背景 假如需要制作子弹预设体&#xff0c;每个子弹上有speed速…

windows 10安装GPU版本pytorch

一、下载Anaconda 1.由于anaconda的服务器都在国外&#xff0c;推荐大家使用镜像源进行下载&#xff0c;清华的conda镜像链接&#xff1a;​​​​​​ anaconda | 镜像站使用帮助 | 清华大学开源软件镜像站 | Tsinghua Open Source Mirrora 2.使用命令新建一个虚拟环境&#…

一个简单的 NLP 神经网络

如何搭建一个简单的 NLP 神经网络&#xff1f; 假设我们一个变量名列表&#xff0c;根据这个变量名列表&#xff0c;学习其中的特征并生成新的变量名。训练一个模型用于预测下一个字符并生成新的变量名。使用一个单层的神经网络实现&#xff0c;假设我们的变量名只能用英文字母…

Python爬虫02

xml 和html 区别 jsonpath模块 场景 多层嵌套的复杂字典直接提取数据 安装 pip install jsonpath使用 from jsonpath import jsonpathret jsonpath(dict, jaonpath语法规则字符串)语法规则 eg: lxml模块&xpath语法 谷歌浏览器 xpath helper 插件 作用对当前页面…

d3dcompiler_47.dll缺失的可能原因多种多样,那么d3dcompiler_47.dll缺失怎么修复

在数字世界的深处&#xff0c;d3dcompiler_47.dll文件扮演着至关重要的角色&#xff0c;它是Direct3D编译器的一部分&#xff0c;负责处理图形渲染和游戏运行中的关键任务。然而&#xff0c;当用户启动某个程序或游戏时&#xff0c;屏幕上突然弹出的错误提示“d3dcompiler_47.d…

DevOps学习笔记

记录以下DevOps学习笔记&#xff0c;这里是笔记的入口汇总&#xff0c;可以直观的看到所有的笔记&#xff0c;还没有入口的部分&#xff0c;在下正在努力编写中。 gitlab jenkins docker docker安装 artifactory 1.artifactory安装 2.artifactory使用 计算机网络 1.dn…