一文简介Spring的IOC和AOP

news2024/12/23 9:40:31

1、IOC

概念:所谓控制反转,就是把原先我们代码里面需要实现的对象创建、依赖的代码,反转给容器来帮忙实现。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。

Spring 启动时读取应用程序提供的Bean配置信息,并在Spring容器中生成一份相应的Bean配置注册表,然后根据这张注册表实例化Bean,装配好Bean之间的依赖关系,为上层应用提供准备就绪的运行环境。

1.1 底层实现:

如果是xml文件,那么需要解析xml文件;如果是注解,需要通过反射获取注解,然后根据获取到的bean信息通过反射实例化bean,实例化之后将bean放到spring容器的bean缓存池中(hashMap),当要使用bean时,可以通过applicationContext获取bean(getBean)。

1.2 spring ioc autowired如何实现

@Autowired表示被修饰的类需要注入对象,spring会扫描所有被@Autowired标注的类,然后根据 类型type 在ioc容器中找到匹配的类注入

@Autowired VS @Resource

  • 提供方:@Autowired是由Spring提供;
    @Resource是由javax.annotation.Resource提供,即J2EE提供,需要JDK1.6及以上;
  • 注入方式:@Autowired只按照byType 注入;
    @Resource默认按byName自动注入,也提供按照byType 注入;

1.3 @component

普通pojo实例化到spring容器中,相当于配置文件中的<bean id="" class=""/>
虽然有了@Autowired,但是我们还是要写一堆bean的配置文件,相当麻烦,而@Component就是告诉spring,我是pojo类,把我注册到容器中吧,spring会自动提取相关信息。那么我们就不用写麻烦的xml配置文件了。

1.4 bean生命周期

  • 1.4.1.当调用者通过 getBean(beanName)向容器请求某一个 Bean 时,如果容器注册了org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor 接口,在实例化 Bean 之前,将调用接口的 postProcessBeforeInstantiation()方法;
  • 1.4.2.根据配置情况调用 Bean 构造函数或工厂方法实例化 Bean;
  • 1.4.3.如果容器注册了 InstantiationAwareBeanPostProcessor 接口,在实例化 Bean 之后,调用该接口的 postProcessAfterInstantiation()方法,可在这里对已经实例化的对象进行一些“梳妆打扮”;
  • 1.4.4.如果 Bean 配置了属性信息,容器在这一步着手将配置值设置到 Bean 对应的属性中,不过在设置每个属性之前将先调用InstantiationAwareBeanPostProcessor 接口的postProcessPropertyValues()方法;
  • 1.4.5.调用 Bean 的属性设置方法设置属性值;
  • 1.4.6.如果 Bean 实现了 org.springframework.beans.factory.BeanNameAware 接口,将调用setBeanName()接口方法,将配置文件中该 Bean 对应的名称设置到 Bean 中;
  • 1.4.7.如果 Bean 实现了 org.springframework.beans.factory.BeanFactoryAware 接口,将调用 setBeanFactory()接口方法,将 BeanFactory 容器实例设置到 Bean 中;
  • 1.4.8.如果 BeanFactory 装配了 org.springframework.beans.factory.config.BeanPostProcessor后处理器,将调用 BeanPostProcessor 的 Object postProcessBeforeInitialization(Object bean, String beanName)接口方法对 Bean 进行加工操作。其中入参 bean 是当前正在处理的 Bean,而 beanName 是当前 Bean 的配置名,返回的对象为加工处理后的 Bean。用户可以使用该方法对某些 Bean 进行特殊的处理,甚至改变 Bean 的行为, BeanPostProcessor 在 Spring 框架中占有重要的地位,为容器提供对 Bean 进行后续加工处理的切入点, Spring 容器所提供的各种“神奇功能”(如 AOP,动态代理等)都通过 BeanPostProcessor 实施;
  • 1.4.9.如果 Bean 实现了 InitializingBean 的接口,将调用接口的 afterPropertiesSet()方法;
  • 1.4.10.如果在<bean>通过 init-method 属性定义了初始化方法,将执行这个方法;
  • 1.4.11.BeanPostProcessor 后处理器定义了两个方法:其一是 postProcessBeforeInitialization() 在第 8 步调用;其二是 Object postProcessAfterInitialization(Object bean, String beanName)方法,这个方法在此时调用,容器再次获得对 Bean 进行加工处理的机会;
  • 1.4.12.如果在<bean>中指定 Bean 的作用范围为 scope=“prototype”,将 Bean 返回给调用者,调用者负责 Bean 后续生命的管理, Spring 不再管理这个 Bean 的生命周期。如果作用范围设置为 scope=“singleton”,则将 Bean 放入到 Spring IoC 容器的缓存池中,并将 Bean引用返回给调用者, Spring 继续对这些 Bean 进行后续的生命管理;
  • 1.4.13.对于 scope=“singleton”的 Bean,当容器关闭时,将触发 Spring 对 Bean 的后续生命周期的管理工作,首先如果 Bean 实现了 DisposableBean 接口,则将调用接口的afterPropertiesSet()方法,可以在此编写释放资源、记录日志等操作;
  • 1.4.14.对于 scope=“singleton”的 Bean,如果通过<bean>的 destroy-method 属性指定了 Bean 的销毁方法, Spring 将执行 Bean 的这个方法,完成 Bean 资源的释放等操作。

可以将这些方法大致划分为三类:

  • Bean 自身的方法:如调用 Bean 构造函数实例化 Bean,调用 Setter 设置 Bean 的属性值以及通过<bean>的 init-method 和 destroy-method 所指定的方法;

  • Bean 级生命周期接口方法:如 BeanNameAware、 BeanFactoryAware、 InitializingBean 和 DisposableBean,这些接口方法由 Bean 类直接实现;

  • 容器级生命周期接口方法:在上图中带“★” 的步骤是由 InstantiationAwareBean PostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为“ 后处理器” 。 后处理器接口一般不由 Bean 本身实现,它们独立于 Bean,实现类以容器附加装置的形式注册到 Spring 容器中并通过接口反射为 Spring 容器预先识别。当Spring 容器创建任何 Bean 的时候,这些后处理器都会发生作用,所以这些后处理器的影响是全局性的。当然,用户可以通过合理地编写后处理器,让其仅对感兴趣Bean 进行加工处理。

1.5 ApplicationContext 与 BeanFactory 区别

  • BeanFactory:是Spring里面最低层的接口,提供了最简单的容器的功能,只提供了实例化对象和拿对象的功能;

  • ApplicationContext:应用上下文,继承BeanFactory接口,它是Spring的一各更高级的容器,提供了更多的有用的功能;

    1. 国际化(MessageSource)
    2. 访问资源,如URL和文件(ResourceLoader)
    3. 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层
    4. 消息发送、响应机制(ApplicationEventPublisher)
    5. AOP(拦截器)

同时ApplicationContext会利用 Java 反射机制自动识别出配置文件中定义的 BeanPostProcessor、 InstantiationAwareBeanPostProcessor 和 BeanFactoryPostProcessor,并自动将它们注册到应用上下文中;
而BeanFactory 需要在代码中通过手工调用 addBeanPostProcessor()方法进行注册。
这也是为什么在应用开发时,我们普遍使用 ApplicationContext 而很少使用 BeanFactory 的原因之一。

1.6 Spring的bean的存储和管理机制

1、读取config.xml文件的bean标签放入数组,读取内容包含的id和class。
2、循环数组并根据class路径利用反射机制实例化Bean(实例化bean的过程就是上面),并放入Map(spring容器中的Bean缓存池)。
3、根据传入的BeanId获取Map中对应的bean实例。

1.7 Spring bean获取方式

从上面我们知道bean是存储在hashMap中的,其中key是beanId,vlaue是bean实例;

bean获取方式其实就是从应用上下文ApplicationContext的HashMap中根据key获取value的过程。
方式一:Object getBean(String name)
方式二:<T> T getBean(String name, Class<T> requiredType)
方式一和方式二的区别只是方式二自动做了类型转换。

1.8 ApplicationContext 获取方式

方式一:读取xml文件获取ApplicationContext对象
ApplicationContext ac = new FileSystemXmlApplicationContext("applicationContext.xml");

方式二:通过Spring提供的工具类获取ApplicationContext对象
ApplicationContext ac2 = WebApplicationContextUtils.getWebApplicationContext(ServletContext sc);

方式三:新建一个springUtils工具类,且实现ApplicationContextAware接口
上面bean实例化时的第五步,如果bean实现了ApplicationContextAware接口,它的setApplicationContext()方法将被调用,将应用上下文的引用传入到bean中;
通过这种方式可以把ApplicationContext传入到springUtils中,然后再springUtils中就可以使用applicationContext.getBean()来获取bean了

方式三是最推荐使用的

1.9 spring懒加载:

Spring默认会在容器初始化的过程中,解析xml,并将单例的bean创建并保存到map中,这样的机制在bean比较少时问题不大,但一旦bean非常多时,spring需要在启动的过程中花费大量的时间来创建bean 花费大量的空间存储bean,但这些bean可能很久都用不上,这种在启动时在时间和空间上的浪费显得非常的不值得。
所以Spring提供了懒加载机制。所谓的懒加载机制就是可以规定指定的bean不在启动时立即创建,而是在后续第一次用到时才创建,从而减轻在启动过程中对时间和内存的消耗。

1.10 spring bean 注册到 IOC容器的过程

  • 1、读取bean配置信息(通过xml中<bean> ,或者通过注解@Autowrite @Configuration),根据配置信息,在容器内部建立Bean定义注册表;
  • 2、根据bean注册表实例化bean;
  • 3、将bean实例化并将其放入hashMap;
  • 4、获取并使用bean

1.11 spring 循环依赖

spring 常用的注入方式有三种:构造方法注入,setter注入,基于注解的注入。

所谓循环依赖,当我们注入一个对象A时,需要注入对象A中标记了某些注解的属性,这些属性也就是对象A的依赖,把对象A中的依赖都初始化完成,对象A才算是创建成功。那么,如果对象A中有个属性是对象B,而且对象B中有个属性是对象A,那么对象A和对象B就算是循环依赖,如果不加处理,就会出现:创建对象A-->处理A的依赖B-->创建对象B-->处理B的对象A-->创建对象A,这样无限的循环下去,我们开发过程中有时也会遇到这种问题,那么spring框架本身是怎么解决这个问题的呢?

从上面bean的生命周期中,我们发现bean实例化(构造器)和setter设置属性并不是同时发生的,这个其实就是解决循环依赖的依据。

当我们初始化一个Bean时,先调用Bean的构造方法,这个对象就在内存中存在了(对象里面的依赖还没有被注入),然后把这个对象保存下来,当循环依赖产生时,直接拿到之前保存的对象,于是循环依赖就被终止了,依赖注入也就顺利完成了。

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//先存singletonObjects中获取bean,
        Object singletonObject = this.singletonObjects.get(beanName);
//如果bean不存在,并且bean正在创建中
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            synchronized (this.singletonObjects) {
//从earlySingletonObjects中获取
                singletonObject = this.earlySingletonObjects.get(beanName);
//如果earlySingletonObjects不存在(allowEarlyReference默认为true)
                if (singletonObject == null && allowEarlyReference) {
//获取singletonFactories
                    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
//从singletonFactories中获取bean
                        singletonObject = singletonFactory.getObject();
//添加到earlySingletonObjects
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
        return (singletonObject != NULL_OBJECT ? singletonObject : null);
    }
public boolean isSingletonCurrentlyInCreation(String beanName) {
        return this.singletonsCurrentlyInCreation.contains(beanName);
    }
  • singletonObjects:缓存key = beanName, value = bean;这里的bean是已经创建完成的,该bean经历过实例化->属性填充->初始化以及各类的后置处理。因此,一旦需要获取bean时,我们第一时间就会寻找一级缓存

  • earlySingletonObjects:缓存key = beanName, value = bean;这里跟一级缓存的区别在于,该缓存所获取到的bean是提前曝光出来的,是还没创建完成的。也就是说获取到的bean只能确保已经进行了实例化,但是属性填充跟初始化还没有做完(AOP情况后续分析),因此该bean还没创建完成,仅仅能作为指针提前曝光,被其他bean所引用

  • singletonFactories:该缓存key = beanName, value = beanFactory;在bean实例化完之后,属性填充以及初始化之前,如果允许提前曝光,spring会将实例化后的bean提前曝光,也就是把该bean转换成beanFactory并加入到三级缓存。在需要引用提前曝光对象时再通过singletonFactory.getObject()获取。

在整个getbean过程中,singletonObjects、earlySingletonObjects、singletonFactories中对象变化如下

  • 开始初始化对象A
    •  singletonFactories:
    • earlySingletonObjects:
    • singletonObjects:
  • 调用A的构造器实例化A,并把A放入singletonFactories
    • singletonFactories:A
    • earlySingletonObjects:
    • singletonObjects:
  • 开始注入A的依赖,发现A依赖对象B之后,初始化对象B(同样是调用B的构造器实例化B,并把B放入singletonFactories)
    • singletonFactories:A,B
    • earlySingletonObjects:
    • singletonObjects:
  • 开始注入B的依赖,发现B依赖对象A,开始初始化对象A,发现A在singletonFactories里有,则直接获取A,把A放入earlySingletonObjects(提前曝光),把A从singletonFactories删除
    • singletonFactories:B
    • earlySingletonObjects:A
    • singletonObjects:
  • 对象B的依赖注入完成之后,对象B创建完成,把B放入singletonObjects,并且把B从earlySingletonObjects和singletonFactories中删除
    • singletonFactories:
    • earlySingletonObjects:A
    • singletonObjects:B
  • 继续A的初始化,把对象B注入给A,继续注入A的其他依赖,直到A注入完成
    • singletonFactories:
    • earlySingletonObjects:A
    • singletonObjects:B
  • 对象A创建完成,把A放入singletonObjects,并把A从earlySingletonObjects和singletonFactories中删除
    • singletonFactories:
    • earlySingletonObjects:
    • singletonObjects:A,B
  • 循环依赖处理结束,A和B都初始化和注入完成
    •  singletonFactories:
    •  earlySingletonObjects:
    • singletonObjects:A,B

解决办法:如果项目中出现了循环依赖,则使用setter注入替代构造器注入。

2、AOP

2.1 概念

AOP的全称是Aspect Orient Programming,即面向切面编程,扩展功能不通过修改源代码实现。

2.2实现方式

  • 2.2.1 JDK 动态代理(必须有接口)
    通过java.lang.reflect.Proxy类实现。
    动态代理就是为了解决静态代理不灵活的缺陷而产生的。静态代理是固定的,一旦确定了代码,如果委托类新增一个方法,而这个方法又需要增强,那么就必须在代理类里重写一个带增强的方法。而动态代理可以灵活替换代理方法,动态就是体现在这里。同时,静态代理每个方法都需要单独写一个代理类,而动态代理一个接口只实现一个动态代理类即可。

设计模式中,有一种

  • 2.2.2 实现
Moveable move = (Moveable) Proxy.newProxyInstance(Car.class.getClassLoader(), Car.class.getInterfaces(), new LogHandler(new Car()));

使用JDK的动态代理去生成代理只需要一行代码,传入的参数中其实就俩,一是被代理类的类对象,二是自定义的增强处理代码。
从上面的例子中可以看出,动态代理除了接受Car类型的目标对象,还可以接受任何其他类型的对象;也不管目标对象实现的接口有多少方法,都可以被代理。


public class LogHandler implements InvocationHandler{ 
 
 private Object target; 
 
 public LogHandler(Object object){
   super();
   this.target = object;
 }
 
 //增强处理
 @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
   Object o = method.invoke(target,args);
   return o;
 }
}

  • 2.2.2 cglib 动态代理(不需要类继承任何接口,字节码技术)
public class Plane {

    public void fly(long ms) {
        System.out.println("plane is flying!");
        try {
            Thread.sleep(ms);
        } catch (Exception e) {

        }
    }
}

public class CglibProxy implements MethodInterceptor {
    private Object target;

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

    public Object getProxyInstance() {
        //1. 实例化工具类
        Enhancer en = new Enhancer();
        //2. 设置父类对象
        en.setSuperclass(this.target.getClass());
        //3. 设置回调函数
        en.setCallback(this);
        //4. 创建子类,也就是代理对象
        return en.create();
    }

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("before invoke ");
        long begin = System.currentTimeMillis();

        //执行目标对象的方法
        Object returnValue = method.invoke(target, objects);

        long end = System.currentTimeMillis();
        System.out.println("after invoke elpased " + (end - begin));

        return returnValue;
    }

}

public static void main() {
    CglibProxy cglibProxy = new CglibProxy(new Plane()); 
    Plane plane = (Plane) cglibProxy.getProxyInstance();             
    plane.fly(150);
}

2.4使用场景:

  • Logging 日 志
  • Authentication 权限
  • Transactions 事务
  • Context passing 内容传递
  • Error handling 错误处理
  • Lazy loading 懒加载
  • Debugging 调试
  • logging,tracing,profiling and monitoring 记录跟踪 优化 校准
  • Performance optimization 性能优化
  • Persistence 持久化
  • Resource pooling 资源池
  • Synchronization 同步
  • Caching 缓存 

2.5 在Spring的AOP编程中

如果加入容器的目标对象有实现接口,就使用JDK代理
如果目标对象没有实现接口,就使用Cglib代理。

3、反射:

反射是Java的特征之一,是一种间接操作目标对象的机制,核心是JVM在运行的时候才动态加载类,并且对于任意一个类,都能够知道这个类的所有属性和方法,调用方法/访问属性,不需要提前在编译期知道运行的对象是谁,他允许运行中的Java程序获取类的信息,并且可以操作类或对象内部属性

程序中对象的类型一般都是在编译期就确定下来的,而当我们的程序在运行时,可能需要动态的加载一些类,这些类因为之前用不到,所以没有加载到jvm,这时,使用Java反射机制可以在运行期动态的创建对象并调用其属性,它是在运行时根据需要才加载。

3.1 new和反射创建有什么区别

new:静态编译,在编译期就将模块编译进来,执行该字节码文件,所有的模块都被加载;
反射:动态编译,编译期没有加载,等到模块被调用时才加载;

3.2 反射的作用

  • 在运行时判断任意一个对象所属的类;
  • 在运行时构造任意一个类的对象;
  • 在运行时判断任意一个类所具有的成员变量和方法;
  • 在运行时调用任意一个对象的方法;

3.3 反射的实现

要使用一个类,就要先把它加载到虚拟机中,生成一个Class对象。这个class对象就保存了这个类的一切信息。

反射机制的实现,就是获取这个Class对象,通过Class对象去访问类、对象的元数据以及运行时的数据。

//通过反射机制创建class对象
class1 = Class.forName(className);
//在运行时,通过创建的class对象,获取自己的父类信息
Class<?> parentClass = class1.getSuperclass();
//通过反射机制创建一个类的对象
Classname 对象=class1.newInstance(参数);
//取得本类已声明的所有字段,包括私有的、保护的
Field[] field = class1.getDeclaredFields();
//返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
Method method = clazz.getMethod(方法名,参数类型);
//调用具体某个实例对象的这个公有方法
method.invoke(实例对象,参数值);

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

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

相关文章

飞桨AI Day落地澳门高校!助力大湾区打造产教融合新范式

为了推动大湾区建设产教融合的人工智能技术生态&#xff0c;加快培养助力社会经济高质量发展的复合型 AI 人才&#xff0c;飞桨校园 AI Day 登陆澳门&#xff0c;开展《AI 技术发展趋势与人才培养》主题讲座 &#xff0c;邀请多位澳门科技大学及百度嘉宾&#xff0c;解读当下AI…

【中兴ZXV10 B860A1.1】

这里写自定义目录标题 开启adb开启adb 部分盒子的ADB调试位置,在设置页面中可以有开启开发者选项。地区界面不同,位置不同有的在设置里。 如果找不到,直接按住遥控器【返回】不放,5秒后,快速不停按【左键】。 点击【打开ADB调试】这时侯让你输入密码 下载zikaikeji.ap…

chatgpt赋能python:Python如何创建集合——你必须知道的所有知识

Python 如何创建集合——你必须知道的所有知识 作为一位有10年 Python 编程经验的工程师&#xff0c;我可以告诉你&#xff0c;Python 集合是编程中非常重要的一部分。如果你不知道如何创建集合&#xff0c;那么你可能会错过很多东西。所以&#xff0c;让我们深入探讨 Python …

提供一个使用Npoi生成excel文档的例子,应能帮助到各位使用Npoi的朋友,因为具有多种情形处理

提供一个使用Npoi生成excel文档的例子&#xff0c;应能帮助到各位使用Npoi的朋友&#xff0c;因为具有多种情形处理 照例&#xff0c;文章开始之前&#xff0c;先看下最终效果&#xff1a; 实现的需求点如下&#xff1a; 1.第一行大标题加了背景色&#xff0c;且这个背景色&…

解密 JS 参数:逆向工程的实用技巧

大家好&#xff0c;我是安果&#xff01; 大部分网站都会对关键参数进行加密&#xff0c;JS 逆向时&#xff0c;我们首要任务是定位参数具体的加密逻辑 常见方式包含&#xff1a;关键字搜索、堆栈调试、XHR 及事件监听、AST 内存漫游、JS Hook 注入等 本篇文章以 JS Hook 注入定…

惊爆!Python打造花式照片墙!

大家注意&#xff1a;因为微信最近又改了推送机制&#xff0c;经常有小伙伴说错过了之前被删的文章&#xff0c;比如前阵子冒着风险写的爬虫&#xff0c;再比如一些限时福利&#xff0c;错过了就是错过了。 所以建议大家加个星标&#xff0c;就能第一时间收到推送。&#x1f44…

NXP IMX8M + Ethercat+Codesys工业实时运动控制解决方案

面向边缘计算应用的全新i.MX 8M Plus异构应用处理器&#xff0c;搭载专用神经网络加速器、独立实时子系统、双摄像头ISP、高性能DSP和GPU。 恩智浦半导体宣布推出i.MX 8M Plus应用处理器&#xff0c;进一步丰富其业界领先的产品组合。这是恩智浦首个集成了专用神经处理引擎&…

G0第25章:Gin框架进阶项目实战

1 Gin框架源码解析 通过阅读gin框架的源码来探究gin框架路由与中间件的秘密。 1.1 Gin框架路由详解 gin框架使用的是定制版本的httprouter&#xff0c;其路由的原理是大量使用公共前缀的树结构&#xff0c;它基本上是一个紧凑的Trie tree 或者只是&#xff08;Radix Tree&am…

Linux Tomcat服务 虚拟主机 多实例部署

Tomcat 服务 Tomcat 是 Java 语言开发的&#xff0c;Tomcat 服务器是一个免费的开放源代码的 Web 应用服务器。Tomcat 属于轻量级应用服务器&#xff0c;在中小型系统和并发访问用户不是很多的场合下被普遍使用&#xff0c;是开发和调试 java开发的JSP 动态页面程序的首选。一般…

Linux教程——常见Linux发行版本有哪些?

新手往往会被 Linux 众多的发行版本搞得一头雾水&#xff0c;我们首先来解释一下这个问题。 从技术上来说&#xff0c;李纳斯•托瓦兹开发的 Linux 只是一个内核。内核指的是一个提供设备驱动、文件系统、进程管理、网络通信等功能的系统软件&#xff0c;内核并不是一套完整的…

DDD领域模型

一、分层介绍 controller层&#xff1a;处理页面或者api请求的输入输出&#xff0c;定义VO(REQ,RES)&#xff0c;没有业务逻辑&#xff0c;只做请求处理和下层逻辑接application层&#xff1a;处理跨领域domain的复杂逻辑&#xff0c;定义DTOdomain层&#xff1a;领域核心逻辑…

深入理解Qt多线程编程:QThread、QTimer与QAudioOutput的内在联系__QObject的主线程的事件循环

深入理解Qt多线程编程&#xff1a;QThread、QTimer与QAudioOutput的内在联系__QObject的主线程的事件循环 1. Qt多线程编程的基础1.1 QObject和线程&#xff08;QObject and Threads&#xff09;1.2 QThread的使用和理解&#xff08;Understanding and Using QThread&#xff0…

C#,码海拾贝(35)——求“实对称矩阵““特征值与特征向量“的“雅可比法“之C#源代码

using System; namespace Zhou.CSharp.Algorithm { /// <summary> /// 矩阵类 /// 作者&#xff1a;周长发 /// 改进&#xff1a;深度混淆 /// https://blog.csdn.net/beijinghorn /// </summary> public partial class Matrix {…

编码器 | 基于 Transformers 的编码器-解码器模型

基于 transformer 的编码器-解码器模型是 表征学习 和 模型架构 这两个领域多年研究成果的结晶。本文简要介绍了神经编码器-解码器模型的历史&#xff0c;更多背景知识&#xff0c;建议读者阅读由 Sebastion Ruder 撰写的这篇精彩 博文。此外&#xff0c;建议读者对 自注意力 (…

【AUTOSAR】Bootloader说明(一)---- 时序流程

电机控制器选用TI TMS28xx DSP&#xff0c;包括boot-loader与应用软件两个部分。其中boot-loader包括下列内容&#xff1a; RAM自检应用程序有效性检查UDS命令处理FLASH操作 下面分别说明DSP上电后整个软件运行流程及程序刷新过程。 DSP软件执行流程 DSP复位后&#xff0c;将…

【Mysql基础】-关于常用的函数简单案例

目录 一、系统函数 二、日期函数 三、字符串函数数 说明&#xff1a;以下所有的操作在8.0的mysql数据库操作系统上操作 一、系统函数 1 显示连接列表&#xff1a;show PROCESSLIST; 2 MD5加密&#xff1a;select MD5("root") 二、日期函数 1、 推算一周之后的…

QMI8658 - 姿态传感的零偏(常值零偏)标定

1. 零偏 理论上在静止状态下三轴输出为0,0,0&#xff0c;但实际上输出有一个小的偏置&#xff0c;这是零偏的静态分量&#xff08;也称固定零偏&#xff09;。 陀螺生产出来后就一直固定不变的零偏值。对于传统的高性能惯性器件来说&#xff0c;该误差在出厂标定时往往就被补偿…

《水经注地图服务》用户如何登录?

《水经注地图服务》&#xff08;WeServer&#xff09;是一款可快速发布全国乃至全球海量卫星影像的地图发布服务产品&#xff0c;该产品完全遵循OGC相关协议标准&#xff0c;是一个基于若干项目成功经验总结的产品。它可以轻松发布100TB级海量卫星影像&#xff0c;从而使“在内…

如何使用 Raycast 一键打开预设工作环境

工作中&#xff0c;你一定遇到过这样的场景&#xff1a;你正在认真写代码&#xff0c;线上突然出现报警。看到报警信息之后&#xff0c;你不得不打开浏览器&#xff0c;点开收藏夹&#xff0c;打开监控页面、告警页面、trace 页面、日志搜索平台……有时&#xff0c;还需要打开…

chatgpt赋能python:Python取值:了解基础知识和应用方法

Python取值&#xff1a;了解基础知识和应用方法 什么是Python取值&#xff1f; Python取值是指从一个对象中获取信息或者值。对象可以包括列表、字典、元组、变量等。Python提供了多种方法来取值&#xff0c;包括基础的索引和切片操作&#xff0c;以及高级的列表推导式、字典…