首页 > 其他分享 >一、Spring学习 : 容器---->BeanFactory+ApplicationContext 的多种容器实现

一、Spring学习 : 容器---->BeanFactory+ApplicationContext 的多种容器实现

时间:2023-12-05 23:44:06浏览次数:38  
标签:容器 beanFactory BeanFactory ---- Bean2 Bean1 println class out

BeanFactory实现的特点

我们来着重讲一下DefaultListableBeanFactory这个实现类:

点击查看完整代码
package com.itvayne.springbootcloudstudy.beanfactory01;

import com.sun.org.slf4j.internal.Logger;
import com.sun.org.slf4j.internal.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @program: cloud
 * @description:
 * @author: Vayne
 * @create: 2023-12-05
 **/
public class TestBeanFactory01 {
    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        //我们需要对bean的定义,描述一个bean的类型,初始化方法,销毁方法,以及我们常说的单例还是多例等信息
        //我们下方的Bean1和Bean2其实依赖于我们的Config类,那我们先来定义一个Config类的定义类

        //定一个Config类的描述定义类(有点拗口,各自理解一下)
        AbstractBeanDefinition beanDefinition =
                BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
        //将这个描述类交给beanFactroy制作出一个Config类对象
        beanFactory.registerBeanDefinition("config", beanDefinition);

        //我们此时可以遍历beanFactory,查看beanFactory中有哪些bean了
        for (String bean : beanFactory.getBeanDefinitionNames()) {
            System.out.println(bean);
        }
        //通过观察我们发现,没有Bean1和Bean2,这是为什么?,说明BeanFactory并不具备解析我们@bean的能力
        //那怎么让他具备呢?
        //通过下面这个工具类中的registerAnnotationConfigProcessors添加注解配置的后处理器,对BeanFactory的解析能力进行增强
        System.out.println("============1.解析Bean1和Bean2,加入后处理器==============");
        AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
        //此时我们再来观察BeanFactory
        for (String bean : beanFactory.getBeanDefinitionNames()) {
            System.out.println(bean);
        }
        /**
         * 发现多了这五个类,我们来说下他们分别是干嘛的
         * org.springframework.context.annotation.internalConfigurationAnnotationProcessor,处理@Configuration,以及@Bean注解的后处理器
         * org.springframework.context.annotation.internalAutowiredAnnotationProcessor,处理@Autowired以及@value注解的后处理器
         * org.springframework.context.annotation.internalCommonAnnotationProcessor,处理@Resource注解
         * org.springframework.context.event.internalEventListenerProcessor
         * org.springframework.context.event.internalEventListenerFactory
         */

        System.out.println("===========2.解析Bean1和Bean2===============");

        //那为什么有了后处理器我们依然看不到Bean1和Bean2呢???
        //我们还需要对后处理器进行调用
        //根据beanFactory拿到里面所有的后处理器,然后遍历,将每个后处理器执行在BeanFactory上,然后再次打印观察
        beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().stream().forEach(beanFactoryPostProcessor -> {
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        });
        beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream()
                .sorted(beanFactory.getDependencyComparator())
                .forEach(beanPostProcessor -> {
                    System.out.println(">>>>>>>>>" + beanPostProcessor);
                    beanFactory.addBeanPostProcessor(beanPostProcessor);
                });
        beanFactory.preInstantiateSingletons();
        for (String bean : beanFactory.getBeanDefinitionNames()) {
            System.out.println(bean);
        }
        System.out.println("==========================");
        //通过输出结果我们看到了Bean1和Bean2,此时我们来看看@Autowired有没有生效
        //System.out.println(beanFactory.getBean(Bean1.class).getBean2());
        //查看结果,我们看到虽然Bean1和Bean2通过Config类的@Bean识别出来了,但是Bean1中注入的Bean2缺没有生效,说明@Autowired没有识别
        //我们上面看到的Config类中识别出了Bean1和Bean2其实是利用了BeanFactory的后处理器,BeanFactoryPostProcessor
        //而此时我们需要一个对于Bean的后处理器来帮我们识别Bean的各个生命周期中的注解,比如@Autowired,@Resource等等


        System.out.println("============查看Bean的加载时机==============");
        System.out.println(beanFactory.getBean(Bean1.class).getBean2());
        //此时我们仍然获取不到,因为在上面我们循环获取的时候,Bean已经初始化完成,所以要将Bean后处理器放在前面
        //beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);放在Bean加载之前

        //我们看到这个Bean其实是在我们getBean的时候才加载的,如果需要一开始就加载好就需要
        //beanFactory.preInstantiateSingletons();
    }

    @Configuration
    static class Config {
        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }

        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }
    }

    static class Bean1 {
        private static final Logger log = LoggerFactory.getLogger(Bean1.class);

        public Bean1() {
            log.debug("构建 Bean1()");
        }

        @Autowired
        private Bean2 bean2;

        public Bean2 getBean2() {
            return bean2;
        }
    }

    static class Bean2 {
        private static final Logger log = LoggerFactory.getLogger(Bean2.class);

        public Bean2() {
            log.debug("构建 Bean2()");
        }
    }
}

public class TestBeanFactory01 {
    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        //我们需要对bean的定义,描述一个bean的类型,初始化方法,销毁方法,以及我们常说的单例还是多例等信息
        //我们下方的Bean1和Bean2其实依赖于我们的Config类,那我们先来定义一个Config类的定义类

        //定一个Config类的描述定义类(有点拗口,各自理解一下)
        AbstractBeanDefinition beanDefinition =
                BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
        //将这个描述类交给beanFactroy制作出一个Config类对象
        beanFactory.registerBeanDefinition("config", beanDefinition);

        //我们此时可以遍历beanFactory,查看beanFactory中有哪些bean了
        String[] beans = beanFactory.getBeanDefinitionNames();
        for (String bean : beans) {
            System.out.println(bean);
        }
        
    }

    @Configuration
    static class Config {
        @Bean
        public Bean1 bean1() { return new Bean1(); }
        @Bean
        public Bean2 bean2() { return new Bean2(); }
    }

    static class Bean1 {
        private static final Logger log = LoggerFactory.getLogger(Bean1.class);

        public Bean1() {
            log.debug("Kiti Bean1()");
        }

        @Autowired
        private Bean2 bean2;

        public Bean2 getBean2() {
            return bean2;
        }
    }

    static class Bean2 {
        private static final Logger log = LoggerFactory.getLogger(Bean2.class);

        public Bean2() {
            log.debug("Miti Bean2()");
        }
    }
}

通过观察我们发现,没有Bean1和Bean2,这是为什么?,说明BeanFactory并不具备解析我们@bean的能力

//那怎么让他具备呢?
        //通过下面这个工具类中的registerAnnotationConfigProcessors添加注解配置的后处理器,对BeanFactory的解析能力进行增强
        System.out.println("==========================");
        AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
        //此时我们再来观察BeanFactory
        for (String bean : beanFactory.getBeanDefinitionNames()) {
            System.out.println(bean);
        }
        /**
         * 发现多了这五个类,我们来说下他们分别是干嘛的
         * org.springframework.context.annotation.internalConfigurationAnnotationProcessor,处理@Configuration,以及@Bean注解的后处理器
         * org.springframework.context.annotation.internalAutowiredAnnotationProcessor,处理Autowired注解的后处理器
         * org.springframework.context.annotation.internalCommonAnnotationProcessor
         * org.springframework.context.event.internalEventListenerProcessor
         * org.springframework.context.event.internalEventListenerFactory
         */

        System.out.println("==========================");

        //那为什么有了后处理器我们依然看不到Bean1和Bean2呢???
        //我们还需要对后处理器进行调用
        //根据beanFactory拿到里面所有的后处理器,然后遍历,将每个后处理器执行在BeanFactory上,然后再次打印观察
        beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().stream().forEach(beanFactoryPostProcessor -> {
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        });
        for (String bean : beanFactory.getBeanDefinitionNames()) {
            System.out.println(bean);
        }
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().stream().forEach(beanFactoryPostProcessor -> {
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        });
        beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);
        beanFactory.preInstantiateSingletons();
        for (String bean : beanFactory.getBeanDefinitionNames()) {
            System.out.println(bean);
        }
        System.out.println("==========================");
        //通过输出结果我们看到了Bean1和Bean2,此时我们来看看@Autowired有没有生效
        //System.out.println(beanFactory.getBean(Bean1.class).getBean2());
        //查看结果,我们看到虽然Bean1和Bean2通过Config类的@Bean识别出来了,但是Bean1中注入的Bean2缺没有生效,说明@Autowired没有识别
        //我们上面看到的Config类中识别出了Bean1和Bean2其实是利用了BeanFactory的后处理器,BeanFactoryPostProcessor
        //而此时我们需要一个对于Bean的后处理器来帮我们识别Bean的各个生命周期中的注解,比如@Autowired,@Resource等等

        for (String bean : beanFactory.getBeanDefinitionNames()) {
            System.out.println(bean);
        }

        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>");
        System.out.println(beanFactory.getBean(Bean1.class).getBean2());
        //此时我们仍然获取不到,因为在上面我们循环获取的时候,Bean已经初始化完成,所以要将Bean后处理器放在前面
        //beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);放在Bean加载之前

        //我们看到这个Bean其实是在我们getBean的时候才加载的,如果需要一开始就加载好就需要
        //beanFactory.preInstantiateSingletons();

那么到此我们发现BeanFactory有个初步的了解

  1. 不会主动调用BeanFactroy后处理器

  2. 不会主动添加Bean后处理器

  3. 不会主动初始化实例

  4. 不会解析BeanFactory,也不能解析 ${ } 和 #{}

那么我们即将学习的ApplicationContext将会给我们准备好这些东西

然后我们来看一下这个后处理器,那么后处理器的顺序决定了哪个注解先被解析

比如我们@Recourse 和 @Autowired 两个注解,如果一个接口有两个实现,那么我们利用@Autowired的先ByType再ByName的特性,注入Bean1,然后利用@Resource注入Bean2

那么到底会发生什么,其实这个注入Bean1还是Bean2,取决于Bean后处理器的加载顺序,这两个对应的Bean后处理器分别是:

org.springframework.context.annotation.internalAutowiredAnnotationProcessor ->@Autowired
org.springframework.context.annotation.internalCommonAnnotationProcessor->@Resource

那么我们在添加BeanPostProcessor的时候则决定了他的顺序,而顺序其实是通过实现了Order的接口来完成的,如果需要修改顺序优先级,可以在遍历添加的时候加入.sorted(beanFactory.getDependencyCmparator())

beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream()
              //.sorted(beanFactory.getDependencyComparator())
                .forEach(beanPostProcessor -> {
                    System.out.println(">>>>>>>>>"+beanPostProcessor);
                    beanFactory.addBeanPostProcessor(beanPostProcessor);
                });

ApplicationContext的常见实现和用法

来说说四个很典型的实现类

ClassPathXmlApplicationContext();
FileSystemXmlApplicationContext();
AnnotationConfigApplicationContext();
AnnotationConfigServletWebServerApplicationContext();

来看看他们于ApplicationContext之间的关系

点击查看完整代码

package com.itvayne.springbootcloudstudy.applicationcontext01;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @program: cloud
 * @description:
 * @author: Vayne
 * @create: 2023-12-05
 **/
public class ApplicationContext01 {

    public static void main(String[] args) {
//        testClassPathXmlApplicationContext();
//        testFileSystemXmlApplicationContext();
//        testAnnotationConfigApplicationContext();
        testAnnotationConfigServletWebServerApplicationContext();
    }

    //软为经典的容器,基于 cLasspath下xmL 格式的配置文件来创建
    private static void testClassPathXmlApplicationContext() {
        ClassPathXmlApplicationContext ctx =
                new ClassPathXmlApplicationContext("b01.xml");
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>");
        for (String beanDefinitionName : ctx.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        //发现这个容器想比于BeanFactory来讲直接就可以获取到
        System.out.println(ctx.getBean("bean2", Bean2.class).getBean1());
        System.out.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<");

        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        System.out.println("读取前...");
        for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        System.out.println("读取后...");
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        reader.loadBeanDefinitions(new ClassPathResource("b01.xml"));
        for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
    }

    //基于磁盘路径下XmL 格式的配置文件来创建
    private static void testFileSystemXmlApplicationContext() {
        FileSystemXmlApplicationContext ctx =
                new FileSystemXmlApplicationContext(
                        "//Users/vayne/IdeaProjects/cloud/src/main/resources/b01.xml");

        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>");
        for (String beanDefinitionName : ctx.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        //发现这个容器想比于BeanFactory来讲直接就可以获取到
        System.out.println(ctx.getBean("bean2", Bean2.class).getBean1());
    }


    //较为经典的容器,基于 java 配置类来创建
    private static void testAnnotationConfigApplicationContext() {
        AnnotationConfigApplicationContext ctx =
                new AnnotationConfigApplicationContext(Config.class);
        for (String beanDefinitionName : ctx.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        System.out.println(ctx.getBean("bean2", Bean2.class).getBean1());
    }

    private static void testAnnotationConfigServletWebServerApplicationContext() {
        AnnotationConfigServletWebServerApplicationContext ctx =
                new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
    }

    @Configuration
    static class WebConfig {
        @Bean
        public ServletWebServerFactory servletWebServerFactory() {
            return new TomcatServletWebServerFactory();
        }

        @Bean
        public DispatcherServlet dispatcherServlet() {
            return new DispatcherServlet();
        }

        @Bean
        public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet) {
            return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
        }

        @Bean("/hello")
        public Controller controller() {
            return (request, response) -> {
                response.getWriter().println("hello");
                return null;
            };
        }
    }


    @Configuration
    static class Config {
        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }

        @Bean
        public Bean2 bean2(Bean1 bean1) {
            Bean2 bean2 = new Bean2();
            bean2.setBean1(bean1);
            return bean2;
        }
    }

    static class Bean1 {
    }

    static class Bean2 {
        private Bean1 bean1;

        public void setBean1(Bean1 bean1) {
            this.bean1 = bean1;
        }

        public Bean1 getBean1() {
            return bean1;
        }
    }
}


<?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="bean1"
          class="com.itvayne.springbootcloudstudy.applicationcontext01.ApplicationContext01$Bean1"/>
    <bean id="bean2"
          class="com.itvayne.springbootcloudstudy.applicationcontext01.ApplicationContext01$Bean2">
        <property name="bean1" ref="bean1"/>
    </bean>
</beans>

ClassPathXmlApplicationContext

我们先来看看ClassPathXmlApplicationContext();

ClassPathXmlApplicationContext ctx =
                new ClassPathXmlApplicationContext("b01.xml");
        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>");
        for (String beanDefinitionName : ctx.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        //发现这个容器想比于BeanFactory来讲直接就可以获取到
        System.out.println(ctx.getBean("bean2", Bean2.class).getBean1());

static class Bean1 {
    }

    static class Bean2 {
        private Bean1 bean1;

        public void setBean1(Bean1 bean1) {
            this.bean1 = bean1;
        }

        public Bean1 getBean1() {
            return bean1;
        }
    }

其实我们写过原生spring框架的朋友可能再熟悉不过了,但是现在可能编写配置文件已经成为历史

FileSystemXmlApplicationContext

再来看看FileSystemXmlApplicationContext();不同的是从磁盘路径开始的,当然相对路径绝对路径都可以

private static void testFileSystemXmlApplicationContext() {
        FileSystemXmlApplicationContext ctx =
                new FileSystemXmlApplicationContext(
                        "//Users/vayne/IdeaProjects/cloud/src/main/resources/b01.xml");

        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>");
        for (String beanDefinitionName : ctx.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        //发现这个容器想比于BeanFactory来讲直接就可以获取到
        System.out.println(ctx.getBean("bean2", Bean2.class).getBean1());
    }

static class Bean1 {
    }

    static class Bean2 {
        private Bean1 bean1;

        public void setBean1(Bean1 bean1) {
            this.bean1 = bean1;
        }

        public Bean1 getBean1() {
            return bean1;
        }
    }

那么两种根据路径实现的容器的简单使用讲完了,那么内部是怎么实现的从xml文件读取配置加载到容器中的呢?

手写一个简单实现:

 DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        System.out.println("读取前...");
        for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        System.out.println("读取后...");
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        reader.loadBeanDefinitions(new ClassPathResource("b01.xml"));
        for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }

再来看看spring的实现方式:

当然FileSystemXmlApplicationContext也是如此,只是直接获取的

通过前两个实现,我们知道ApplicationContext可以帮我们实例化单例,以及加载Bean的定义信息,这个信息可以来自配置文件

AnnotationConfigApplicationContext

简单使用

AnnotationConfigApplicationContext ctx =
                new AnnotationConfigApplicationContext(Config.class);
        for (String beanDefinitionName : ctx.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        System.out.println(ctx.getBean("bean2", Bean2.class).getBean1());

@Configuration
    static class Config{
        @Bean
        public Bean1 bean1(){
            return new Bean1();
        }
        @Bean
        public Bean2 bean2(Bean1 bean1){
            Bean2 bean2 = new Bean2();
            bean2.setBean1(bean1);
            return bean2;
        }
    }

    static class Bean1 {
    }

    static class Bean2 {
        private Bean1 bean1;

        public void setBean1(Bean1 bean1) {
            this.bean1 = bean1;
        }

        public Bean1 getBean1() {
            return bean1;
        }
    }

AnnotationConfigServletWebServerApplicationContext

用于web环境的一种经典容器

想要使用它,其实并不简单,web容器中我们必须最少配置三个Bean,分别是Tomcat容器工厂,前处理器DipatcherServlet,将DipatcherServlet注册到Tomcat中的Bean,这三个bean是必须的,前两者在第三者中关联起来

private static void testAnnotationConfigServletWebServerApplicationContext() {
        AnnotationConfigServletWebServerApplicationContext ctx =
                new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
    }

    @Configuration
    static class WebConfig {
        @Bean
        public ServletWebServerFactory servletWebServerFactory() {
            return new TomcatServletWebServerFactory();
        }

        @Bean
        public DispatcherServlet dispatcherServlet() {
            return new DispatcherServlet();
        }

        @Bean
        public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet) {
            return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
        }

        @Bean("/hello")
        public Controller controller() {
            return (request, response) -> {
                response.getWriter().println("hello");
                return null;
            };
        }
    }

这里定义的第四个为web容器的控制器,有个隐藏规则,如果bean的名称是以"/"开头,则直接可以当作路径访问,启动之后可以使用接口调用访问到这个路径并返回"hello"信息

小结:

  1. 内嵌Tomcat如何工作的?

  2. 所有的请求都被前处理器dispatcherServlet拦截,然后经过前处理器进一步分发请求到了我们的控制器

  3. 其实我们这里没有使用springBoot,而其实springBoot内部的web环境也需要这样去工作,我们后面再进行学习

标签:容器,beanFactory,BeanFactory,----,Bean2,Bean1,println,class,out
From: https://www.cnblogs.com/vaynebeself/p/17876374.html

相关文章

  • LD_PRELOAD
    修改库文件它可以影响程序的运行时的链接(Runtimelinker),它允许你定义在程序运行前优先加载的动态链接库。这个功能主要就是用来有选择性的载入不同动态链接库中的相同函数。通过这个环境变量,我们可以在主程序和其动态链接库的中间加载别的动态链接库,甚至覆盖正常的函数库。使用......
  • kafka入门(三):kafka多线程消费
    kafka消费积压如果生产者发送消息的速度过快,或者是消费者处理消息的速度太慢,那么就会有越来越多的消息无法及时消费,也就是消费积压。消费积压时,可以使用多线程消费,提高消费速度。kafka多线程消费的代码:publicclassThirdMultiConsumerThreadDemo{publicstaticfinalS......
  • pta
    pta7-1-1查询子序列和对N个整数的序列,查询子序列和${\textstyle\sum_{k=i}^{j}A_{k}(1≤i,j≤N)}$输入格式:第1行,两个整数:N和Q,表示整数的个数和查询的次数,1≤N≤100000,0≤Q≤100000.第2行,N个用空格分开的整数x,│x│≤20000.第3至Q+2行,每行两个整数i和j,表示所求子序......
  • 抖音自动点赞评论刷视频机器人
    影刀直接获取我的应用,进行测试https://api.winrobot360.com/redirect/robot/share?inviteKey=9cd173e2024d2440 按照以下流程执行打开Edge浏览器,打开www.douyin.com键盘输入x,打开评论无限循环等待元素输入框出现键盘输入z,点赞视频如果输入框没出现,键盘输入x,打开......
  • ASIC 功能验证VTB
    目标设计流程验证设计文档和RTLcode之间的关系RTLcode(DUT)-可以当作是一个黑盒,DUT内部是完全不可见的白盒验证-DUT内部RTL完全可见灰盒验证-DUT内部的RTL部分可见工具主流EDA设计节点DV-特指是功能验证,主要是systemverilog和UVMVerilogTestbench......
  • Linux学习之存储管理
    7.2基本分区7.2.1添加新硬盘在虚拟机上为系统添加两块10GiB虚拟硬盘sdb和sdc,可使用lsblk命令查看新添加的两个硬盘7.2.2MBR分区fdisk-l可以查看系统所挂硬盘个数及分区情况输入m参数可以帮助查看信息,了解每个参数的具体作用,分区具体操作输入n参数可以创建新的分区选择主分......
  • 使用ThinkPHP框架根据Excel内容批量处理图片名称详解记录
    ThinkPHP依赖以下环境Nginx+PHP,建议提前装好Composer,PHP、Composer需要设置好系统环境变量。1.通过Composer安装Laravel框架composercreate-projecttopthink/thinkthinkphp6启动服务测试cdthinkphp6phpthinkrun然后就可以在浏览器中访问http://localhost:8000如果不能显示......
  • 技术架构演进之路基础概念
    概述在进行技术学习过程中,由于没有经历过一些中大型系统的实际经验,导致无法从全局理解一些概念,所以本文以一个"电子商务"应用为例,介绍从一百个到千万级并发情况下服务端的架构的演进过程,同时列举出每个演进阶段会遇到的相关技术,让大家对架构的演进有一个整体的认知,方便大家对后......
  • 天合光能收益如何?天合跟踪前三季业绩新高,全球化布局加速
    10月27日,天合光能(SH:688599)发布2023年第三季度报告,2023年前三季度,公司实现营业收入811.2亿元,同比增长39.38%,天合光能累计支架出货量5.6GW。自2020年9月,天合光能完成对西班牙跟踪支架企业NclaveRenewableS.L.的全资收购(收购后正式更名为“天合跟踪”)正式进军跟踪支架市场后,天......
  • 3.1-AD跨域迁移工具ADMT安装
    1.ADMT工具介绍ADMT(ActiveDirectoryMigrationTool)是一种由Microsoft公司提供的免费工具,用于在ActiveDirectory环境中进行跨域用户和计算机对象的迁移。ADMT可以帮助管理员简化ActiveDirectory环境中复杂的用户和计算机迁移过程,并提供了许多额外的功能和选项来管理......