实现Spring底层机制(三)

文章目录

  • 阶段4—实现BeanPostProcessor机制
    • 1.文件目录
    • 2.初始化方法实现
        • 1.编写初始化接口InitializingBean.java
        • 2.MonsterService.java实现初始化接口
        • 3.容器中的createBean方法增加初始化逻辑,判断对象类型是否是InitializingBean的子类型,如果是,则转换成初始化接口类型执行初始化方法
    • 3.后置处理器实现
        • 1.编写后置处理器接口BeanPostProcessor.java
        • 2.在组件文件夹下编写后置处理器实现类SunBeanPostProcessor.java会被容器扫描
        • 3.容器类完整代码SunSpringApplicationContext.java
        • 4.结果展示
    • 4.该阶段完成的任务
  • 阶段5—实现AOP机制&Spring底层机制总结
    • 1.实现AOP机制
        • 1.原理分析
        • 2.代码实现
          • 1.文件目录
          • 2.编写接口SmartAnimalable.java
          • 2.编写实现类SmartDog.java
          • 3.编写切面类SmartAnimalAspect.java
          • 4.修改SunBeanPostProcessor.java对SmartDog的getSum方法进行动态代理
          • 5.启动类
          • 6.结果展示
        • 3.该阶段完成的任务
    • 2.Spring底层机制总结
        • 1.bean的生命周期
        • 2.Spring容器的执行流程
        • 3.动态代理和AOP的区别
        • 4.关于后置处理器 + 动态代理的理解
        • 5.AOP的使用方式

阶段4—实现BeanPostProcessor机制

1.文件目录

image-20240222142242669

2.初始化方法实现

1.编写初始化接口InitializingBean.java
package com.sun.spring.processor;/*** 该接口有一个方法afterPropertiesSet是在依赖注入之后调用,即初始化方法* @author 孙显圣* @version 1.0*/
public interface InitializingBean {void afterPropertiesSet() throws Exception;
}
2.MonsterService.java实现初始化接口
package com.sun.spring.component;import com.sun.spring.annotation.Autowired;
import com.sun.spring.annotation.Component;
import com.sun.spring.annotation.Scope;
import com.sun.spring.processor.InitializingBean;/*** @author 孙显圣* @version 1.0*/@Scope(value = "prototype") //指定是多例的
@Component(value = "monsterService")//自定义注解,自动反射创建bean对象,如果指定了value则id为value否则为首字母小写
public class MonsterService implements InitializingBean{//自定义注解,按照名字进行依赖注入@Autowiredprivate MonsterDao monsterDao;public void m1() {monsterDao.hi();}//初始化方法@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("MonsterService 的初始化方法被调用!");}
}
3.容器中的createBean方法增加初始化逻辑,判断对象类型是否是InitializingBean的子类型,如果是,则转换成初始化接口类型执行初始化方法

3.后置处理器实现

1.编写后置处理器接口BeanPostProcessor.java
package com.sun.spring.processor;/*** @author 孙显圣* @version 1.0*/
public interface BeanPostProcessor {//这两个方法会对Spring容器的所有bean生效,切面编程//bean初始化方法前调用default Object postProcessBeforeInitialization(Object bean, String beanName){return bean;}//bean初始化方法后调用default Object postProcessAfterInitialization(Object bean, String beanName){return bean;}
}
2.在组件文件夹下编写后置处理器实现类SunBeanPostProcessor.java会被容器扫描
package com.sun.spring.component;import com.sun.spring.annotation.Component;
import com.sun.spring.processor.BeanPostProcessor;/*** 后置处理器,实现了自定义的后置处理器的接口** @author 孙显圣* @version 1.0*/
//反射创建bean对象
@Component
public class SunBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) {System.out.println("\n后置处理器postProcessBeforeInitialization被调用 bean类型=" + bean.getClass() + "bean名字=" + beanName);if (bean instanceof Car) {System.out.println("后置处理器发现这个类型是Car类型");}return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) {System.out.println("后置处理器postProcessAfterInitialization被调用 bean类型=" + bean.getClass() + "bean名字=" + beanName);return bean;}
}
3.容器类完整代码SunSpringApplicationContext.java
package com.sun.spring.ioc;import com.sun.spring.annotation.Autowired;
import com.sun.spring.annotation.Component;
import com.sun.spring.annotation.ComponentScan;
import com.sun.spring.annotation.Scope;
import com.sun.spring.processor.BeanPostProcessor;
import com.sun.spring.processor.InitializingBean;
import org.apache.commons.lang.StringUtils;import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;/*** 类似于Spring原生的ioc容器** @author 孙显圣* @version 1.0*/
public class SunSpringApplicationContext {//传进来一个配置类的Class对象private Class configClass;//bean定义字段private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();//bean对象字段private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();//定义一个属性ArrayList来存放后置处理器private List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();//构造器,接收配置类的class对象public SunSpringApplicationContext(Class configClass) throws ClassNotFoundException, InstantiationException, IllegalAccessException {//bean定义扫描,并将信息封装到beanDefinitionMap中this.beanDefinitionScan(configClass);//初始化单例池//1.获取所有bean的名字Enumeration<String> keys = beanDefinitionMap.keys();//2.遍历名字while (keys.hasMoreElements()) {String beanName = keys.nextElement();//3.是单例类型的就创建bean对象并放到单例池中BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);if (beanDefinition.getScope().equals("singleton")) {Object bean = createBean(beanDefinition, beanName);//4.放到单例池singletonObjects.put(beanName, bean);}}}public void beanDefinitionScan(Class configClass) throws ClassNotFoundException, InstantiationException, IllegalAccessException {this.configClass = configClass;//一、获取要扫描的包//1.首先反射获取类的注解信息ComponentScan componentScan = (ComponentScan) this.configClass.getDeclaredAnnotation(ComponentScan.class);//2.通过注解来获取要扫描的包的路径String path = componentScan.value();System.out.println("要扫描的包=" + path);//二、得到要扫描包的.class文件对象,从而得到全路径进行反射//1.获取类加载器ClassLoader classLoader = SunSpringApplicationContext.class.getClassLoader();//2.获取要扫描包的真实路径,默认刚开始在根目录下path = path.replace(".", "/");URL resource = classLoader.getResource(path);//3.由该路径创建一个文件对象,可使用resource.getFile()将URL类型转化为String类型File file = new File(resource.getFile());//4.遍历该文件夹下的所有.class文件对象if (file.isDirectory()) {File[] files = file.listFiles();System.out.println("==================================扫描所有组件==================================");for (File f : files) {//反射注入容器//1.获取所有文件的绝对路径String absolutePath = f.getAbsolutePath();//只处理class文件if (absolutePath.endsWith(".class")) {//2.分割出类名String className = absolutePath.substring(absolutePath.lastIndexOf("\\") + 1,absolutePath.indexOf("."));//3.得到全路径String fullPath = path.replace("/", ".") + "." + className;//4.判断是否需要注入容器,查看有没有自定义的注解ComponentClass<?> aClass = classLoader.loadClass(fullPath);//如果该类使用了注解Component则说明是一个spring beanif (aClass.isAnnotationPresent(Component.class)) {//后置处理器逻辑//为了方便,将后置处理器放到ArrayList,原生的Spring容器中,对后置处理器还是放到的singletonObjects//判断当前的class对象是否实现了后置处理器的接口if (BeanPostProcessor.class.isAssignableFrom(aClass)) {//如果实现了后置处理器的接口则转换成后置处理器类型BeanPostProcessor beanPostProcessor = (BeanPostProcessor) aClass.newInstance();//添加到ArrayList中beanPostProcessors.add(beanPostProcessor);//后面我们并没有用到单例池中的后置处理器,所以不需要将这个bean定义的信息放到mapcontinue;}System.out.println("这是一个Spring bean=" + aClass);//将Bean的信息封装到BeanDefinition对象中并放入到beanDefinitionMapBeanDefinition beanDefinition = new BeanDefinition();//获取scope注解信息Scope scopeAnnotation = aClass.getDeclaredAnnotation(Scope.class);//只要scopeAnnotation是空的或者他不是空的但是值是空串,则返回singleon,否则就返回valueString scope = scopeAnnotation == null || scopeAnnotation.value().equals("") ?"singleton" : scopeAnnotation.value();//封装信息到bean定义字段中beanDefinition.setScope(scope);beanDefinition.setClazz(aClass);//获取Component注解的value值作为beanNameComponent componentAnnotation = aClass.getDeclaredAnnotation(Component.class);//只要component注解的值是空串就返回类名首字母小写,否则返回这个注解的值String beanName = componentAnnotation.value().equals("") ?StringUtils.uncapitalize(className) : componentAnnotation.value();//封装到beanDefinitionMap中beanDefinitionMap.put(beanName, beanDefinition);} else {System.out.println("这不是一个Spring bean=" + aClass);}}}}}//根据bean定义对象来创建bean对象private Object createBean(BeanDefinition beanDefinition, String beanName) {//获取Class对象,反射创建实例Class clazz = beanDefinition.getClazz();try {Object instance = clazz.getDeclaredConstructor().newInstance();//进行依赖注入//1.遍历所有字段for (Field field : clazz.getDeclaredFields()) {//2.判断字段中是否有autowired注解if (field.isAnnotationPresent(Autowired.class)) {//3.依赖注入String name = field.getName();Object bean = getBean(name);//反射爆破field.setAccessible(true);field.set(instance, bean);System.out.println(instance + "依赖注入完毕!");}}//初始化方法逻辑//判断是否要执行Bean的初始化方法//存储instanceObject result = instance;//查看这个对象是否实现了InitializingBean接口,instanceof判断是否是某个类型或者某个类型的子类型if (instance instanceof InitializingBean) {//在初始化方法之前调用后置处理器的before方法,可以对容器的bean进行修改for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {instance = beanPostProcessor.postProcessBeforeInitialization(instance, beanName);}//向上转型为接口类型并调用初始化方法((InitializingBean) instance).afterPropertiesSet();//在初始化方法之后调用后置处理器的before方法,可以对容器的bean进行修改for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);}}//如果返回的instence是null,则返回之前存贮的结果if (instance == null) {return result;}//如果成功则返回这个对象return instance;} catch (InstantiationException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);} catch (InvocationTargetException e) {throw new RuntimeException(e);} catch (NoSuchMethodException e) {throw new RuntimeException(e);} catch (Exception e) {throw new RuntimeException(e);}}//返回容器中的对象public Object getBean(String name) {//如果是单例的,则从单例池中获取,如果是多例的则直接创建一个实例返回,名字没在bean定义中则抛出异常if (beanDefinitionMap.containsKey(name)) {BeanDefinition beanDefinition = beanDefinitionMap.get(name);//判断是否是单例if ("singleton".equals(beanDefinition.getScope())) {//从单例池中获取对象return singletonObjects.get(name);} else {//直接创建对象(多例)return createBean(beanDefinition, name);}} else {//name不在bean定义中则抛出异常throw new NullPointerException("没有该bean");}}}
4.结果展示

image-20240222143316755

4.该阶段完成的任务

  • 实现初始化方法
    • 编写初始化接口,里面有一个default的初始化方法
    • 编写初始化实现类,重写这个初始化方法
    • 在容器的依赖注入后添加初始化逻辑,当这个对象的类型是初始化接口的子类型的时候,就将其转换成接口类型并且调用初始化方法
  • 后置处理器实现
    • 编写一个后置处理器接口,里面有两个方法一个在初始化前调用,一个在初始化后调用
    • 在组件文件夹下编写后置处理器实现类
    • 在容器中beanDefinitionScan方法的扫描组件时添加后置处理器逻辑,如果该组件实现了后置处理器接口,则转换成后置处理器类型,并且放到ArrayList中方便查找
    • 在容器中的createBean方法增加后置处理器逻辑,在初始化方法之前和之后遍历存储后置处理器的ArrayList并分别执行方法

阶段5—实现AOP机制&Spring底层机制总结

1.实现AOP机制

1.原理分析

image-20240222151512245

2.代码实现
1.文件目录

image-20240222164154334

2.编写接口SmartAnimalable.java
package com.sun.spring.component;/*** @author 孙显圣* @version 1.0*/
public interface SmartAnimalable {float getSum(float i, float j);float getSub(float i, float j);
}
2.编写实现类SmartDog.java
package com.sun.spring.component;import com.sun.spring.annotation.Component;
import com.sun.spring.processor.InitializingBean;/*** @author 孙显圣* @version 1.0*/
@Component(value = "smartDog")
public class SmartDog implements SmartAnimalable, InitializingBean {public float getSum(float i, float j) {float res = i + j;System.out.println("SmartDog-getSum=" + res);return res;}public float getSub(float i, float j) {float res = i - j;System.out.println("SmartDog-getSub=" + res);return res;}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("smartDog 被初始化!");}
}
3.编写切面类SmartAnimalAspect.java
package com.sun.spring.component;/*** @author 孙显圣* @version 1.0*/
public class SmartAnimalAspect {public static void showBeginLog() {System.out.println("前置通知");}public static void showSuccessLog() {System.out.println("返回通知");}
}
4.修改SunBeanPostProcessor.java对SmartDog的getSum方法进行动态代理
package com.sun.spring.component;import com.sun.spring.annotation.Component;
import com.sun.spring.processor.BeanPostProcessor;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** 后置处理器,实现了自定义的后置处理器的接口** @author 孙显圣* @version 1.0*/
//反射创建bean对象
@Component
public class SunBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) {System.out.println("\n后置处理器postProcessBeforeInitialization被调用 bean类型=" + bean.getClass() + "bean名字=" + beanName);if (bean instanceof Car) {System.out.println("后置处理器发现这个类型是Car类型");}return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) {System.out.println("后置处理器postProcessAfterInitialization被调用 bean类型=" + bean.getClass() + "bean名字=" + beanName);//实现AOP,返回代理对象if ("smartDog".equals(beanName)) {//使用jdk的动态代理返回代理对象/*** ClassLoader loader,* Class<?>[] interfaces,* InvocationHandler h*///1.要代理的对象的类加载器ClassLoader classLoader = bean.getClass().getClassLoader();//2.要代理对象的接口信息Class<?>[] interfaces = bean.getClass().getInterfaces();//3.代理对象执行的方法,在代理对象执行所有的方法时都会调用InvocationHandler invocationHandler = new InvocationHandler() {/*** 代理对象执行的方法,在代理对象执行所有的方法时都会调用** @param proxy 动态代理对象** @param method 动态代理对象调用的方法** @param args 方法的参数** @return 返回method返回的结果* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//判断是不是getSum方法,如果是,则进行AOP处理Object result = null;if ("getSum".equals(method.getName())) {//前置通知SmartAnimalAspect.showBeginLog();result = method.invoke(bean, args);//返回通知SmartAnimalAspect.showSuccessLog();} else {//如果不是getSum方法则正常执行原来的方法result = method.invoke(bean, args);}return result;}};//返回针对接口的代理对象(可以使用接口类型接收)return Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);}return bean;}
}
5.启动类
package com.sun.spring;import com.sun.spring.component.MonsterService;
import com.sun.spring.component.SmartAnimalable;
import com.sun.spring.ioc.SunSpringApplicationContext;
import com.sun.spring.ioc.SunSpringConfig;/*** @author 孙显圣* @version 1.0*/
public class AppMain {public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {SunSpringApplicationContext ioc = new SunSpringApplicationContext(SunSpringConfig.class);//单例对象Object bean01 = ioc.getBean("monsterDao");//测试依赖注入MonsterService bean = (MonsterService) ioc.getBean("monsterService");System.out.println("==================================测试依赖注入调用方法==================================");bean.m1();//演示AOPSystem.out.println("==================================测试AOP==================================");SmartAnimalable proxy = (SmartAnimalable) ioc.getBean("smartDog");proxy.getSub(4,1);proxy.getSum(2,4);}
}
6.结果展示

image-20240222164835898

3.该阶段完成的任务
  • 编写接口,编写实现类并将实例交给Spring容器管理,编写切面类
  • 后置处理器中进行动态代理操作,这里是对SmartDog类型的getSum方法进行动态代理
    • 首先判断beanName是不是smartDog
    • 如果是则进行动态代理,invoke方法中先判断当前执行的方法是不是getSum
    • 如果是getSum则插入前置通知和返回通知,如果不是则正常执行这个方法

2.Spring底层机制总结

1.bean的生命周期
  • 反射创建bean对象
  • 依赖注入
  • 初始化bean
  • getBean
  • 销毁bean
2.Spring容器的执行流程
  • 获取容器对象
  • 读取配置文件,得到要扫描的包
  • 扫描包下的组件,将bean定义信息放到Map中
  • 如果是单例
    • 反射创建bean对象,放到单例池中
    • 依赖注入(调用getBean)
    • 初始化bean
      • 初始化容器前调用后置处理器的before方法
      • 初始化容器之后调用后置处理器的after方法
  • 如果是多例
    • 在这个阶段什么都不做
  • getBean阶段
    • 如果是单例
      • 从单例池中获取bean对象
    • 如果是多例
      • 反射创建bean对象
      • 依赖注入(调用getBean)
      • 初始化bean
        • 初始化容器前调用后置处理器的before方法
        • 初始化容器之后调用后置处理器的after方法
      • 得到bean对象
  • 销毁bean
3.动态代理和AOP的区别
  • 动态代理:针对的是某个对象所有方法
  • AOP:针对的是某些类型所有对象具体方法
4.关于后置处理器 + 动态代理的理解
  • 后置处理器作用于Spring容器中所有类型,所有对象的初始化方法
  • getBean得到的就是后置处理器返回的bean
  • 当进入到后置处理器的时候
    • 获取切面类的所有信息
    • 将切入表达式与当前bean对象进行对比,只要类型匹配就进行动态代理
    • 使用动态代理进一步筛选要代理的方法,并根据不同的通知执行不同的操作,返回动态代理对象
    • 如果是不需要代理的方法,就不进行额外操作
5.AOP的使用方式
  • 编写接口,接口对象(注解)(用于展示AOP的效果,因为没有对象)
  • 编写切面类(注解),切面对象(注解)
  • 通知 + 切点
  • 配置beans.xnl
    • 普通注解扫描
    • 开启AOP注解
  • 具体使用
    • 获取针对接口类型的代理对象(通过id或者接口类型获取)
    • 使用代理对象调用接口的方法
  • 四种通知
    • 前置通知
    • 返回通知
    • 异常通知
    • 后置通知

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

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

相关文章

在电脑上安装Linux?有手就行!

文章目录 安装虚拟机管理软件VM下载centos镜像文件开始安装创建虚拟机打开虚拟机&#xff0c;开始安装程序安装启动程序测试光盘选择语言进行安装前的配置安装 安装后操作 安装虚拟机管理软件VM 官方正版VMware下载&#xff08;16 pro&#xff09;&#xff1a;https://www.ali…

探索亚马逊云科技「生成式 AI 精英速成计划」

目录 前言「生成式 AI 精英速成计划」技术开发课程学习课程学习 总结 前言 亚马逊云科技&#xff08;Amazon Web Services&#xff0c;简称AWS&#xff09;作为全球领先的云计算服务提供商&#xff0c;一直以来在推动人工智能&#xff08;AI&#xff09;领域的发展中扮演着重要…

服务器 BMC(基板管理控制器,Baseboard Management Controller)认知

写在前面 工作中遇到&#xff0c;简单整理博文内容涉及 BMC 基本认知理解不足小伙伴帮忙指正 不必太纠结于当下&#xff0c;也不必太忧虑未来&#xff0c;当你经历过一些事情的时候&#xff0c;眼前的风景已经和从前不一样了。——村上春树 基板管理控制器&#xff08;BMC&…

rust 学习笔记(13-19)

13 迭代器与闭包 Rust 的设计灵感来源于很多现存的语言和技术。其中一个显著的影响就是 函数式编程&#xff08;functional programming&#xff09;。函数式编程风格通常包含将函数作为参数值或其他函数的返回值、将函数赋值给变量以供之后执行等等。 闭包&#xff08;Closu…

【学习】服务器解决:重新分配同样端口号后,连不上VScode

原来服务器分配的环境有问题&#xff0c;重新分配了一下。还是同样的端口号&#xff0c;Xshell和xftp能够连接上&#xff0c;但是VScode连接不上。 问题解决: 清除本地 SSH 缓存中与远程主机相关的条目可以通过编辑 known_hosts 文件来实现。这个文件包含了您曾经连接过的远程主…

API请求报错 Required request body is missing问题解决

背景 在进行调用的时候&#xff0c;加载方法&#xff0c;提示以下错误 错误信息如下&#xff1a; {"code": 10001,"msg": "Required request body is missing: XXX","data": null,"extra": null }Required request body…

2015NOIP普及组真题 3. 求和

线上OJ&#xff1a; 一本通&#xff1a;http://ybt.ssoier.cn:8088/problem_show.php?pid1971 核心思想&#xff1a; 本题的约束条件有两个&#xff1a; 条件1、colorx colorz 条件2、x、y、z的坐标满足 y − x z − y&#xff08;即 y 在 x 和 z 的中心位置&#xff09; …

ESP32学习第一天-ESP32点亮LED,按键控制LED状态,LED流水灯

第一天使用到的函数: 函数第一个参数设置哪一个引脚&#xff0c;第二个参数设置引脚模式。 pinMode(led_pin,OUTPUT); //设置引脚模式 函数的第一个参数设置哪一个引脚&#xff0c;第二个参数设置是高电平还是低电平。 digitalWrite(led_pin,HIGH);//将引脚电平拉高 #incl…

spring一二三级缓存和@Lazy解决循环依赖流程

简单对象指的是 实例化后还没有属性注入的时候的早期bean lambda表达式用于判断a是否存在aop代理 假如a和b循环依赖&#xff0c;a实例化时&#xff0c; bean创建流程如下&#xff1a; 0&#xff0c;创建一个set记录当前正在实例化的bean&#xff0c; 1.实例化a的简单对象时…

电脑问题快速判断

电脑开机没有任何反应 检查电源 检查电源是否有问题或损坏&#xff0c;可以短接方法检测 板电源卡口对自己接第四或第五根线&#xff0c;若风扇匀速转动&#xff0c;电源无问题&#xff0c;若不转动或转一下停一下&#xff0c;电源有问题 检查内部连线 确保主板上的线插的…

linux下编译c++程序报错“undefined reference to `std::allocator<char>::allocator()‘”

问题 linux下编译c程序报错“undefined reference to std::allocator::allocator()”。 原因 找不到c标准库文件。 解决办法 开始尝试给gcc指令添加-L和-l选项指定库路径和库文件名&#xff0c;但是一直不成功&#xff0c;后来把gcc改为g就可以了。

Google Play App Store API 获取谷歌安卓应用商城app数据接口

iDataRiver平台 https://www.idatariver.com/zh-cn/ 提供开箱即用的谷歌安卓应用商城google play app store数据采集API&#xff0c;供用户按需调用。 接口使用详情请参考Google Play App Store接口文档 接口列表 1. 获取指定app的基础信息 参数类型是否必填默认值示例值描…

重磅发布 | 《网络安全专用产品指南》(第一版)

2017年6月1日&#xff0c;《中华人民共和国网络安全法》正式实施&#xff0c;明确规定“网络关键设备和网络安全专用产品应当按照相关国家标准的强制性要求&#xff0c;由具备资格的机构安全认证合格或者安全检测符合要求后&#xff0c;方可销售或者提供。国家网信部门会同国务…

【python】python学生信息管理系统 ——数据库版(源码)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

js进行数据移除性能比较(splice,map)

当使用 splice() 方法处理大量数据时&#xff0c;确实会遇到性能问题&#xff0c;因为它涉及到移动数组中的元素&#xff0c;导致操作的时间复杂度为 O(n)。对于大量数据&#xff0c;频繁的插入和删除可能会导致性能下降。 1、设置数组数据为10000&#xff0c;使用splice移除数…

MySQL从入门到高级 --- 2.DDL基本操作

文章目录 第二章&#xff1a;2.基本操作 - DDL2.1 数据库的常用操作创建数据库选择要操作的数据库删除数据库修改数据库编码 2.2 表结构的常用操作创建表格式查看当前数据库的所有表名称查看指定某个表的创建语句查看表结构删除表 2.3 修改表结构添加列修改列名和类型删除列修改…

水平越权,垂直越权

水平越权和垂直越权 水平越权 首先自己创建一个账号 然后在自己的修改密码&#xff0c;抓包&#xff0c;修改用户名等 但一般都会固定&#xff0c;它会固定当前用户名 垂直越权 不用登录就可以删除 当我们复制管理员的删除地址&#xff0c;然后访问它 它会跳出登录地址&#…

【六十四】【算法分析与设计】699. 掉落的方块,离散化操作,线段树优化,区间查询sum+区间更新update

699. 掉落的方块 在二维平面上的 x 轴上&#xff0c;放置着一些方块。 给你一个二维整数数组 positions &#xff0c;其中 positions[i] [left(i), sideLength(i)] 表示&#xff1a;第 i 个方块边长为 sideLength(i) &#xff0c;其左侧边与 x 轴上坐标点 left(i) 对齐。 每个…

[Meachines][Easy]Bizness

Main $ nmap -p- 10.10.11.252 --min-rate 1000 $ dirsearch -u https://bizness.htb/ $ whatweb https://bizness.htb/control/login 存在一个未授权的RCE $ git clone https://github.com/jakabakos/Apache-OFBiz-Authentication-Bypass.git $ cd Apache-OFBiz-Authenticat…

网络爬虫快速入门及爬取百度搜索结果(附源码)

前言 爬虫的基本结构及工作流程 1. 确定目标 首先&#xff0c;确定你想要爬取的目标&#xff0c;包括目标网站或网页、需要提取的数据类型&#xff08;如文本、图片、视频等&#xff09;以及爬取的深度&#xff08;单页、整个网站等&#xff09;。 2. 获取网页内容 使用HT…