Spring 使用指南 ~ 3、Spring 中 bean 的生命周期详解

news2025/1/16 1:42:20

Spring 中 bean 的生命周期详解

一、bean 的生命周期图解

在这里插入图片描述

二、bean 创建时使用 Spring 的资源

  • 实现 aware 类型接口的 bean,可以在 bean 实例化的时候获取到一些相对应的资源,如实现 BeanNameAware 的 bean,就可以获取到 beanName。
  • Spring 自带的 aware 类型的接口有很多,下面只列举了常用的三个(ApplicationContextAware 是用的最多的一个)

1、BeanNameAware

  • 使用 BeanNameAware 接口来获取 beanName

示例

package com.luo.spring.guides.beanlifecycle.aware.name;

import org.springframework.beans.factory.BeanNameAware;

/**
 * @author : archer
 * @date : Created in 2022/12/6 15:37
 * @description :
 */
public class NamedSinger  implements BeanNameAware {
    private String name;

    /** @Implements {@link BeanNameAware#setBeanName(String)} */
    public void setBeanName(String beanName) {
        this.name = beanName;
    }

    public void sing() {
        System.out.println("Singer [" + name + "] - sing()");
    }
}
<?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="namedSinger" class="com.luo.spring.guides.beanlifecycle.aware.name.NamedSinger"/>
</beans>

测试

package com.luo.spring.guides.beanlifecycle.aware.name;

import org.springframework.context.support.GenericXmlApplicationContext;

/**
 * @author : archer
 * @date : Created in 2022/12/6 15:38
 * @description :
 */
public class Main {
    public static void main(String[] args) {
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
        ctx.load("beanlifecycle/aware/name/app-context-name.xml");
        ctx.refresh();

        NamedSinger bean = (NamedSinger) ctx.getBean("namedSinger");
        bean.sing();

        ctx.close();
    }
}

输出

Singer [namedSinger] - sing()

2、BeanClassLoaderAware

package com.luo.spring.guides.beanlifecycle.aware.classloader;

import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.stereotype.Component;

/**
 * @author : archer
 * @date : Created in 2022/12/6 15:51
 * @description :
 */
@Component
public class SingerClassLoaderBean implements BeanClassLoaderAware {

    private ClassLoader classLoader;

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    public void print(){
        System.out.println(classLoader);
    }
}

测试

package com.luo.spring.guides.beanlifecycle.aware.classloader;

import com.luo.spring.guides.iocdi.annotation.field.Singer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @author : archer
 * @date : Created in 2022/12/6 15:52
 * @description :
 */
public class Main {

    @Configuration
    @ComponentScan(basePackages = {"com.luo.spring.guides.beanlifecycle.aware.classloader"})
    public static class ClassloaderConfiguration{}

    public static void main(String... args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext
                (ClassloaderConfiguration.class);
        SingerClassLoaderBean singerClassLoaderBean = ctx.getBean("singerClassLoaderBean", SingerClassLoaderBean.class);


        singerClassLoaderBean.print();
    }
}

输出

jdk.internal.loader.ClassLoaders$AppClassLoader@4e25154f

3、ApplicationContextAware

package com.luo.spring.guides.beanlifecycle.aware.applicationcontext;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * Created by iuliana.cosmina on 2/22/17.
 */
@Component
public class Singer implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }


    public void sing() {
		System.out.println(applicationContext.getId());
    }
}

测试

package com.luo.spring.guides.beanlifecycle.aware.applicationcontext;

import com.luo.spring.guides.beanlifecycle.aware.classloader.SingerClassLoaderBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @author : archer
 * @date : Created in 2022/12/8 14:20
 * @description :
 */
public class Main {

    @Configuration
    @ComponentScan(basePackages = {"com.luo.spring.guides.beanlifecycle.aware.applicationcontext"})
    public static class MConfiguration {
    }

    public static void main(String... args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(MConfiguration.class);
        Singer singer = (Singer) ctx.getBean("singer");
        singer.sing();
    }
}

输出

org.springframework.context.annotation.AnnotationConfigApplicationContext@45820e51

三、bean 创建时调用特定方法

1、@PostConstruct

package com.luo.spring.guides.beanlifecycle.init.postconstruct;

import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

import javax.annotation.PostConstruct;

public class SingerWithJSR250 {
    private static final String DEFAULT_NAME = "Eric Clapton";

    private String name;
    private int age = Integer.MIN_VALUE;

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @PostConstruct
    private void init() throws Exception {
        System.out.println("Initializing bean");

       if (name == null) {
            System.out.println("Using default name");
            name = DEFAULT_NAME;
        }

        if (age == Integer.MIN_VALUE) {
            throw new IllegalArgumentException(
                    "You must set the age property of any beans of type " + 
                    SingerWithJSR250.class);
        }
    }

    public String toString() {
        return "\tName: " + name + "\n\tAge: " + age;
    }
}
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans.xsd
          http://www.springframework.org/schema/context 
          http://www.springframework.org/schema/context/spring-context.xsd"
       default-lazy-init="true">

    <context:annotation-config/>

    <bean id="singerOne"
          class="com.luo.spring.guides.beanlifecycle.init.postconstruct.SingerWithJSR250"
          p:name="John Mayer" p:age="39"/>

    <bean id="singerTwo"
          class="com.luo.spring.guides.beanlifecycle.init.postconstruct.SingerWithJSR250"
          p:age="72"/>

    <bean id="singerThree"
          class="com.luo.spring.guides.beanlifecycle.init.postconstruct.SingerWithJSR250"
          p:name="John Butler"/>
</beans>

测试

package com.luo.spring.guides.beanlifecycle.init.postconstruct;

import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

/**
 * @author : archer
 * @date : Created in 2022/12/8 15:26
 * @description :
 */
public class Main {
    public static void main(String... args) {
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
        ctx.load("classpath:beanlifecycle/init/app-context-postconstruct.xml");
        ctx.refresh();

        getBean("singerOne", ctx);
        getBean("singerTwo", ctx);
        getBean("singerThree", ctx);

        ctx.close();
    }

    private static SingerWithJSR250 getBean(String beanName, ApplicationContext ctx) {
        try {
            SingerWithJSR250 bean = (SingerWithJSR250) ctx.getBean(beanName);
            System.out.println(bean);
            return bean;
        } catch (BeanCreationException ex) {
            System.out.println("An error occured in bean configuration: "
                    + ex.getMessage());
            return null;
        }
    }
}

输出

Initializing bean
Name: John Mayer
Age: 39
Initializing bean
Using default name
Name: Eric Clapton
Age: 72
Initializing bean
An error occured in bean configuration: Error creating bean with name ‘singerThree’: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: You must set the age property of any beans of type class com.luo.spring.guides.beanlifecycle.init.postconstruct.SingerWithJSR250

2、InitializingBean

package com.luo.spring.guides.beanlifecycle.init.initialzingbean;

import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class SingerWithInterface implements InitializingBean {
    private static final String DEFAULT_NAME = "Eric Clapton";

    private String name;
    private int age = Integer.MIN_VALUE;

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void afterPropertiesSet() throws Exception {
        System.out.println("Initializing bean");

        if (name == null) {
            System.out.println("Using default name");
            name = DEFAULT_NAME;
        }

        if (age == Integer.MIN_VALUE) {
            throw new IllegalArgumentException(
                    "You must set the age property of any beans of type " 
                    + SingerWithInterface.class);
        }
    }

    public String toString() {
        return "\tName: " + name + "\n\tAge: " + age;
    }
}
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd"
       default-lazy-init="true">

    <bean id="singerOne"
          class="com.luo.spring.guides.beanlifecycle.init.initialzingbean.SingerWithInterface"
          p:name="John Mayer" p:age="39"/>

    <bean id="singerTwo"
          class="com.luo.spring.guides.beanlifecycle.init.initialzingbean.SingerWithInterface"
          p:age="72"/>

    <bean id="singerThree"
          class="com.luo.spring.guides.beanlifecycle.init.initialzingbean.SingerWithInterface"
          p:name="John Butler"/>
</beans>

测试

package com.luo.spring.guides.beanlifecycle.init.initialzingbean;

import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

/**
 * @author : archer
 * @date : Created in 2022/12/8 15:33
 * @description :
 */
public class Main {

    public static void main(String... args) {
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
        ctx.load("beanlifecycle/init/app-context-initializingbean.xml");
        ctx.refresh();

        getBean("singerOne", ctx);
        getBean("singerTwo", ctx);
        getBean("singerThree", ctx);

        ctx.close();
    }

    private static SingerWithInterface getBean(String beanName,
                                               ApplicationContext ctx) {
        try {
            SingerWithInterface bean = (SingerWithInterface) ctx.getBean(beanName);
            System.out.println(bean);
            return bean;
        } catch (BeanCreationException ex) {
            System.out.println("An error occurred in bean configuration: "
                    + ex.getMessage());
            return null;
        }
    }
}

输出

Initializing bean
Name: John Mayer
Age: 39
Initializing bean
Using default name
Name: Eric Clapton
Age: 72
Initializing bean
An error occurred in bean configuration: Error creating bean with name ‘singerThree’ defined in class path resource [beanlifecycle/init/app-context-initializingbean.xml]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: You must set the age property of any beans of type class com.luo.spring.guides.beanlifecycle.init.initialzingbean.SingerWithInterface

3、init-method

package com.luo.spring.guides.beanlifecycle.init.initmethod.domain;

import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class Singer {
    private static final String DEFAULT_NAME = "Eric Clapton";

    private String name;
    private int age = Integer.MIN_VALUE;

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    private void init() {
        System.out.println("Initializing bean");

       if (name == null) {
            System.out.println("Using default name");
            name = DEFAULT_NAME;
        }

        if (age == Integer.MIN_VALUE) {
            throw new IllegalArgumentException(
                    "You must set the age property of any beans of type " + Singer.class);
        }
    }

    public String toString() {
        return "\tName: " + name + "\n\tAge: " + age;
    }
}

1)、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"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd"
    default-lazy-init="true" default-init-method="init">

    <bean id="singerOne"
        class="com.luo.spring.guides.beanlifecycle.init.initmethod.domain.Singer"
          p:name="John Mayer" p:age="39"/>

    <bean id="singerTwo"
        class="com.luo.spring.guides.beanlifecycle.init.initmethod.domain.Singer"
         p:age="72"/>

    <bean id="singerThree"
        class="com.luo.spring.guides.beanlifecycle.init.initmethod.domain.Singer"
         p:name="John Butler"/>
</beans>

测试

package com.luo.spring.guides.beanlifecycle.init.initmethod.xml;

import com.luo.spring.guides.beanlifecycle.init.initmethod.domain.Singer;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

/**
 * @author : archer
 * @date : Created in 2022/12/8 15:41
 * @description :
 */
public class Main {
    public static void main(String... args) {
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
        ctx.load("classpath:beanlifecycle/init/app-context-initmethod.xml");
        ctx.refresh();

        getBean("singerOne", ctx);
        getBean("singerTwo", ctx);
        getBean("singerThree", ctx);

        ctx.close();
    }

    public static Singer getBean(String beanName, ApplicationContext ctx) {
        try {
            Singer bean = (Singer) ctx.getBean(beanName);
            System.out.println(bean);
            return bean;
        } catch (BeanCreationException ex) {
            System.out.println("An error occurred in bean configuration: "
                    + ex.getMessage());
            return null;
        }
    }
}

输出

Initializing bean
Name: John Mayer
Age: 39
Initializing bean
Using default name
Name: Eric Clapton
Age: 72
Initializing bean
An error occurred in bean configuration: Error creating bean with name ‘singerThree’ defined in class path resource [beanlifecycle/init/app-context-initmethod.xml]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: You must set the age property of any beans of type class com.luo.spring.guides.beanlifecycle.init.initmethod.domain.Singer

2)、注解形式

测试

package com.luo.spring.guides.beanlifecycle.init.initmethod.annotation;

import com.luo.spring.guides.beanlifecycle.init.initmethod.domain.Singer;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.support.GenericApplicationContext;

/**
 * @author : archer
 * @date : Created in 2022/12/8 15:42
 * @description :
 */
public class Main {

    @Configuration
    static class SingerConfig{

        @Lazy
        @Bean(initMethod = "init")
        Singer singerOne() {
            Singer singerOne = 	new Singer();
            singerOne.setName("John Mayer");
            singerOne.setAge(39);
            return singerOne;
        }

        @Lazy
        @Bean(initMethod = "init")
        Singer singerTwo() {
            Singer singerTwo = 	new Singer();
            singerTwo.setAge(72);
            return singerTwo;
        }

        @Lazy
        @Bean(initMethod = "init")
        Singer singerThree() {
            Singer singerThree = 	new Singer();
            singerThree.setName("John Butler");
            return singerThree;
        }
    }

    public static void main(String... args) {
        GenericApplicationContext ctx = new AnnotationConfigApplicationContext(SingerConfig.class);

        getBean("singerOne", ctx);
        getBean("singerTwo", ctx);
        getBean("singerThree", ctx);

        ctx.close();
    }

    public static Singer getBean(String beanName, ApplicationContext ctx) {
        try {
            Singer bean = (Singer) ctx.getBean(beanName);
            System.out.println(bean);
            return bean;
        } catch (BeanCreationException ex) {
            System.out.println("An error occurred in bean configuration: "
                    + ex.getMessage());
            return null;
        }
    }
}

输出

Initializing bean
Name: John Mayer
Age: 39
Initializing bean
Using default name
Name: Eric Clapton
Age: 72
Initializing bean
An error occurred in bean configuration: Error creating bean with name ‘singerThree’ defined in com.luo.spring.guides.beanlifecycle.init.initmethod.annotation.Main$SingerConfig: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: You must set the age property of any beans of type class com.luo.spring.guides.beanlifecycle.init.initmethod.domain.Singer

四、bean 销毁时调用特定方法

1、@PreDestroy

package com.luo.spring.guides.beanlifecycle.destory.predestory.domain;

import org.springframework.context.support.GenericXmlApplicationContext;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.File;

public class DestructiveBeanWithJSR250 {
    private File file;
    private String filePath;
    
    @PostConstruct
    public void init() throws Exception {
        System.out.println("Initializing Bean");

        if (filePath == null) {
            throw new IllegalArgumentException(
                    "You must specify the filePath property of " + 
                    DestructiveBeanWithJSR250.class);
        }

        this.file = new File(filePath);
        this.file.createNewFile();

        System.out.println("File exists: " + file.exists());
    }

    @PreDestroy
    public void destroy() {
        System.out.println("Destroying Bean");

        if(!file.delete()) {
            System.err.println("ERROR: failed to delete file.");
        }

        System.out.println("File exists: " + file.exists());
    }

    public void setFilePath(String filePath) {
        this.filePath = filePath;
    }


}

1)、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"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

    <bean id="destructiveBean"
          class="com.luo.spring.guides.beanlifecycle.destory.predestory.domain.DestructiveBeanWithJSR250"
          p:filePath=
                  "#{systemProperties['java.io.tmpdir']}#{systemProperties['file.separator']}test.txt"/>
</beans>

测试

package com.luo.spring.guides.beanlifecycle.destory.predestory.xml;

import com.luo.spring.guides.beanlifecycle.destory.predestory.domain.DestructiveBeanWithJSR250;
import org.springframework.context.support.GenericXmlApplicationContext;

/**
 * @author : archer
 * @date : Created in 2022/12/8 16:08
 * @description :
 */
public class Main {

    public static void main(String... args) throws Exception {
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
        ctx.load("classpath:beanlifecycle/destroy/app-context-predestory.xml");
        ctx.refresh();

        DestructiveBeanWithJSR250 bean =
                (DestructiveBeanWithJSR250) ctx.getBean("destructiveBean");

        System.out.println("Calling destroy()");
        ctx.close();
        System.out.println("Called destroy()");
    }
}

输出

Initializing Bean
File exists: true
Destroying Bean
File exists: false

2)、注解形式

测试

package com.luo.spring.guides.beanlifecycle.destory.predestory.annotation;

import com.luo.spring.guides.beanlifecycle.destory.predestory.domain.DestructiveBeanWithJSR250;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.support.GenericApplicationContext;

/**
 * Created by iuliana.cosmina on 2/27/17.
 */
public class Main {

	@Configuration
	static class DestructiveBeanConfig {

		@Lazy // 表示 getBean 时再创建 bean
		@Bean
		DestructiveBeanWithJSR250 destructiveBean() {
			DestructiveBeanWithJSR250 destructiveBean = new DestructiveBeanWithJSR250();
			destructiveBean.setFilePath(System.getProperty("java.io.tmpdir") +
					System.getProperty("file.separator") + "test.txt");
			return destructiveBean;
		}

	}

	public static void main(String... args) {
		GenericApplicationContext ctx =
				   new AnnotationConfigApplicationContext(DestructiveBeanConfig.class);

		ctx.getBean(DestructiveBeanWithJSR250.class);
		ctx.registerShutdownHook();
	}

}

输出

Initializing Bean
File exists: true
Destroying Bean
File exists: false

2、DisposableBean

package com.luo.spring.guides.beanlifecycle.destory.disposable;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.support.GenericXmlApplicationContext;

import java.io.File;

public class DestructiveBeanWithInterface implements InitializingBean, DisposableBean {
    private File file;
    private String filePath;
    
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Initializing Bean");

        if (filePath == null) {
            throw new IllegalArgumentException(
                    "You must specify the filePath property of " + 
                    DestructiveBeanWithInterface.class);
        }

        this.file = new File(filePath);
        this.file.createNewFile();

        System.out.println("File exists: " + file.exists());
    }

    @Override
    public void destroy() {
        System.out.println("Destroying Bean");

        if(!file.delete()) {
            System.err.println("ERROR: failed to delete file.");
        }

        System.out.println("File exists: " + file.exists());
    }

    public void setFilePath(String filePath) {
        this.filePath = filePath;
    }

}

测试

package com.luo.spring.guides.beanlifecycle.destory.disposable;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.support.GenericApplicationContext;

/**
 * @author : archer
 * @date : Created in 2022/12/8 16:49
 * @description :
 */
public class Main {

    @Configuration
    static class DestructiveBeanConfig {

        @Lazy // 表示 getBean 时再创建 bean
        @Bean
        DestructiveBeanWithInterface destructiveBean() {
            DestructiveBeanWithInterface destructiveBean = new DestructiveBeanWithInterface();
            destructiveBean.setFilePath(System.getProperty("java.io.tmpdir") +
                    System.getProperty("file.separator") + "test.txt");
            return destructiveBean;
        }

    }

    public static void main(String... args) throws Exception {
        GenericApplicationContext ctx =
                new AnnotationConfigApplicationContext(DestructiveBeanConfig.class);

        ctx.getBean(DestructiveBeanWithInterface.class);
        ctx.close();
    }
}

输出

Initializing Bean
File exists: true
Destroying Bean
File exists: false

3、destroy-method

package com.luo.spring.guides.beanlifecycle.destory.destroymethod;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.support.GenericXmlApplicationContext;

import java.io.File;

public class DestructiveBean {
    private File file;
    private String filePath;
    
    public void init() throws Exception {
        System.out.println("Initializing Bean");

        if (filePath == null) {
            throw new IllegalArgumentException(
                    "You must specify the filePath property of " + DestructiveBean.class);
        }

        this.file = new File(filePath);
        this.file.createNewFile();

        System.out.println("File exists: " + file.exists());
    }

    public void destroy() {
        System.out.println("Destroying Bean");

        if(!file.delete()) {
            System.err.println("ERROR: failed to delete file.");
        }

        System.out.println("File exists: " + file.exists());
    }

    public void setFilePath(String filePath) {
        this.filePath = filePath;
    }


}

测试

package com.luo.spring.guides.beanlifecycle.destory.destroymethod;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.support.GenericApplicationContext;

/**
 * @author : archer
 * @date : Created in 2022/12/8 16:55
 * @description :
 */
public class Main {

    @Configuration
    static class DestructiveBeanConfig {
        @Lazy // 表示 getBean 时再创建 bean
        @Bean(initMethod = "init", destroyMethod = "destroy")
        DestructiveBean destructiveBean() {
            DestructiveBean destructiveBean = new DestructiveBean();
            destructiveBean.setFilePath(System.getProperty("java.io.tmpdir") +
                    System.getProperty("file.separator") + "test.txt");
            return destructiveBean;
        }
    }

    public static void main(String... args) throws Exception {
        GenericApplicationContext ctx =
                new AnnotationConfigApplicationContext(DestructiveBeanConfig.class);

        ctx.getBean(DestructiveBean.class);
        ctx.registerShutdownHook();
    }
}

输出

Initializing Bean
File exists: true
Destroying Bean
File exists: false

五、使用关闭钩子

在 Spring 中销毁回调函数唯一缺点是,它们不会自动触发,需要应用程序关闭之前调用 AbstractApplicationContext.destroy()。那么怎么让它随着应用程序的关闭自动调用呢?

一个可行的方案是创建一个关闭钩子(Shutdown Hook),它是应用程序关闭之前执行的一个线程,这是调用 AbstractApplicationContext.destroy() 的一种理想的方式。

  • ctx.registerShutdownHook() 会与 ctx.close() 产生相同的结果
  • ctx.registerShutdownHook() 方法自动指示 Spring 注册底层 JVM 运行时的关闭钩子。

代码实现如下

package com.luo.spring.guides.beanlifecycle.shutdownhook;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericApplicationContext;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.File;

public class DestructiveBeanWithHook implements ApplicationContextAware {
    private File file;
    private String filePath;

    private ApplicationContext applicationContext;

    @PostConstruct
    public void init() throws Exception {
        System.out.println("Initializing Bean");

        if (filePath == null) {
            throw new IllegalArgumentException(
                    "You must specify the filePath property of " +
                            DestructiveBeanWithHook.class);
        }

        this.file = new File(filePath);
        this.file.createNewFile();

        System.out.println("File exists: " + file.exists());
    }

    @PreDestroy
    public void destroy() {
        System.out.println("Destroying Bean");

        if (!file.delete()) {
            System.err.println("ERROR: failed to delete file.");
        }

        System.out.println("File exists: " + file.exists());
    }

    public void setFilePath(String filePath) {
        this.filePath = filePath;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
        if (applicationContext instanceof AbstractApplicationContext) {
            ((AbstractApplicationContext) applicationContext).registerShutdownHook();
        }
    }
}

测试

package com.luo.spring.guides.beanlifecycle.shutdownhook;

import com.luo.spring.guides.beanlifecycle.destory.destroymethod.DestructiveBean;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

/**
 * @author : archer
 * @date : Created in 2022/12/8 17:11
 * @description :
 */
public class Main {

    @Configuration
    static class DestructiveBeanConfig {
        @Lazy // 表示 getBean 时再创建 bean
        @Bean
        DestructiveBeanWithHook destructiveBean() {
            DestructiveBeanWithHook destructiveBean = new DestructiveBeanWithHook();
            destructiveBean.setFilePath(System.getProperty("java.io.tmpdir") +
                    System.getProperty("file.separator") + "test.txt");
            return destructiveBean;
        }
    }

    public static void main(String... args) throws Exception {
        GenericApplicationContext ctx =
                new AnnotationConfigApplicationContext(DestructiveBeanConfig.class);

        ctx.getBean(DestructiveBeanWithHook.class);
    }
}

输出

Initializing Bean
File exists: true

//若不注册 registerShutdownHook(),则没有下面两行,即 destroy() 方法不执行

Destroying Bean
File exists: false

六、使用 FactoryBean

package com.luo.spring.guides.factorybean;

import java.security.MessageDigest;

public class MessageDigester {
    private MessageDigest digest1;
    private MessageDigest digest2;

    public void setDigest1(MessageDigest digest1) {
        this.digest1 = digest1;
    }

    public void setDigest2(MessageDigest digest2) {
        this.digest2 = digest2;
    }

    public MessageDigest getDigest1() {
        return digest1;
    }

    public void digest(String msg) {
        System.out.println("Using digest1");
        digest(msg, digest1);

        System.out.println("Using digest2");
        digest(msg, digest2);
    }

    private void digest(String msg, MessageDigest digest) {
        System.out.println("Using alogrithm: " + digest.getAlgorithm());
        digest.reset();
        byte[] bytes = msg.getBytes();
        byte[] out = digest.digest(bytes);
        System.out.println(out);
    }
}
package com.luo.spring.guides.factorybean;

import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;

import java.security.MessageDigest;

public class MessageDigestFactoryBean implements 
      FactoryBean<MessageDigest>, InitializingBean {
    private String algorithmName = "MD5";

    private MessageDigest messageDigest = null;

    public MessageDigest getObject() throws Exception {
       return messageDigest;
    }

    public Class<MessageDigest> getObjectType() {
        return MessageDigest.class;
    }

    public boolean isSingleton() {
        return true;
    }

    public void afterPropertiesSet() throws Exception {
        messageDigest = MessageDigest.getInstance(algorithmName);
    }

    public void setAlgorithmName(String algorithmName) {
        this.algorithmName = algorithmName;
    }
}

测试

package com.luo.spring.guides.factorybean;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.GenericApplicationContext;

import java.security.MessageDigest;

/**
 * Created by iuliana.cosmina on 3/7/17.
 */
public class Main {

    @Configuration
    static class MessageDigesterConfig {

        @Bean
        public MessageDigestFactoryBean shaDigest() {
            MessageDigestFactoryBean factoryOne = new MessageDigestFactoryBean();
            factoryOne.setAlgorithmName("SHA1");
            return factoryOne;
        }

        @Bean
        public MessageDigestFactoryBean defaultDigest() {
            return new MessageDigestFactoryBean();
        }

        @Bean
        MessageDigester digester() throws Exception {
            MessageDigester messageDigester = new MessageDigester();
            messageDigester.setDigest1(shaDigest().getObject());
            messageDigester.setDigest2(defaultDigest().getObject());
            return messageDigester;
        }
    }

    public static void main(String... args) throws Exception {
        GenericApplicationContext ctx = new AnnotationConfigApplicationContext(MessageDigesterConfig.class);

        MessageDigester digester = (MessageDigester) ctx.getBean("digester");
        digester.digest("Hello World!");

        System.out.println("==========我是分割线=============");

        MessageDigest shaDigest1 = ctx.getBean("shaDigest", MessageDigest.class);
        System.out.println(shaDigest1.digest("Hello World".getBytes()).toString());

        MessageDigestFactoryBean factoryBean =
                (MessageDigestFactoryBean) ctx.getBean("&shaDigest");
        MessageDigest shaDigest2 = factoryBean.getObject();
        System.out.println(shaDigest2.digest("Hello World".getBytes()).toString());

        System.out.println("shaDigest1==shaDigest2:" + (shaDigest1 == shaDigest2));
        System.out.println("digester.getDigest1()==shaDigest2:" + (digester.getDigest1() == shaDigest2));

        ctx.close();
    }
}

输出

Using digest1
Using alogrithm: SHA1
[B@782859e
Using digest2
Using alogrithm: MD5
[B@34bde49d
我是分割线===
[B@1b1cfb87
[B@821330f
shaDigest1==shaDigest2:true
digester.getDigest1()==shaDigest2:true

七、factory-bean && factory-method

package com.luo.spring.guides.factorybean.xml;

import java.security.MessageDigest;

public class MessageDigestFactory {
    private String algorithmName = "MD5";

    public MessageDigest createInstance() throws Exception {
       return MessageDigest.getInstance(algorithmName);
    }

    public void setAlgorithmName(String algorithmName) {
        this.algorithmName = algorithmName;
    }
}
package com.luo.spring.guides.factorybean;

import java.security.MessageDigest;

public class MessageDigester {
    private MessageDigest digest1;
    private MessageDigest digest2;

    public void setDigest1(MessageDigest digest1) {
        this.digest1 = digest1;
    }

    public void setDigest2(MessageDigest digest2) {
        this.digest2 = digest2;
    }

    public MessageDigest getDigest1() {
        return digest1;
    }

    public void digest(String msg) {
        System.out.println("Using digest1");
        digest(msg, digest1);

        System.out.println("Using digest2");
        digest(msg, digest2);
    }

    private void digest(String msg, MessageDigest digest) {
        System.out.println("Using alogrithm: " + digest.getAlgorithm());
        digest.reset();
        byte[] bytes = msg.getBytes();
        byte[] out = digest.digest(bytes);
        System.out.println(out);
    }
}
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="shaDigestFactory" 
        class="com.luo.spring.guides.factorybean.xml.MessageDigestFactory"
        p:algorithmName="SHA1"/>

    <bean id="defaultDigestFactory"
        class="com.luo.spring.guides.factorybean.xml.MessageDigestFactory"/>

    <bean id="shaDigest"
          factory-bean="shaDigestFactory"
          factory-method="createInstance">
    </bean>

    <bean id="defaultDigest"
          factory-bean="defaultDigestFactory"
          factory-method="createInstance"/>

    <bean id="digester" 
        class="com.luo.spring.guides.factorybean.MessageDigester"
        p:digest1-ref="shaDigest"
        p:digest2-ref="defaultDigest"/>
</beans>

测试

package com.luo.spring.guides.factorybean.xml;

import com.luo.spring.guides.factorybean.MessageDigester;
import org.springframework.context.support.GenericXmlApplicationContext;

import java.security.MessageDigest;

public class Main {
    public static void main(String... args) throws Exception {
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
        ctx.load("classpath:factorybean/app-context-xml.xml");
        ctx.refresh();

        MessageDigester digester = (MessageDigester) ctx.getBean("digester");
        digester.digest("Hello World!");

        System.out.println("==========我是分割线=============");

        MessageDigest shaDigest1 = ctx.getBean("shaDigest", MessageDigest.class);
        System.out.println(shaDigest1.digest("Hello World".getBytes()).toString());

        System.out.println("digester.getDigest1()==shaDigest2:" + (digester.getDigest1() == shaDigest1));

        ctx.close();
    }
}

输出

Using digest1
Using alogrithm: SHA1
[B@16a0ee18
Using digest2
Using alogrithm: MD5
[B@505fc5a4
我是分割线===
[B@5fbdfdcf
digester.getDigest1()==shaDigest2:true

八、PropertyEditor

1、使用内置的 PropertyEditor

  • 默认情况下,Spring 不会注册 CustomDateEditor 和 StringTrimmerEditor
  • 使用 Spring 内置的 PropertyEditor,可以将各种属性的 String 转换为正确的类型
package com.luo.spring.guides.propertyeditor.domain;

import org.springframework.beans.PropertyEditorRegistrar;
import org.springframework.beans.PropertyEditorRegistry;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.context.support.GenericXmlApplicationContext;

import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Pattern;

public class PropertyEditorBean {
    private byte[] bytes;                 // ByteArrayPropertyEditor
    private Character character;          //CharacterEditor
    private Class cls;                    // ClassEditor
    private Boolean trueOrFalse;          // CustomBooleanEditor
    private List<String> stringList;      // CustomCollectionEditor
    private Date date;                    // CustomDateEditor
    private Float floatValue;             // CustomNumberEditor
    private File file;                    // FileEditor
    private InputStream stream;           // InputStreamEditor
    private Locale locale;                // LocaleEditor
    private Pattern pattern;              // PatternEditor
    private Properties properties;        // PropertiesEditor
    private String trimString;            // StringTrimmerEditor
    private URL url;                      // URLEditor

    public void setCharacter(Character character) {
        System.out.println("Setting character: " + character);
        this.character = character;
    }

    public void setCls(Class cls) {
        System.out.println("Setting class: " + cls.getName());
        this.cls = cls;
    }

    public void setFile(File file) {
        System.out.println("Setting file: " + file.getName());
        this.file = file;
    }

    public void setLocale(Locale locale) {
        System.out.println("Setting locale: " + locale.getDisplayName());
        this.locale = locale;
    }

    public void setProperties(Properties properties) {
        System.out.println("Loaded " + properties.size() + " properties");
        this.properties = properties;
    }

    public void setUrl(URL url) {
        System.out.println("Setting URL: " + url.toExternalForm());
        this.url = url;
    }

    public void setBytes(byte... bytes) {
        System.out.println("Setting bytes: " + Arrays.toString(bytes));
        this.bytes = bytes;
    }

    public void setTrueOrFalse(Boolean trueOrFalse) {
        System.out.println("Setting Boolean: " + trueOrFalse);
        this.trueOrFalse = trueOrFalse;
    }

    public void setStringList(List<String> stringList) {
        System.out.println("Setting string list with size: "
            + stringList.size());

        this.stringList = stringList;

        for (String string: stringList) {
            System.out.println("String member: " + string);
        }
    }

    public void setDate(Date date) {
        System.out.println("Setting date: " + date);
        this.date = date;
    }

    public void setFloatValue(Float floatValue) {
        System.out.println("Setting float value: " + floatValue);
        this.floatValue = floatValue;
    }

    public void setStream(InputStream stream) {
        System.out.println("Setting stream: " + stream);
        this.stream = stream;
    }

    public void setPattern(Pattern pattern) {
        System.out.println("Setting pattern: " + pattern);
        this.pattern = pattern;
    }

    public void setTrimString(String trimString) {
        System.out.println("Setting trim string: " + trimString);
        this.trimString = trimString;
    }

    public static class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar {
        @Override
        public void registerCustomEditors(PropertyEditorRegistry registry) {
            SimpleDateFormat dateFormatter = new SimpleDateFormat("MM/dd/yyyy");
            //默认情况下,Spring 不会注册 CustomDateEditor 和 StringTrimmerEditor
            registry.registerCustomEditor(Date.class,
                     new CustomDateEditor(dateFormatter, true));

            registry.registerCustomEditor(String.class, new StringTrimmerEditor(true));
        }
    }
}
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:util="http://www.springframework.org/schema/util"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/util    
        http://www.springframework.org/schema/util/spring-util.xsd">

    <bean id="customEditorConfigurer" 
        class="org.springframework.beans.factory.config.CustomEditorConfigurer"
        p:propertyEditorRegistrars-ref="propertyEditorRegistrarsList"/>
   
    <util:list id="propertyEditorRegistrarsList">
        <bean class="com.luo.spring.guides.propertyeditor.domain.PropertyEditorBean$CustomPropertyEditorRegistrar"/>
    </util:list>

    <bean id="builtInSample" class="com.luo.spring.guides.propertyeditor.domain.PropertyEditorBean"
          p:character="A"
        p:bytes="John Mayer"
        p:cls="java.lang.String"
        p:trueOrFalse="true"
        p:stringList-ref="stringList"
        p:stream="test.txt"
        p:floatValue="123.45678"
        p:date="05/03/13"
        p:file="#{systemProperties['java.io.tmpdir']}#{systemProperties['file.separator']}test.txt"
        p:locale="en_US"
        p:pattern="a*b"
        p:properties="name=Chris age=32"
        p:trimString="   String need trimming   "
        p:url="https://spring.io/"
    /> 

    <util:list id="stringList">
        <value>String member 1</value>
        <value>String member 2</value>
    </util:list>
</beans>

测试

package com.luo.spring.guides.propertyeditor.xml;

import com.luo.spring.guides.propertyeditor.domain.PropertyEditorBean;
import org.springframework.context.support.GenericXmlApplicationContext;

import java.io.File;

/**
 * @author : archer
 * @date : Created in 2022/12/8 19:02
 * @description :
 */
public class Main {

    public static void main(String... args) throws Exception {
        File file = File.createTempFile("test", "txt");
        file.deleteOnExit();

        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
        ctx.load("classpath:propertyeditor/app-context-propertyeditor.xml");
        ctx.refresh();

        PropertyEditorBean bean =
                (PropertyEditorBean) ctx.getBean("builtInSample");

        ctx.close();
    }
}

输出

Setting bytes: [74, 111, 104, 110, 32, 77, 97, 121, 101, 114]
Setting character: A
Setting class: java.lang.String
Setting date: Wed May 03 00:00:00 CST 13
Setting file: test.txt
Setting float value: 123.45678
Setting locale: 英语 (美国)
Setting pattern: a*b
Loaded 1 properties
Setting stream: java.io.BufferedInputStream@4b14918a
Setting string list with size: 2
String member: String member 1
String member: String member 2
Setting trim string: String need trimming
Setting Boolean: true
Setting URL: https://spring.io/

2、自定义 PropertyEditor

package com.luo.spring.guides.propertyeditor.domain;

public class FullName {
    private String firstName;
    private String lastName;

    public FullName(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String toString() {
        return "First name: " + firstName + " - Last name: " + lastName;
    }
}
package com.luo.spring.guides.propertyeditor.domain;

import java.beans.PropertyEditorSupport;

public class NamePropertyEditor extends PropertyEditorSupport {
    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        //匹配任意空白字符(空格,制表符等)
        String[] name = text.split("\\s");

        setValue(new FullName(name[0], name[1]));
    }
}
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean name="customEditorConfigurer"
          class="org.springframework.beans.factory.config.CustomEditorConfigurer">
        <property name="customEditors">
            <map>
                <entry key="com.luo.spring.guides.propertyeditor.domain.FullName"
                       value="com.luo.spring.guides.propertyeditor.domain.NamePropertyEditor"/>
            </map>
        </property>
    </bean>

    <bean id="exampleBean" class="com.luo.spring.guides.propertyeditor.domain.CustomEditorExample"
      p:name="John Mayer"/>
</beans>

测试

package com.luo.spring.guides.propertyeditor.domain;

import org.springframework.context.support.GenericXmlApplicationContext;

/**
 * @author : archer
 * @date : Created in 2022/12/8 19:03
 * @description :
 */
public class CustomEditorExample {

    private FullName name;

    public FullName getName() {
        return name;
    }

    public void setName(FullName name) {
        this.name = name;
    }

    public static void main(String... args) {
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
        ctx.load("classpath:propertyeditor/app-context-02.xml");
        ctx.refresh();

        CustomEditorExample bean =
                (CustomEditorExample) ctx.getBean("exampleBean");

        System.out.println(bean.getName());

        ctx.close();
    }
}

输出

First name: John - Last name: Mayer

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

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

相关文章

[附源码]JAVA毕业设计无人驾驶汽车管理系统(系统+LW)

[附源码]JAVA毕业设计无人驾驶汽车管理系统&#xff08;系统LW&#xff09; 项目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目…

[附源码]JAVA毕业设计西藏民族大学论文管理系统(系统+LW)

[附源码]JAVA毕业设计西藏民族大学论文管理系统&#xff08;系统LW&#xff09; 项目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 …

KubeSphere v3.3.1 权限控制详解

作者&#xff1a;周文浩&#xff0c;青云科技研发工程师&#xff0c;KubeSphere Maintainer。热爱云原生&#xff0c;热爱开源&#xff0c;目前负责 KubeSphere 权限控制的开发与维护。 KubeSphere 3.3.1 已经发布一个多月了。 3.3.1 版本对于 KubeSphere 来说只是一个小的 Pat…

ADI Blackfin DSP处理器-BF533的开发详解10:SPORT-IIS口驱动和应用(含源代码)

硬件准备 ADSP-EDU-BF533&#xff1a;BF533开发板 AD-HP530ICE&#xff1a;ADI DSP仿真器 软件准备 Visual DSP软件 硬件链接 接口功能介绍 ADSP-BF533上有两个 SPORT 口&#xff0c;SPORT&#xff08;synchronous serial ports&#xff09;接口是 ADSP-BF53x 上速度最快的…

执法仪物联卡在哪里采购靠谱

在这个万物互联的时代&#xff0c;针对于企业设备联网的物联卡就显得格外重要了&#xff0c;而共享单车&#xff0c;移动支付&#xff0c;智慧城市&#xff0c;自动售卖机等企业采购物联卡会面临着各种问题&#xff0c;低价陷阱&#xff0c;流量虚假&#xff0c;管理混乱&#…

基于LSTM递归神经网络的多特征电能负荷预测(Python代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

Kubernetes 系统化学习之 集群安全篇(七)

Kubernetes 作为一个分布式集群管理的工具&#xff0c;保证集群的安全性是其一个重要的任务。API Server 是集群内部各个组件通信的中介&#xff0c;也是外部控制的入口&#xff0c;所以 K8s 的安全机制就是围绕保护 API Server 来设计的。K8s 使用了认证&#xff08;Authentic…

计算机毕业设计springboot+vue基本微信小程序的大学生竞赛信息发布与报名小程序

项目介绍 大学生竞赛是提升大学生综合能力和专业素质的重要手段和途径,越来越受到广大高校师生的关注与重视。大学生学科竞赛活动不仅有利于提升大学生的专业素养,也有利于提升大学生的创新、实践能力、竞争意识与团队精神。 各类学科竞赛汇总、信息发布、信息收集、报名、备赛…

针对前端项目node版本问题导致依赖安装异常的处理办法

Mac如何切换版本 前端项目开发过程中&#xff0c;多人开发会遇到由于node版本不同造成的依赖不适配。 比如: node 16.xx 大多都会遇到依赖版本与node版本不适配导致安装报错等问题&#xff0c;并且你不管如何更新还是使用稳定版本的node.js都不起作用&#xff0c;此时你需要修…

看直播怎么录屏?这2个方法,一看就会!

​现在很多人在斗鱼、虎牙、斗鱼、腾讯课堂等平台上直播&#xff0c;有些人在视频聊天平台上&#xff0c;如微信上直播。我们如何保存这些直播视频&#xff1f;看直播怎么录屏&#xff1f;今天小编就分享2个方法&#xff0c;教你如何看直播的同时录屏。 看直播怎么录屏方法一&a…

Font字体属性

Font字体属性 源代码 font font属性用于定义字体系列、大小、粗细、和文字样式(如斜体) font-family font-family属性用于定义文本字体&#xff0c;多个字体用 ” , ” 号隔开&#xff0c;一般情况下&#xff0c;有空格隔开的多个单词组成的字体&a…

Eziriz .NET Reactor保护NET代码

Eziriz .NET Reactor保护NET代码 NET Reactor软件是一个简单而小巧的工具&#xff0c;但对保护NET代码非常强大。会的。编程数据可以通过使用本程序、编写的代码和程序来保护&#xff0c;并禁止复制和使用它们。 Eziriz.NET Reactor软件的功能和特点&#xff1a; -支持收集和模…

MODBUS-ASCII协议

MODBUS协议在RS485总线上有RTU和ASCII两种传输格式。 其中ASCII协议应用比较少&#xff0c;主要还是以RTU格式为主。 相比较于RTU的2进制传输&#xff0c;ASCII使用的是文本传输&#xff0c;整个数据包都是可打印字符。 下面是示例&#xff1a; :010300000001FB\r\n 帧头是冒…

GWAS:使用R,比较GLM和MLM对假阳性的控制差异(复刻Nature genetics 图)

目录 1.数据准备 2.代码 如果想知道横纵坐标设置的原理&#xff0c;移步这篇超级棒的文章&#xff01; 我们来复刻如下这张2016年发表在Nature genetics上的一篇文章中比较GLM和MLM的QQ plot&#xff01; 参考文献&#xff1a; Genetic variation in ZmVPP1 contributes t…

Python爬虫项目100例

前言 Python爬虫项目100例&#xff08;一&#xff09;&#xff1a;入门级 CentOS环境安装 和谐图网站爬取 美空网数据爬取 美空网未登录图片爬取 27270图片爬取 蜂鸟网图片爬取之一 蜂鸟网图片爬取之二 蜂鸟网图片爬取之三 河北阳光理政投诉板块 Pyt图虫网多线程爬取…

【计算机视觉+Tensorflow】SORT目标跟踪算法的讲解(图文解释 超详细)

觉得有帮助请点赞关注收藏~~~ 一、目标跟踪简介 目标跟踪算法可以进行轨迹特征的分析和提取&#xff0c;以弥补目标检测的不足&#xff1b;有效地去除误检&#xff0c;提高检测精度&#xff0c;为进一步的行为分析提供基础。例如&#xff0c;在自动驾驶系统中&#xff0c;目标跟…

Kafka知识点

消费者组 kafka的消费者组里面包含一个或多个消费者实例&#xff0c;它们共享一个公共的 ID&#xff0c;这个 ID 被称为 Group ID。一个消费者组可以订阅多个主题&#xff0c;但是同一个消费者组里面的一个实例只能消费一个主题里面的一个分区。 consumer group A kafka consum…

web课程设计网页规划与设计(HTML+CSS+JavaScript仿悦世界游戏官网 6个页面)

&#x1f389;精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

web前端 基于html实现花店购物网站源码(HTML+CSS+JavaScript) 企业网站制作

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…