Spring深入学习

1 Bean创建的生命周期

Spring bean是Spring运行时管理的对象。Spring Bean的生命周期指的是Bean从创建到初始化再到销毁的过程,这个过程由IOC容器管理。

IOC即控制反转,是面向对象编程中的一种设计原则,通过依赖注入(DI)、依赖查找的方式实现对象之间的松耦合关系。

BeanFactory为IoC容器,ApplicationContext为应用上下文,ApplicationContext容器包括BeanFactory容器的所有功能。

1)创建bean的三种方式

  1. 基于XML配置文件
  2. 基于注解,@Component、 @Repository、@Service、@Controller;@Component可以代替@Repository、@Service、@Controller。
  3. 基于Java类的bean定义,需要提供setter方法
    @Bean
    public Student student(){
        return new Student();;
    }


    public class Student{
        private String name;
  
        public void SetName(String name){
            this.name = name;
        }
    }

 2)bean对象

 

对象不一定是bean,bean一定是对象,bean对象都放在一个MAP里。 

获取对象的方式可以使用构造方法去创建对象,上面的UserService就存在一个默认的构造方法。(如果程序中没有显式定义任何构造方法,那么java语言将自动提供一个隐含的默认构造方法。

spring扫描到@Component等注解时,就会认为这是定义的bean,就会使用此类构造方法获取对象。然后Spring去检查哪些对象存在@Autowired,就给自动进行依赖注入,进行赋值。

UserServie.class--->构造方法--->普通对象--->依赖注入--->放入Map<beanName,Bean对象>

spring会继续去检查哪些方法存在@PostConstruct方法,然后主动执行方法里的内容。 

实现逻辑如下:

当然也可以实现InitializingBean接口,用写afterPropertiesSet()方式实现

((InitializingBean)对象).afterPropertiesSet(); 

UserServie.class--->推断构造方法--->普通对象--->依赖注入--->初始化前(@PostConstruct)--->初始化(InitializingBean)--->初始化后(AOP)--->代理对象--->放入Map<beanName,Bean对象>

推断构造方法:

@Service
public class UserService {
    private final UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}

写了无参构造,则默认使用无参构造依赖注入;

不写无参构造,写多个有参构造,会报错No Default Construct;必须使用@Autowired指定默认是是哪个;

不写无参构造,只写一个有参构造,则会直接使用这个有参构造进行依赖注入;

依赖注入完成属性赋值,spring会依据入参的类型、名字去spring IOC容器里的Bean MAP<beanname,bean对象>里寻找bean对象。

1.1 依赖注入

在Java中,DI的实现方式主要有以下几种:

● 构造器注入
● Setter方法注入
● 接口注入
● 注解注入

1)构造器注入(spring框架中在构造方法上添加@Autowired注解)

@Component 标准一个普通的spring Bean类; @Repository标注一个DAO组件类; @Service标注一个业务逻辑组件类。 @Component可以代替@Repository、@Service、@Controller,因为这三个注解是被@Component标注的。

@Service
public class UserService {
    private final UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public User getUserById(int id) {
        return userRepository.getUserById(id);
    }
}

2)setter方法注入(在setter方法上添加@Autowired注解)

@Service
public class UserService {
    private UserRepository userRepository;

    @Autowired
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public User getUserById(int id) {
        return userRepository.getUserById(id);
    }
}

3)接口注入

@Service
public class UserService {
    private UserRepository userRepository;

    @Autowired
    public void setUserRepositorySetter(UserRepositorySetter userRepositorySetter) {
        userRepositorySetter.setUserRepository(userRepository);
    }

    public User getUserById(int id) {
        return userRepository.getUserById(id);
    }
}

实现对应的接口

public interface UserRepositorySetter {
    void setUserRepository(UserRepository userRepository);
}

@Repository
public class UserRepositoryImpl implements UserRepository, UserRepositorySetter {
    @Override
    public User getUserById(int id) {
        // 实现代码
    }

    @Override
    public void setUserRepository(UserRepository userRepository) {
        // 实现代码
    }
}

4)注解注入

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;

    public User getUserById(int id) {
        return userRepository.getUserById(id);
    }
}

依赖注入如何寻找是哪个 userRepository?过程如下,从by type 到 by name:

1.2 AOP

认识AOP

AOP 是 Aspect Oriented Programming 的缩写,译为面向切向编程。

设计一个日志打印模块: 

  • 按 OOP 思想,我们会设计一个打印日志 LogUtils 类,然后在需要打印的地方引用即可。
  • 按AOP思想,声明哪些地方需要打印日志,这个地方就是一个切面,AOP 会在适当的时机为你把打印语句插进切面。

AOP实现的关键在于AOP框架自动创建的AOP代理,以AspectJ为代表的静态代理,以Spring AOP为代表的动态代理。Spring AOP中的动态代理主要有两种方式:JDK动态代理和CGLIB动态代理。

Spring AOP通过在代理类中包裹切面,Spring在运行期把切面织入到Spring管理的bean中。代理类封装了目标类,并拦截被通知方法的调用,再把调用转发给真正的目标bean(目标对象)。

AOP实现技术由APT、AspetJ等,如下:

1)横切关注点

跨越应用程序多个模块的方法或功能,如日志、安全、缓存、事务等等。

2)连接点

连接点是在应用执行中能够插入切面的一个点。即程序执行过程中能够应用通知的所有点。

3)通知

切面的工作被称为通知,Spring切面可以应用5种类型的通知:

  • 前置通知(Before):在目标方法被调用之前调用通知功能。
  • 后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么。
  • 返回通知(After-returning):在目标方法成功执行之后调用通知。
  • 异常通知(After-throwing)):在目标方法抛出异常后调用通知。
  • 环绕通知(Around) :通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。

1.3 SpringBoot AOP

orderService为空? 

进入test之前,orderServcie是有值的!

1)Spring首先要判断这个对象要不要执行AOP

2)生成一个子类代理类,继承UserService,重写UserService里的test方法

3)子类代理类(代理对象)执行test方法时,先执行切面逻辑,然后执行业务逻辑

4)执行 代理对象.target.test()方法

        代理对象.target对象 = 被代理对象 = 普通对象 = 已经经过了依赖注入 = 对象已经属性有值;

        但是代理对象没有依赖注入,没有值;他只是为了执行切面逻辑,所以不需要必须去用对象的属性。

切面逻辑中可以通过获取这个target对象,来获取普通对象

AOP基本使用: 

依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

代码
@Aspect  // 使用@Aspect注解声明一个切面
@Component
public class SysLogAspect {

    @Autowired
    private SysLogService sysLogService;

    @Pointcut("@annotation(com.lmlsj.SysLog)")
    public void logPointCut() {}


    @Before("execution(* com.lmlsj.SysLog.*(..))")
    public void before() {
        System.out.println("MyAspect: 前置增强.....");
    }
}

配置
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {

}

正常流程:【环绕通知-前】-> 【前置通知】-> 【返回通知】-> 【后置通知】->【环绕通知-后】。 

2 事物

1)事物执行逻辑

2)普通对象调用,事物失效

这里a()方法是普通对象的,直接执行a()里面的语句,不会去走切面逻辑判断是否有@Transactional注解,事物失效。 

3)代理对象调用才会去走切面逻辑

自己注入自己,使用代理对象实现事物正常执行

4)@Configuration

加上@Configuration后,Appconfig就是代理对象,才能保证下图两处的dataSource()是同一个对象,才能执行事务。

3 扫描

Spring扫描首先Spring根据注解去寻找bean类,非懒加载的bean在Spring容器启动时就创建好,懒加载的bean是用到时再创建。如何寻找注解的实现思路:

1)反射方式:AA.class.isAnnotationPresent(Component.class)

2)ASM技术(Spring使用):编辑CLASS字节码

扫描类的寻找:

AnnotationConfigApplicationContext.java

1)处理配置类

(1)判断Component注解

ConfigurationClassParser.java  doProcessConfigurationClass(*)

(2)检查是不是配置类的地方

2)ComponentScan

parse解析得到BeanDefinition集合,然后去遍历BeanDefinition这些对象是不是有什么注解、配置

 3)parse属性解析过程

ComponentScanAnnotationParser类

this.registry是Spring IOC容器

(1) useDefaultFilters属性,注册一些默认的过滤器

(2)ComponentScan的nameGenerator属性

generatorClass是nameGenerator属性的管理,没有设置该属性就使用默认值。

补充:可以根据@Component的value设置bean的名字,没有设置就根据类名进行设置。

前两个字符都是大写,就直接返回;不符合就将第一个字符,设置为小写。

(3)scopeProxy属性设置

作用域在类上设置,在收到请求时再创建bean

同时可以指定代理对象的生成方式

(4)resourcePattern、includeFilters、excludeFilters属性

excludeFilters可以设置某个类不是一个bean,type = FilterType.ASSIGNABLE_TYPE是根据类class来过滤

@ComponentScan(value = "com.lmlsj", excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {MyService.class})})

(5)懒加载

(6)扫描路径属性

根据属性值配置扫描路径,或者根据@ComponentScan注解配置扫描路径

排除器,排除已经设置成bean的类 

最后就是doScan真正的扫描开始。

4)doScan扫描

扫描包路径

 public Set<BeanDefinition> findCandidateComponents(String basePackage) {
        return this.componentsIndex != null && this.indexSupportsIncludeFilters() 
        ? 
        this.addCandidateComponentsFromIndex(this.componentsIndex, basePackage) : 
        this.scanCandidateComponents(basePackage);
    }

检查是否在过滤器里

4 Spring启动demo

1)SpringApplicationContex

public class SpringApplicationContext {

    private Class configClass;
    private Map<String,BeanDefination> beanDefinationMap = new HashMap<>();
    private Map<String,Object> singletonObjects = new HashMap<>();  //单例池
    private List<BeanPostProcess> beanPostProcessorList = new ArrayList<>();

    public SpringApplicationContext(Class configClass) {
        this.configClass = configClass;
        scan(configClass);              //解析传进来的配置类,生成beanDefination
        preInstantiateSingletons();     //单例bean初始化
    }

    private void preInstantiateSingletons() {
        for(Map.Entry<String,BeanDefination> entry : beanDefinationMap.entrySet()){
            BeanDefination beanDefination = entry.getValue();
            if(beanDefination.getScope().equals("singleton")){
                Object bean = createBean(entry.getKey(), beanDefination);
                singletonObjects.put(entry.getKey(), bean);     //单例bean
            }
        }
    }

    public Object createBean(String beanName, BeanDefination beanDefination){
        Class clazz = beanDefination.getClazz();
        Object instance = null;
        try {
            // 1 对象实例化
            instance = clazz.newInstance();

            // 2 依赖注入 属性赋值
            for(Field field : clazz.getDeclaredFields()){
                if(field.isAnnotationPresent(LmAutowired.class)){
                    String name = field.getName();  // field.getType()  ,by name/ by type
                    Object bean = getBean(name);
                    field.setAccessible(true);
                    field.set(instance,bean);
                }
            }

            // 4 初始化前
            for (BeanPostProcess beanPostProcess : beanPostProcessorList) {
               instance =  beanPostProcess.postProcessBeforeInitialization(instance,beanName);
            }

            // 3 spring初始化数值
            if(instance instanceof InitializingBean){
                try {
                    ((InitializingBean)instance).afterPropertiesSet();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            // 5 初始化后
            for (BeanPostProcess beanPostProcess : beanPostProcessorList) {
               instance =  beanPostProcess.postProcessAfterInitialization(instance,beanName);
            }

        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return instance;
    }

    public void scan(Class configClass){
        // 1 解析配置类
        if(configClass.isAnnotationPresent(LmComponentScan.class)){
            LmComponentScan componentScan = (LmComponentScan)configClass.getAnnotation(LmComponentScan.class);
            String path = componentScan.value();
            System.out.println("配置路径: " + path);
            path = path.replace(".","/");

            //2 扫描配置路径下有LmComponent注解的类
            ClassLoader classLoader = SpringApplicationContext.class.getClassLoader();  //app
            URL resource = classLoader.getResource(path);

            File file = new File(resource.getFile()); //获取对应文件夹
            File[] files = file.listFiles();//文件夹下所有的文件

            for (File f : files) {
                String fileName = f.getAbsolutePath();
                if(fileName.endsWith(".class")){
                    String className = fileName.substring(fileName.indexOf("com"),fileName.indexOf(".class"));
                    className = className.replace("/",".");
                    try {
                        Class clazz = classLoader.loadClass(className);
                        //spring是使用ASM去解析字节码文件的,这里简单实现一下
                        if(clazz.isAnnotationPresent(LmComponent.class)){

                            //beanPostProcessorList初始化
                            if(BeanPostProcess.class.isAssignableFrom(clazz)){
                                try {
                                    BeanPostProcess beanPostProcess = (BeanPostProcess) clazz.newInstance();
                                    beanPostProcessorList.add(beanPostProcess);
                                } catch (InstantiationException e) {
                                    e.printStackTrace();
                                } catch (IllegalAccessException e) {
                                    e.printStackTrace();
                                }
                            }

                            LmComponent annotation = (LmComponent) clazz.getAnnotation(LmComponent.class);
                            String beanName = annotation.value();
                            //3 生成beanDefination对象
                            BeanDefination beanDefination = new BeanDefination();

                            beanDefination.setClazz(clazz);

                            if(clazz.isAnnotationPresent(Scope.class)){
                                Scope scope = (Scope) clazz.getAnnotation(Scope.class);
                                beanDefination.setScope(scope.value());
                            }else{
                                beanDefination.setScope("singleton");
                            }

                            beanDefinationMap.put(beanName,beanDefination);
                        }
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                }
            }
        }else {
            System.out.println("没有LmComponentScan注解");
        }
    }

    public Object getBean(String beanName){
        //1 判断是否已存在bean
        if(beanDefinationMap.containsKey(beanName)){
            BeanDefination beanDefination = beanDefinationMap.get(beanName);
            //2 判断是不是单例bean
            if(beanDefination.getScope().equals("singleton")){
                Object o = singletonObjects.get(beanName);
                return o;
            }else{
                //多例bean
                Object bean = createBean(beanName,beanDefination);
                return bean;
            }
        }else {
            System.out.println("没有找到" + beanName);
            throw new NullPointerException();
        }
    }

}

2)BeanDefination

public class BeanDefination {

    private Class clazz;
    private String scope;

    public Class getClazz() {
        return clazz;
    }

    public void setClazz(Class clazz) {
        this.clazz = clazz;
    }

    public String getScope() {
        return scope;
    }

    public void setScope(String scope) {
        this.scope = scope;
    }
    
}

3)BeanPostProcess

public interface BeanPostProcess {

    Object postProcessBeforeInitialization(Object bean,String beanName);

    Object postProcessAfterInitialization(Object bean,String beanName);
}

4)InitializingBean

public interface InitializingBean {
    void afterPropertiesSet() throws Exception;
}

5)注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface LmAutowired {

    String value() default ""; //属性
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface LmComponent {

    String value() default ""; //属性
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface LmComponentScan {

    String value() default ""; //属性
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scope {
    String value() default ""; //属性
}

6)测试类

public class Main {

    public static void main(String[] args){
        //用spring 包里自己写的代码
        SpringApplicationContext springApplicationContext = new SpringApplicationContext(AppConfig.class);

        //多例bean
        UserService userService =  (UserService)springApplicationContext.getBean("userService");
        UserService userService2 =  (UserService)springApplicationContext.getBean("userService");
        UserService userService3 =  (UserService)springApplicationContext.getBean("userService");
        System.out.println(userService);
        System.out.println(userService2);
        System.out.println(userService3);

        userService.test();

        System.out.println("_____________________");
        //单例bean
        OrderService orderService = (OrderService)springApplicationContext.getBean("orderService");
        OrderService orderService2 = (OrderService)springApplicationContext.getBean("orderService");
        OrderService orderService3 = (OrderService)springApplicationContext.getBean("orderService");
        System.out.println(orderService);
        System.out.println(orderService2);
        System.out.println(orderService3);
    }
}

7)BeanPostProcesorImpl

@LmComponent
public class BeanPostProcesorImpl implements BeanPostProcess {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        if(beanName.equals("orderService")){
            System.out.println("初始化之前");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        //代理AOP在此实现
        return bean;
    }
}

8)AppConfig

@LmComponentScan("com.lmlsj.test")
public class AppConfig {
}

9)其他类

@LmComponent("orderService")
public class OrderService {
}

@LmComponent("userDao")
public class UserDao {
}

@LmComponent("userService")
@Scope("prototype")
public class UserService implements InitializingBean {

    @LmAutowired
    private UserDao userDao;

    private User defaultUser;

    public void test(){
        System.out.println(userDao);
        System.out.println(defaultUser.getName() + ":" + defaultUser.getPass());
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        defaultUser = new User("default","123456");
    }
}


10)测试结果

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java8实战 - 行为参数化传递代码

背景&#xff1a; 根据《java8实战》把第二章简单概括一下。 在软件工程中&#xff0c;一个最重要的问题是&#xff0c;用户的需求会一直变化&#xff0c;如何应对不断变化的需求&#xff0c;并且把工作量降到最低是需要考虑的&#xff0c;而行为参数化就是一个处理频繁变更需…

我在代码随想录|写代码之203. 移除链表元素,707. 设计链表,206. 反转链表

​第一题 ​​ 203. 移除链表元素 题目: 思路分析: 我们要删除节点说白了就是将节点移除,将要删除的节点的前一个的next域移动到要删除节点的next域,我们可以这样写当我们运到我们要删除节点然后件他删除,那么怎么删除?我们可以直接让我们要删除的元素找不到。如果我们直接将…

JdbcTemplate query系列方法指定jdbcType类型

使用SqlParameterValue类包装一下就行了&#xff0c;只要创建一个SqlParameterValue对象&#xff0c;通过构造函数把jdbcType类型&#xff08;用的是Types中的常量&#xff09;和值传入 例如&#xff1a; // 这两个包下面的 import org.springframework.jdbc.core.SqlParamete…

LAMP平台——构建PHP运行环境

在构建LAMP平台时&#xff0c;各组件的安装顺序依次为Linux、Apache、MySQL、PHP。其中Apache和 MySQL的安装并没有严格的顺序&#xff1b;而PHP环境的安装一般放到最后&#xff0c;负责沟通Web服务器和数据库 系统以协同工作。 PHP 即 Hypertext Preprocessor&#xff08;超级…

nodejs+vue+微信小程序+python+PHP邮件分类系统的设计与实现-计算机毕业设计推荐

方便安装&#xff0c;减少了维护的工作量&#xff0c;只需要通过服务器端的更新就可以实现新系统的发布&#xff0c;提高了邮件分类系统的可扩展性和可移植性。 E-mail是信息化时代最重要的联系工具之一&#xff0c;在日常的工作学习中具有非常重要作用。电子邮件作为互联网技术…

Vue3-19-组件-定义和基本使用

组件的定义 个人理解 &#xff1a;1、组件&#xff0c;就是我们把某个功能模块进行封装&#xff0c;在使用时直接引入进行使用&#xff0c;极大的提高了代码的可复用性。2、在vue 中&#xff0c;一个 [.vue] 文件&#xff0c;就是一个组件。3、组件之间存在【引入】 与 【被引…

什么是供应链安全及其工作原理?

6000公里长的丝绸之路将丝绸、谷物和其他货物从中国运送到帕尔米拉。尽管蒙古治下的和平保护丝绸之路免受海盗、强盗和内部盗窃的侵害&#xff0c;但商人仍然装备精良&#xff0c;并依赖于大型商队旅行和战略性放置的小型堡垒所提供的安全。 为什么供应链安全很重要&#xff1…

智安网络|企业网络安全工具对比:云桌面与堡垒机,哪个更适合您的需求

随着云计算技术的快速发展&#xff0c;越来越多的企业开始采用云计算解决方案来提高效率和灵活性。在云计算环境下&#xff0c;云桌面和堡垒机被广泛应用于企业网络安全和办公环境中。尽管它们都有助于提升企业的安全和效率&#xff0c;但云桌面和堡垒机在功能和应用方面存在着…

智能优化算法应用:基于秃鹰算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于秃鹰算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于秃鹰算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.秃鹰算法4.实验参数设定5.算法结果6.参考文献7.MA…

实战指南:使用 Nginx 反向代理实现多端口跳转

目录 前言1 实现的效果2 准备两个tomcat服务2.1 启动8080端口的tomcat服务2.2 启动8081端口的tomcat服务 3 Nginx 配置3.1 配置内容3.2 配置说明3.3 location符号的含义和作用 4 开放防火墙端口5 测试与验证结语 前言 在现代 Web 开发中&#xff0c;Nginx作为一款高性能的开源…

FL Studio 21.2.2.3914破解补丁含FL Studio2024 Crack文件及怎么激活FL Studio

FL Studio 21.2.2.3914中文破解版国人习惯称水果编曲, 是一个完整的电音软件音乐制作环境或数字音频工作站。是现在流行的数字音频工作站之一,包括撰写,整理,记录,编辑,电音,混音和掌握专业品质的音乐。 FL Studio 21.2.2.3914 (Windows)原版安装程序破解补丁 软件全名&#x…

索引与优化原理(上)

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 上一篇&#xff0c;我们…

ToolLLM model 以及LangChain AutoGPT Xagent在调用外部工具Tools的表现对比浅析

文章主要谈及主流ToolLLM 以及高口碑Agent 在调用Tools上的一些对比&#xff0c;框架先上&#xff0c;内容会不断丰富与更新。 第一部分&#xff0c;ToolLLM model 先来说主打Function Call 的大模型们 OpenAI GPT 宇宙第一LLM&#xff0c;它的functionCall都知道&#xff0…

nrm 的使用 可以快速切换下载(npm)镜像,解决资源下载慢和运行失败

nrm是什么&#xff1f; 介绍 nrm(npm registry manager) 是 npm 的镜像源管理工具. 有时候国外资源太慢,使用 nrm 可以快速的在 npm 源之间切换 安装 npm install -g nrm 基本使用 查看可选择的源 nrm ls 切换到对应的镜像源 nrm use 对应的镜像 删除镜像源 nrm del 名字 …

数据挖掘目标(客户价值分析)

import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as snsIn [2]: datapd.read_csv(r../教师文件/air_data.csv)In [3]: data.head()Out[3]: Start_timeEnd_timeFareCityAgeFlight_countAvg_discountFlight_mileage02011/08/182014/0…

网络入门---守护进程

目录标题 什么是守护进程会话的理解setsid函数daemonSelf函数模拟实现测试 什么是守护进程 在前面的学习过程中我们知道了如何使用TCP协议和UDP协议来实现通信&#xff0c;比如说登录xshell运行了服务端&#xff1a; 然后再登录一个xshell运行客户端并向服务端发送信息&#…

笔记本电脑如何安装openwrt

环境&#xff1a; 联想E14笔记本 装机U盘 DiskImage v1.6 刷写工具 immortalwrt镜像 问题描述&#xff1a; 笔记本电脑如何安装openwrt 解决方案&#xff1a; 一、官方版 1.官网下载固件 2.BIOS关闭安全启动改为引导 3.用U盘启动进入PE系统后&#xff0c;需要先用PE系…

国产浪潮服务器:风扇免手动调节脚本

简介&#xff1a;浪潮集团&#xff0c;是中国本土顶尖的大型IT企业之一&#xff0c;中国领先的云计算、大数据服务商。浪潮集团旗下拥有浪潮信息、浪潮软件、浪潮国际&#xff0c;业务涵盖云计算、大数据、工业互联网等新一代信息技术产业领域&#xff0c;为全球120多个国家和地…

JNA实现JAVA调用C/C++动态库

1.JNA JNA全称Java Native Access&#xff0c;是一个建立在经典的JNI技术之上的Java开源框架&#xff08;https://github.com/twall/jna&#xff09;。JNA提供一组Java工具类用于在运行期动态访问系统本地库&#xff08;native library&#xff1a;如Window的dll&#xff09;而…

计算机网络——数据链路层-可靠传输的实现机制:回退N帧协议GBN(无差错情况、累积确认、有差错情况、发送窗口尺寸)

目录 回退N帧协议GBN 介绍 无差错情况 累积确认 有差错情况 发送窗口尺寸 小结 练习 解析 示意图 上篇中所介绍的停止-等待协议的信道利用率很低&#xff1b;若出现超时重传&#xff0c;则信道利用率更低。 如果发送方在收到接收方的确认分组之前可以连续发送多个数…