相关demo: GitHub
Java中常用注解:
注意:以下两个注解属于Java
@PostConstruct
@PreDestroy
接下来我们用一段代码演示这两个注解在Spring中的执行顺序
创建一个springboot项目
一、
创建一个bean:
package com.futuretrip.demo.springdemo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Slf4j
@Component
public class BeanDemo {
@Value(value = "${str}")
private String str;
public BeanDemo() {
log.info("调用构造器");
}
/**
* Sets the str. *
* <p>You can use getStr() to get the value of str</p>
* * @param str str
*/
@PostConstruct
public void demo(){
log.info("调用PostConstruct{}", str);
}
@PreDestroy
public void destroy(){
log.info("调用PreDestroy");
}
}
运行结果:
/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/bin/java -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:56154,suspend=y,server=n -XX:TieredStopAtLevel=1 -noverify -Dspring.output.ansi.enabled=always -javaagent:/Users/fangcheng/Library/Caches/JetBrains/IntelliJIdea2021.1/captureAgent/debugger-agent.jar -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/lib/tools.jar:/Users/fangcheng/project/GitHub/springdemo/target/classes:/Users/fangcheng/environment/repo/org/springframework/boot/spring-boot-starter/2.5.2/spring-boot-starter-2.5.2.jar:/Users/fangcheng/environment/repo/org/springframework/boot/spring-boot/2.5.2/spring-boot-2.5.2.jar:/Users/fangcheng/environment/repo/org/springframework/spring-context/5.3.8/spring-context-5.3.8.jar:/Users/fangcheng/environment/repo/org/springframework/spring-aop/5.3.8/spring-aop-5.3.8.jar:/Users/fangcheng/environment/repo/org/springframework/spring-beans/5.3.8/spring-beans-5.3.8.jar:/Users/fangcheng/environment/repo/org/springframework/spring-expression/5.3.8/spring-expression-5.3.8.jar:/Users/fangcheng/environment/repo/org/springframework/boot/spring-boot-autoconfigure/2.5.2/spring-boot-autoconfigure-2.5.2.jar:/Users/fangcheng/environment/repo/org/springframework/boot/spring-boot-starter-logging/2.5.2/spring-boot-starter-logging-2.5.2.jar:/Users/fangcheng/environment/repo/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar:/Users/fangcheng/environment/repo/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar:/Users/fangcheng/environment/repo/org/apache/logging/log4j/log4j-to-slf4j/2.14.1/log4j-to-slf4j-2.14.1.jar:/Users/fangcheng/environment/repo/org/apache/logging/log4j/log4j-api/2.14.1/log4j-api-2.14.1.jar:/Users/fangcheng/environment/repo/org/slf4j/jul-to-slf4j/1.7.31/jul-to-slf4j-1.7.31.jar:/Users/fangcheng/environment/repo/jakarta/annotation/jakarta.annotation-api/1.3.5/jakarta.annotation-api-1.3.5.jar:/Users/fangcheng/environment/repo/org/springframework/spring-core/5.3.8/spring-core-5.3.8.jar:/Users/fangcheng/environment/repo/org/springframework/spring-jcl/5.3.8/spring-jcl-5.3.8.jar:/Users/fangcheng/environment/repo/org/yaml/snakeyaml/1.28/snakeyaml-1.28.jar:/Users/fangcheng/environment/repo/org/slf4j/slf4j-api/1.7.31/slf4j-api-1.7.31.jar:/Users/fangcheng/environment/repo/org/projectlombok/lombok/1.18.16/lombok-1.18.16.jar:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar com.futuretrip.demo.springdemo.SpringdemoApplication
Connected to the target VM, address: '127.0.0.1:56154', transport: 'socket'
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.5.2)
2021-07-15 22:53:28.094 INFO 25337 --- [ main] c.f.d.springdemo.SpringdemoApplication : Starting SpringdemoApplication using Java 1.8.0_231 on MacBook-Pro.local with PID 25337 (/Users/fangcheng/project/GitHub/springdemo/target/classes started by fangcheng in /Users/fangcheng/project/GitHub/springdemo)
2021-07-15 22:53:28.097 INFO 25337 --- [ main] c.f.d.springdemo.SpringdemoApplication : No active profile set, falling back to default profiles: default
[MyBeanFactoryPostProcessor]调用了postProcessBeanFactory
[MyBeanFactoryPostProcessor]当前beanFactory共有45个bean
2021-07-15 22:53:33.034 INFO 25337 --- [ main] com.futuretrip.demo.springdemo.BeanDemo : 调用构造器
2021-07-15 22:53:39.070 INFO 25337 --- [ main] com.futuretrip.demo.springdemo.BeanDemo : 调用PostConstructstr
2021-07-15 22:53:39.671 INFO 25337 --- [ main] c.f.d.springdemo.SpringdemoApplication : Started SpringdemoApplication in 11.909 seconds (JVM running for 12.506)
2021-07-15 22:53:39.701 INFO 25337 --- [ionShutdownHook] com.futuretrip.demo.springdemo.BeanDemo : 调用PreDestroy
Disconnected from the target VM, address: '127.0.0.1:56154', transport: 'socket'
Process finished with exit code 0
由此可以得出执行顺序为:
无参构造器----->@PostConstruct---->@PreDestroy(销毁关闭时调用)
二、
当去掉@Component注解时,@PostConstruct---->@PreDestroy注解的方法未被调用
我们修改这个类,让他实现InitializingBean及DisposableBean接口
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Slf4j
public class BeanDemo implements InitializingBean, DisposableBean {
@Value(value = "${str}")
private String str;
public BeanDemo() {
log.info("调用构造器");
}
@PreDestroy
public void des(){
log.info("调用PreDestroy");
}
public void init(){
log.info("调用init");
}
public void stop(){
log.info("调用stop");
}
@Override
public void afterPropertiesSet() throws Exception {
log.info("调用afterPropertiesSet");
}
@PostConstruct
public void demo(){
log.info("调用PostConstruct{}", str);
}
@Override
public void destroy() throws Exception {
log.info("调用destroy");
}
}
在启动类中通过@Bean的方式注入bean,并指定init和destroy方法
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class SpringdemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringdemoApplication.class, args);
}
@Bean(initMethod = "init",destroyMethod = "stop")
public BeanDemo beanDemo(){
return new BeanDemo();
}
}
在以上的代码中我们定义了三种方式调用bean中的init及destroy方法,他们的执行顺序分别是
调用PostConstructstr-----调用afterPropertiesSet-------调用init----调用PreDestroy-----调用destroy----调用stop
调整代码中方法的顺序无法改变执行结果
那我们就一块看看他们的调用顺序是如何被安排的:
首先下载一份Spring的源码方便查找
使用全局搜索功能查看引用到注解类的地方,排除掉Test类,剩下的就是我们要找的
该类间接实现了BeanPostProcessor接口,完成方法的调用
实现InitializingBean接口