手写Spring:第16章-给代理对象的属性设置值

news2025/1/19 11:14:44

文章目录

  • 一、目标:给代理对象的属性设置值
  • 二、设计:给代理对象的属性设置值
  • 三、实现:给代理对象的属性设置值
    • 3.1 工程结构
    • 3.2 在Bean生命周期中创建代理对象类图
    • 3.3 判断CGLIB对象
    • 3.4 迁移创建AOP代理方法
      • 3.4.1 实例化感知对象处理
      • 3.4.2 扫描自定义注解类
      • 3.4.3 默认自动代理创建者
    • 3.5 在Bean生命周期中初始化执行
  • 四、测试:给代理对象的属性设置值
    • 4.1 添加测试配置
      • 4.1.1 用户服务层实现类
      • 4.1.2 用户前置处理
      • 4.1.3 Spring属性配置文件
    • 4.2 单元测试
  • 五、总结:给代理对象的属性设置值

一、目标:给代理对象的属性设置值

💡 如何给代理对象中的属性填充相应的值?

  • 因为在之前把 AOP 动态代理,融入到 Bean 的生命周期时,创建代理对象是在整个创建 Bean 对象之前,也就是这个代理对象的创建并不是在 Bean 生命周期中。
  • 所以我们要把代理对象的创建融入到 Bean 的生命周期中,也就是需要把创建代理对象的逻辑迁移到 Bean 对象执行初始化方法之后,再执行代理对象的创建。

二、设计:给代理对象的属性设置值

💡 设计:把创建代理对象的逻辑迁移到对象执行初始化之后。

  • 创建代理对象:DefaultAdvisorAutoProxyCreator 实现的 InstantiationAwareBeanPostProcessor 接口。
  • 那么原本在 Before 中的操作,则需要放到 After 中处理

在这里插入图片描述

  • 在创建 Bean 对象 createBean 的生命周期中,有一个阶段是在 Bean 对象属性填充完成以后,执行 Bean 的初始化方法和 BeanPostProcessor 的前置和后置处理。
    • 例如:感知 Aware 对象、处理 init-method 方法等。
  • 那么在这个阶段的 BeanPostProcessor After 就可以用于创建处理对象操作。
  • DefaultAdvisorAutoProxyCreator 用于创建代理对象的操作中,需要把创建操作从 postProcessBeforeInstantiation 方法中迁移到 postProcessAfterInitialization,这样才能满足 Bean 属性填充后的创建操作。

三、实现:给代理对象的属性设置值

3.1 工程结构

spring-step-15
|-src
  |-main
  | |-java
  |   |-com.lino.springframework
  |     |-aop
  |     | |-aspectj
  |     | | |-AspectJExpressionPointcut.java
  |     | | |-AspectJExpressionPointcutAdvisor.java
  |     | |-framework
  |     | | |-adapter
  |     | | | |-MethodBeforeAdviceInterceptor.java
  |     | | |-autoproxy
  |     | | | |-DefaultAdvisorAutoProxyCreator.java
  |     | | |-AopProxy.java
  |     | | |-Cglib2AopProxy.java
  |     | | |-JdkDynamicAopProxy.java
  |     | | |-ProxyFactory.java
  |     | | |-ReflectiveMethodInvocation.java
  |     | |-AdvisedSupport.java
  |     | |-Advisor.java
  |     | |-BeforeAdvice.java
  |     | |-ClassFilter.java
  |     | |-MethodBeforeAdvice.java
  |     | |-MethodMatcher.java
  |     | |-Pointcut.java
  |     | |-PointcutAdvisor.java
  |     | |-TargetSource.java
  |     |-beans
  |     | |-factory
  |     | | |-annotation
  |     | | | |-Autowired.java
  |     | | | |-AutowiredAnnotationBeanPostProcessor.java
  |     | | | |-Qualifier.java
  |     | | | |-Value.java
  |     | | |-config
  |     | | | |-AutowireCapableBeanFactory.java
  |     | | | |-BeanDefinition.java
  |     | | | |-BeanFactoryPostProcessor.java
  |     | | | |-BeanPostProcessor.java
  |     | | | |-BeanReference.java
  |     | | | |-ConfigurableBeanFactory.java
  |     | | | |-InstantiationAwareBeanPostProcessor.java
  |     | | | |-SingletonBeanRegistry.java
  |     | | |-support
  |     | | | |-AbstractAutowireCapableBeanFactory.java
  |     | | | |-AbstractBeabDefinitionReader.java
  |     | | | |-AbstractBeabFactory.java
  |     | | | |-BeabDefinitionReader.java
  |     | | | |-BeanDefinitionRegistry.java
  |     | | | |-CglibSubclassingInstantiationStrategy.java
  |     | | | |-DefaultListableBeanFactory.java
  |     | | | |-DefaultSingletonBeanRegistry.java
  |     | | | |-DisposableBeanAdapter.java
  |     | | | |-FactoryBeanRegistrySupport.java
  |     | | | |-InstantiationStrategy.java
  |     | | | |-SimpleInstantiationStrategy.java
  |     | | |-xml
  |     | | | |-XmlBeanDefinitionReader.java
  |     | | |-Aware.java
  |     | | |-BeanClassLoaderAware.java
  |     | | |-BeanFactory.java
  |     | | |-BeanFactoryAware.java
  |     | | |-BeanNameAware.java
  |     | | |-ConfigurableListableBeanFactory.java
  |     | | |-DisposableBean.java
  |     | | |-FactoryBean.java
  |     | | |-HierarcgicalBeanFactory.java
  |     | | |-InitializingBean.java
  |     | | |-ListableBeanFactory.java
  |     | | |-PropertyPlaceholderConfigurer.java
  |     | |-BeansException.java
  |     | |-PropertyValue.java
  |     | |-PropertyValues.java
  |     |-context
  |     | |-annotation
  |     | | |-ClassPathBeanDefinitionScanner.java
  |     | | |-ClassPathScanningCandidateComponentProvider.java
  |     | | |-Scope.java
  |     | |-event
  |     | | |-AbstractApplicationEventMulticaster.java
  |     | | |-ApplicationContextEvent.java
  |     | | |-ApplicationEventMulticaster.java
  |     | | |-ContextclosedEvent.java
  |     | | |-ContextRefreshedEvent.java
  |     | | |-SimpleApplicationEventMulticaster.java
  |     | |-support
  |     | | |-AbstractApplicationContext.java
  |     | | |-AbstractRefreshableApplicationContext.java
  |     | | |-AbstractXmlApplicationContext.java
  |     | | |-ApplicationContextAwareProcessor.java
  |     | | |-ClassPathXmlApplicationContext.java
  |     | |-ApplicationContext.java
  |     | |-ApplicationContextAware.java
  |     | |-ApplicationEvent.java
  |     | |-ApplicationEventPublisher.java
  |     | |-ApplicationListener.java
  |     | |-ConfigurableApplicationContext.java
  |     |-core.io
  |     | |-ClassPathResource.java
  |     | |-DefaultResourceLoader.java
  |     | |-FileSystemResource.java
  |     | |-Resource.java
  |     | |-ResourceLoader.java
  |     | |-UrlResource.java
  |     |-stereotype
  |     | |-Component.java
  |     |-util
  |     | |-ClassUtils.java
  |     | |-StringValueResolver.java
  |-test
    |-java
      |-com.lino.springframework.test
                |-bean
                | |-IUserService.java
                | |-UserService.java
        | |-UserServiceBeforeAdvice.java
                |-ApiTest.java
    |-resources
      |-spring.xml
      |-token.properties

3.2 在Bean生命周期中创建代理对象类图

在这里插入图片描述

  • 本节完成关于代理对象中属性的填充问题,但实际解决的思路是处理在 Bean 生命周期中合适的位置(初始化 initializeBean)中处理代理类的创建。
  • 主要包括:
    • DefaultAdvisorAutoProxyCreator 类创建代理对象的操作放置在 postProcessAfterInitialization 方法中。
    • AbstractAutowireCapableBeanFactory 完成初始化方法的调用操作。
  • 注意:在目前的 Spring 框架中,AbstractAutowireCapableBeanFactory 类里使用的是 CglibSubclassingInstantiationStrategy 创建对象,所有有需要判断对象获取接口的方法中,也都需要判断是否为 CGLIB 创建,否则是不能正确获取到接口的。
    • 如:ClassUtils.isCglibProxyClass(clazz) ? clazz.getSuperclass() : clazz

3.3 判断CGLIB对象

TargetSource.java

package com.lino.springframework.aop;

import com.lino.springframework.util.ClassUtils;

/**
 * @description: 被代理的目标对象
 */
public class TargetSource {

    private final Object target;

    public TargetSource(Object target) {
        this.target = target;
    }

    /**
     * 获取目标对象列表
     *
     * @return 目标对象列表
     */
    public Class<?>[] getTargetClass() {
        Class<?> clazz = this.target.getClass();
        clazz = ClassUtils.isCglibProxyClass(clazz) ? clazz.getSuperclass() : clazz;
        return clazz.getInterfaces();
    }

    /**
     * 获取目标对象
     *
     * @return 目标对象
     */
    public Object getTarget() {
        return this.target;
    }
}
  • TargetSource#getTargetClass 是用于获取 target 对象的接口信息的,那么这个 target 可以是 JDK 代理创建,也可能是 CGLIB 创建。
  • 为了保证都能正确的获取到结果,这里需要增加判断 ClassUtils.isCglibProxyClass(clazz)

3.4 迁移创建AOP代理方法

3.4.1 实例化感知对象处理

InstantiationAwareBeanPostProcessor.java

package com.lino.springframework.beans.factory.config;

import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValues;

/**
 * @description: 实例化感知对象处理
 */
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {

    /**
     * 在 Bean 对象执行初始化方法之前,执行此方法
     *
     * @param beanClass 对象类
     * @param beanName  对象名
     * @return 新对象
     * @throws BeansException 异常
     */
    Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;

    /**
     * 在 Bean 对象执行初始化方法之后,执行此方法
     *
     * @param bean     对象
     * @param beanName 对象名称
     * @return 是否执行
     * @throws BeansException 异常
     */
    boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;

    /**
     * 在 Bean 对象实例化完成后,设置属性操作之前执行此方法
     *
     * @param pvs      属性值集合
     * @param bean     对象
     * @param beanName 对象名称
     * @return 属性值集合
     * @throws BeansException 异常
     */
    PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) throws BeansException;
}

3.4.2 扫描自定义注解类

AutowiredAnnotationBeanPostProcessor.java

package com.lino.springframework.beans.factory.annotation;

import cn.hutool.core.bean.BeanUtil;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValues;
import com.lino.springframework.beans.factory.BeanFactory;
import com.lino.springframework.beans.factory.BeanFactoryAware;
import com.lino.springframework.beans.factory.config.ConfigurableBeanFactory;
import com.lino.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import com.lino.springframework.util.ClassUtils;
import java.lang.reflect.Field;

/**
 * @description: 扫描自定义注解类
 */
public class AutowiredAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {

    ...

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return null;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return null;
    }

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        return null;
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        return true;
    }
}

3.4.3 默认自动代理创建者

DefaultAdvisorAutoProxyCreator.java

package com.lino.springframework.aop.framework.autoproxy;

import com.lino.springframework.aop.*;
import com.lino.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
import com.lino.springframework.aop.framework.ProxyFactory;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValues;
import com.lino.springframework.beans.factory.BeanFactory;
import com.lino.springframework.beans.factory.BeanFactoryAware;
import com.lino.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import com.lino.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import java.util.Collection;

/**
 * @description: 默认自动代理创建者
 */
public class DefaultAdvisorAutoProxyCreator implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {

    private DefaultListableBeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = (DefaultListableBeanFactory) beanFactory;
    }

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        return null;
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        return true;
    }

    private boolean isInfrastructureClass(Class<?> beanClass) {
        return Advice.class.isAssignableFrom(beanClass) || Pointcut.class.isAssignableFrom(beanClass) || Advisor.class.isAssignableFrom(beanClass);
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (isInfrastructureClass(bean.getClass())) {
            return bean;
        }

        Collection<AspectJExpressionPointcutAdvisor> advisors = beanFactory.getBeansOfType(AspectJExpressionPointcutAdvisor.class).values();

        for (AspectJExpressionPointcutAdvisor advisor : advisors) {
            ClassFilter classFilter = advisor.getPointcut().getClassFilter();
            // 过滤匹配类
            if (!classFilter.matches(bean.getClass())) {
                continue;
            }
            AdvisedSupport advisedSupport = new AdvisedSupport();

            TargetSource targetSource = new TargetSource(bean);
            advisedSupport.setTargetSource(targetSource);
            advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
            advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher());
            advisedSupport.setProxyTargetClass(false);

            // 返回代理对象
            return new ProxyFactory(advisedSupport).getProxy();
        }
        return bean;
    }

    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        return pvs;
    }
}
  • 关于 DefaultAdvisorAutoProxyCreator 类的操作主要就是把创建 AOP 代理的操作从 postProcessBeforeInstantiation 移动到 postProcessAfterInitialization 中。
  • 通过设置一些 AOP 的必备参数后,返回代理对象 new ProxyFactory(advisedSupport).getProxy()
    • 这个代理对象中就包括间接调用 TargetSource#getTargetClass 的获取。

3.5 在Bean生命周期中初始化执行

AbstractAutowireCapableBeanFactory.java

package com.lino.springframework.beans.factory.support;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValue;
import com.lino.springframework.beans.PropertyValues;
import com.lino.springframework.beans.factory.*;
import com.lino.springframework.beans.factory.config.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * @description: 实现默认bean创建的抽象bean工厂超类
 * @author: lingjian
 * @createDate: 2022/11/22 14:39
 */
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {

    private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();

    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) {
        Object bean = null;
        try {
            // 判断是否返回代理 Bean 对象
            bean = resolveBeforeInstantiation(beanName, beanDefinition);
            if (null != bean) {
                return bean;
            }
            // 实例化Bean
            bean = createBeanInstance(beanDefinition, beanName, args);
            // 实例化后判断
            boolean continueWithPropertyPopulation = applyBeanPostProcessorsAfterInstantiation(beanName, bean);
            if (!continueWithPropertyPopulation) {
                return bean;
            }
            // 在设置Bean属性之前,允许 BeanPostProcessor修改属性值
            applyBeanPostProcessorsBeforeApplyingPropertyValues(beanName, bean, beanDefinition);
            // 给bean填充属性
            applyPropertyValues(beanName, bean, beanDefinition);
            // 执行 Bean 的初始化方法和 BeanPostProcessor 的前置和后置处理方法
            bean = initializeBean(beanName, bean, beanDefinition);
        } catch (Exception e) {
            throw new BeansException("Instantiation of bean failed", e);
        }

        // 注册实现 DisposableBean 接口的 Bean 对象
        registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);

        // 判断 SCOPE_SINGLETON、SCOPE_PROTOTYPE
        if (beanDefinition.isSingleton()) {
            registerSingletonBean(beanName, bean);
        }
        return bean;
    }

    /**
     * Bean 实例化后对于返回 false 的对象,不再执行后续设置 Bean 对象属性的操作
     *
     * @param beanName 对象名称
     * @param bean     对象
     * @return 布尔值
     */
    private boolean applyBeanPostProcessorsAfterInstantiation(String beanName, Object bean) {
        boolean continueWithPropertyPopulation = true;
        for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) {
            if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor instantiationAwareBeanPostProcessor = (InstantiationAwareBeanPostProcessor) beanPostProcessor;
                if (!instantiationAwareBeanPostProcessor.postProcessAfterInstantiation(bean, beanName)) {
                    continueWithPropertyPopulation = false;
                    break;
                }
            }
        }
        return continueWithPropertyPopulation;
    }

    ...

    private Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
        for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) {
            if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
                Object result = ((InstantiationAwareBeanPostProcessor) beanPostProcessor).postProcessBeforeInstantiation(beanClass, beanName);
                if (null != result) {
                    return result;
                }
            }
        }
        return null;
    }

    ...
}
  • AbstractAutowireCapableBeanFactory#createBean 方法中,关注点在于 initializeBean -> applyBeanPostProcessorsAfterInitialization 这块逻辑的调用,最终完成 AOP 代理对象的创建操作。

四、测试:给代理对象的属性设置值

4.1 添加测试配置

4.1.1 用户服务层实现类

UserService.java

package com.lino.springframework.test.bean;

import com.lino.springframework.beans.factory.annotation.Autowired;
import com.lino.springframework.beans.factory.annotation.Value;
import com.lino.springframework.stereotype.Component;
import java.util.Random;

/**
 * @description: 用户接口实现类
 */
public class UserService implements IUserService {

    private String token;

    @Override
    public String queryUserInfo() {
        try {
            Thread.sleep(new Random(1).nextInt(100));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "张三,10001,杭州," + token;
    }

    @Override
    public String register(String userName) {
        try {
            Thread.sleep(new Random(1).nextInt(100));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "注册用户:" + userName + " success!";
    }

    @Override
    public String toString() {
        return "UserService#token = {" + token + "}";
    }

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }
}

4.1.2 用户前置处理

UserServiceBeforeAdvice.java

package com.lino.springframework.test.bean;

import com.lino.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;

/**
 * @description: 用户前置处理
 */
public class UserServiceBeforeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("拦截方法:" + method.getName());
    }
}

4.1.3 Spring属性配置文件

spring.xml

<?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 id="userService" class="com.lino.springframework.test.bean.UserService">
        <property name="token" value="RejDlI78hu223Opo983Ds"/>
    </bean>

    <bean class="com.lino.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

    <bean id="beforeAdvice" class="com.lino.springframework.test.bean.UserServiceBeforeAdvice"/>

    <bean id="methodInterceptor" class="com.lino.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor">
        <property name="advice" ref="beforeAdvice"/>
    </bean>

    <bean id="pointcutAdvisor" class="com.lino.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">
        <property name="expression" value="execution(* com.lino.springframework.test.bean.IUserService.*(..))"/>
        <property name="advice" ref="methodInterceptor"/>
    </bean>

</beans>

4.2 单元测试

ApiTest.java

@Test
public void test_autoProxy() {
    ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
    IUserService userService = applicationContext.getBean("userService", IUserService.class);
    System.out.println("测试结果:" + userService.queryUserInfo());
}

测试结果

拦截方法:queryUserInfo
测试结果:张三,10001,杭州,RejDlI78hu223Opo983Ds

在这里插入图片描述

  • 测试结果看,通过对 Bean 生命周期的调整,在创建 AOP 代理对象就可以把代理对象的属性信息填充进去了。

五、总结:给代理对象的属性设置值

  • 核心内容主要是完善 Bean 的生命周期,在创建类的操作中完成代理对象的创建。
    • 通过这样的方式就可以让代理对象中的属性也可以随着创建过程被填充进行。
  • 除核心功能的实现外,也要关注到对象的初始化操作:CglibSubclassingInstantiationStrategySimpleInstantiationStrategy
    • 这两种方式中 CGLIB 创建对象,会影响到很多地方用于接口获取的操作。因为 CGLIB 创建对象走的是 ASM 字节码生成的操作,所以和普通的 JDK 代理生成对象是不一样,需要注意。

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

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

相关文章

自动化测试:selenium(完结篇)

一、元素操作方法 方法&#xff1a; 1、.send_keys() # 输入方法 2、.click() # 点击方法 3、.clear() # 清空方法注意&#xff1a;在输入方法之前一定要清空操作&#xff01;&#xff01; # 导包 from time import sleep from selenium import webdriver# 实例化浏览器 d…

教你如何在三秒内,将PPT转换成翻页的电子书

​大家好&#xff01;今天教大家一个非常实用的技巧 瞬间将你的PPT变身为炫酷的翻页电子书&#xff0c;这个方法非常简单&#xff0c;只需要几个操作步骤就能完成&#xff0c;让我们一起来看看吧&#xff01; 在转换之前肯定是需要一款工具的&#xff0c;可以试试FLBOOK在线制…

论文笔记:Reinforcing Local Structure Perception for Monocular Depth Estimation

提出问题 混合数据集中深度范围的变化会导致网络的不稳定。虽然已经引入了一些仿射不变的损失函数&#xff0c;但现有的方法可能会导致次优的几何结构&#xff0c;如模糊的边界和细节。 思路 我们提出了一种新的像素级监督损失&#xff0c;称为 the windowed correlation re…

两个有序链表序列的交集

已知两个非降序链表序列S1与S2&#xff0c;设计函数构造出S1与S2的交集新链表S3。 输入格式: 输入分两行&#xff0c;分别在每行给出由若干个正整数构成的非降序序列&#xff0c;用−1表示序列的结尾&#xff08;−1不属于这个序列&#xff09;。数字用空格间隔。 输出格式:…

气传导耳机排名前十名,推荐几款性能表现不错的气传导耳机

​蓝牙耳机大家都很熟悉&#xff0c;如果更了解一些的朋友&#xff0c;一定也知道气传导耳机。气传导耳机最大的好处在于不入耳佩戴更舒适&#xff0c;户外使用时还能听到周围环境音&#xff0c;不会屏蔽汽车鸣笛声&#xff0c;使用更加安全。但也还有很多小伙伴不知道气传导耳…

css flex:1;详解,配合demo效果解答

前言 给设置了display&#xff1a;flex的子组件设置了flex&#xff1a;1&#xff1b;就能让他填满整个容器&#xff0c;如果有多个就平均 flex&#xff1a;1&#xff1b;是另外三个样式属性的简写&#xff0c;等同 flex-grow: 0; flex-shrink: 1; flex-basis: auto;我们就针…

idea插件推荐——Bito提高编码效率

Bito是一款在IntelliJ IDEA编辑器中的插件&#xff0c;Bito插件是由ChatGPT团队开发的&#xff0c;它是ChatGPT团队为了提高开发效率而开发的一款工具。Bito插件的强大之处在于它可以帮助开发人员更快地提交代码&#xff0c;同时还提供了一些有用的功能&#xff0c;如自动补全提…

it设备综合监控系统

IT综合监控系统是一系列IT管理产品的总称&#xff0c;具有功能齐全、应用便捷、解决方案齐全的产品&#xff0c;可一站式服务满足消费者的各种IT管理需求。该产品涵盖网络管理、服务器管理、存储系统、安全管理等方面&#xff0c;可为企业提供对整个IT系统的全方位监控和管理。…

【UIPickerView案例06-省市选择界面数据展示02-省市显示到Label上 Objective-C语言】

一、接下来,我要把城市、省、显示到下面的Label上 1.但是呢,我们现在能拿到它的Label吗, 是不是也是一样的,拖线啊 切换到三视图、选择ViewController.m文件 在类扩展里面, 左边这个呢,按住Control键,拖进来, Name:provinceLbl, 右边这个呢,按住Control键,拖进来…

G1 收集器【JVM调优】

文章目录 1. 分区收集器2. G1 收集器 1. 分区收集器 ① G1&#xff1a;分区算法&#xff0c;物理上不分代&#xff0c;逻辑分代。每次只回收快满了的几个小区域&#xff0c;对于较大的 Eden 区&#xff0c;回收效率还不算很高&#xff1b; ② ZGC&#xff1a;分页算法&#xff…

JS 一维数组 和 二维数组之间的相互转换

JS 一维数组 和 二维数组之间的相互转换 二维数组转一维数组一、需求二、分析1. 方法一&#xff08;ES5&#xff09;2. 方法二&#xff08;ES6&#xff09;3. 方法三&#xff08;ES6&#xff09;3. 方法四&#xff08;ES5&#xff09;4. 特殊说明&#xff1a;flat()方法会移除数…

基于Java+SpringBoot+Vue前后端分离电商应用系统设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

streamlit执行报错WARNING,重新安装碰到问题如何解决

streamlit执行报错WARNING&#xff0c;重新安装碰到问题如何解决 如何解决1、卸载已经安装的程序2、再次安装程序3、出现如下yinstaller 警告问题&#xff1a;4、又出现“which is not on PATH”警告。5、解决方案 发现在安装的时候有很多WARNING出现&#xff0c;但是没有但回事…

C# OpenVino Yolov8 Detect 目标检测

效果 项目 代码 using OpenCvSharp; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using static System.Net.Mime.MediaT…

线性代数(六) 线性变换

前言 《线性空间》定义了空间&#xff0c;这章节来研究空间与空间的关联性 函数 函数是一个规则或映射&#xff0c;将一个集合中的每个元素&#xff08;称为自变量&#xff09;映射到另一个集合中的唯一元素&#xff08;称为因变量&#xff09;。 一般函数从 “A” 的每个元…

数字化时代,企业为什么要做数字化转型?

企业需要在数字时代进行数字化转型的原因是多方面的&#xff1a; 1.竞争优势&#xff1a;数字化转型使企业能够获得竞争优势。通过采用先进技术和数字化运营&#xff0c;他们可以提供创新的产品和服务&#xff0c;比竞争对手更快地满足客户不断变化的需求。 2.提高效率和降低…

删除单链表偶数节点

本题要求实现两个函数&#xff0c;分别将读入的数据存储为单链表、将链表中偶数值的结点删除。链表结点定义如下&#xff1a; struct ListNode { int data; struct ListNode *next; }; 函数接口定义&#xff1a; struct ListNode *createlist(); struct ListNode *deleteeven( …

cookies 设置过期时间

1.如何在浏览器中查看cookie过期时间 F12-Application-Cookies可以查看到网页所有设置cookie值&#xff0c; 如果设置了过期时间的cookie是可以看到过期时间的持久cookie&#xff08;persistent cookie&#xff09;&#xff0c; 没有设置过期时间的是会话cookie&#xff08;s…

Java版工程行业管理系统源码-专业的工程管理软件-提供一站式服

鸿鹄工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离构建工程项目管理系统 1. 项目背景 一、随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大。为了提高工程管理效率、减轻劳动强度、提高信息处理速度和准确性&#xff0c;公司对内部工程管…

Linux ubuntu磁盘扩容

1.服务器添加硬盘 2.linux系统重启 reboot 3.查看分区大小 lsblk 4.分配空间 growpart /dev/sda 3 lvextend -l 100%FREE /dev/mapper/ubuntu--vg-ubuntu--lv resize2fs /dev/mapper/ubuntu--vg-ubuntu--lv