Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说
spring init-method执行顺序_sql执行先后顺序口诀,希望能够帮助你!!!。
想要知道 @PostConstruct
、init-method
、afterPropertiesSet()
的执行顺序,只要搞明白它们各自在什么时候被谁调用就行了。
程序版本:Spring Boot 2.3.5.RELEASE
准备好要验证的材料:
public class Foo implements InitializingBean {
@Override public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet()"); } @PostConstruct public void init() {
System.out.println("@PostConstruct"); } private void initMethod() {
System.out.println("initMethod()"); } }
@Configuration public class FooConfiguration {
@Bean(initMethod = "initMethod") public Foo foo() {
return new Foo(); } }
执行启动类,可以看到在控制台中输出:
@PostConstruct
afterPropertiesSet()
initMethod()
说明执行顺序是:@PostConstruct、afterPropertiesSet()、init-method
接下来将跟着源码来了解为什么是这个顺序。
@PostConstruct
标注的方法在何时被谁调用首先,在 init()
中打个断点,然后以 debug 的方式启动项目,得到下面的调用栈:
init:23, Foo (com.xurk.init.foo) invoke0:-1, NativeMethodAccessorImpl (sun.reflect) invoke:62, NativeMethodAccessorImpl (sun.reflect) invoke:43, DelegatingMethodAccessorImpl (sun.reflect) invoke:498, Method (java.lang.reflect) invoke:389, InitDestroyAnnotationBeanPostProcessor$LifecycleElement (org.springframework.beans.factory.annotation) invokeInitMethods:333, InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata (org.springframework.beans.factory.annotation) postProcessBeforeInitialization:157, InitDestroyAnnotationBeanPostProcessor (org.springframework.beans.factory.annotation) applyBeanPostProcessorsBeforeInitialization:415, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support) initializeBean:1786, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support) doCreateBean:594, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support) createBean:516, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support) lambda$doGetBean$0:324, AbstractBeanFactory (org.springframework.beans.factory.support) getObject:-1, (org.springframework.beans.factory.support.AbstractBeanFactory$$Lambda$169) getSingleton:234, DefaultSingletonBeanRegistry (org.springframework.beans.factory.support) doGetBean:322, AbstractBeanFactory (org.springframework.beans.factory.support) getBean:202, AbstractBeanFactory (org.springframework.beans.factory.support) preInstantiateSingletons:897, DefaultListableBeanFactory (org.springframework.beans.factory.support) finishBeanFactoryInitialization:879, AbstractApplicationContext (org.springframework.context.support) refresh:551, AbstractApplicationContext (org.springframework.context.support) refresh:143, ServletWebServerApplicationContext (org.springframework.boot.web.servlet.context) refresh:758, SpringApplication (org.springframework.boot) refresh:750, SpringApplication (org.springframework.boot) refreshContext:405, SpringApplication (org.springframework.boot) run:315, SpringApplication (org.springframework.boot) run:1237, SpringApplication (org.springframework.boot) run:1226, SpringApplication (org.springframework.boot) main:14, InitApplication (com.xurk.init)
从上往下看,跳过使用 sun.reflect 的方法,进入到第6行。
public void invoke(Object target) throws Throwable { ReflectionUtils.makeAccessible(this.method); this.method.invoke(target, (Object[]) null); }
很明显,这里是在通过反射调用某个对象的一个方法,并且这个“某个对象”就是我们定义的 Foo
的实例对象了。
那么这里的 method 又是在什么时候进行赋值的呢?
invoke(...)
全路径是: org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.LifecycleElement#invoke
并且 LifecycleElement
有且只有一个显示声明并且带参数的构造器,这个要传入构造器的参数正是 invoke(...)
使用的那个 Method
对象。
接下来就是查一下,是谁在 new LifecycleElement
。
于是定位到:org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#buildLifecycleMetadata
private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
return this.emptyLifecycleMetadata; } List<LifecycleElement> initMethods = new ArrayList<>(); List<LifecycleElement> destroyMethods = new ArrayList<>(); Class<?> targetClass = clazz; do {
final List<LifecycleElement> currInitMethods = new ArrayList<>(); final List<LifecycleElement> currDestroyMethods = new ArrayList<>(); ReflectionUtils.doWithLocalMethods(targetClass, method -> {
if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
LifecycleElement element = new LifecycleElement(method); currInitMethods.add(element); if (logger.isTraceEnabled()) {
logger.trace("Found init method on class [" + clazz.getName() + "]: " + method); } } if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
currDestroyMethods.add(new LifecycleElement(method)); if (logger.isTraceEnabled()) {
logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method); } } }); initMethods.addAll(0, currInitMethods); destroyMethods.addAll(currDestroyMethods); targetClass = targetClass.getSuperclass(); } while (targetClass != null && targetClass != Object.class); return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata : new LifecycleMetadata(clazz, initMethods, destroyMethods)); }
第15-26行是在通过反射判断方法上是否存在某个注解,如果是的话就加到一个集合中,在最后用于构建 LifecycleMetadata
实例。
**那么15行的 this.initAnnotationType
是不是就是我们要找的 @PostConstruct
注解呢?**继续找 initAnnotationType
字段被赋值了什么内容。
在这里因为我们要查找的是被赋值的内容,所以在使用IDE进行查找时只要关注 write 相关的内容就行了。
到这里,已经知道了是在 CommonAnnotationBeanPostProcessor
的构造器中进行 set 的,也就是当创建 CommonAnnotationBeanPostProcessor
实例的时候就会进行赋值,并且 CommonAnnotationBeanPostProcessor
是 InitDestroyAnnotationBeanPostProcessor
的子类。
并且,CommonAnnotationBeanPostProcessor
构造器中调用的 setInitAnnotationType
其实是它父类的方法,实际是对 InitDestroyAnnotationBeanPostProcessor
的实例的 initAnnotationType
字段进行赋值。
到这里已经可以明确 buildLifecycleMetadata(...)
中判断的正是 @PostConstruct
。
再回到buildLifecycleMetadata(...)
,查看其使用的 doWithLocalMethods(...)
的实现。
public static void doWithLocalMethods(Class<?> clazz, MethodCallback mc) {
Method[] methods = getDeclaredMethods(clazz, false); for (Method method : methods) {
try {
mc.doWith(method); } catch (IllegalAccessException ex) {
throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex); } } }
很简单,通过反射获得类的所有方法,然后调用一个函数接口的方法,这个函数接口的实现就是判断方法是不是被 @PostConstruct
标注,如果被标注的话放到一个名字叫 currInitMethods
的集合中。
看到这里或许你已经意识到了, @PostConstruct
可以标注多个方法,并且因为反射获取方法时是根据声明顺序的、 currInitMethods
是 ArrayList
,两者之间的顺序是一样的。
好了,被 @PostConstruct
标注的方法已经找到放到集合中了,将被用来构建 LifecycleMetadata
实例了。
buildLifecycleMetadata(...)
方法返回一个 LifecycleMetadata
实例,这个返回值中包含传入Class实例中得到的所有被 @PostConstruct
标注的 Method 实例,接下来要看看是谁在调用 buildLifecycleMetadata(...)
方法,看看它是怎么用的?
追溯到 findLifecycleMetadata(...)
而 findLifecycleMetadata(...)
又有好几处被调用。
查看最早得到的方法调用栈,查到postProcessBeforeInitializatio(...)
,它又是再被谁调用?
init:23, Foo (com.xurk.init.foo) invoke0:-1, NativeMethodAccessorImpl (sun.reflect) invoke:62, NativeMethodAccessorImpl (sun.reflect) invoke:43, DelegatingMethodAccessorImpl (sun.reflect) invoke:498, Method (java.lang.reflect) invoke:389, InitDestroyAnnotationBeanPostProcessor$LifecycleElement (org.springframework.beans.factory.annotation) invokeInitMethods:333, InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata (org.springframework.beans.factory.annotation) postProcessBeforeInitialization:157, InitDestroyAnnotationBeanPostProcessor (org.springframework.beans.factory.annotation) applyBeanPostProcessorsBeforeInitialization:415, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support) initializeBean:1786, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
跟着方法调用栈,我们来到 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization
@Override public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {
Object result = existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName); if (current == null) {
return result; } result = current; } return result; }
在这个方法,遍历 BeanPostProcessors 集合并执行每个 BeanPostProcessor 的 postProcessBeforeInitialization(...)
方法。
**那么 getBeanPostProcessors()
中的内容又是在什么时候放进去的呢?都有哪些内容?**可以通过 AnnotationConfigUtils
和 CommonAnnotationBeanPostProcessor
查找,这里就不再赘述了。
查找 applyBeanPostProcessorsBeforeInitialization(...)
的调用者,来到org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean); return null; }, getAccessControlContext()); } else {
invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try {
invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) {
throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
顾名思义,在这个方法中对 Bean 进行初始化。是在被注入前一定要经过的过程,到这里被 @PostConstruct
标注的方法执行已经完成了。至于这个方法谁调用可以自己查看调用栈。
init-method、afterPropertiesSet()
的调用细心的朋友可能已经发现了在 initializeBean(...)
中有调用到一个叫做 invokeInitMethods(...)
的方法。
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd) throws Throwable {
boolean isInitializingBean = (bean instanceof InitializingBean); if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((InitializingBean) bean).afterPropertiesSet(); return null; }, getAccessControlContext()); } catch (PrivilegedActionException pae) {
throw pae.getException(); } } else {
((InitializingBean) bean).afterPropertiesSet(); } } if (mbd != null && bean.getClass() != NullBean.class) {
String initMethodName = mbd.getInitMethodName(); if (StringUtils.hasLength(initMethodName) && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd); } } }
BeanDefinition是Bean定义的一个抽象。类似于在Java中存在Class类用于描述一个类,里面有你定义的 Bean 的各种信息。
在第4行,判断是不是 InitializingBean
,如果是的话会进行类型强转,然后调用 afterPropertiesSet()
。
在第26行,获得到自定义初始化方法的名字,然后在第30行调用 invokeCustomInitMethod
执行完成。
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean); return null; }, getAccessControlContext()); } else {
invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try {
invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) {
throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
initializeBean(...)
方法中,先执行 applyBeanPostProcessorsBeforeInitialization(...)
在执行 invokeInitMethods(...)
。
而 applyBeanPostProcessorsBeforeInitialization(...)
会执行被 @PostConstruct
标注的方法,invokeInitMethods(...)
会执行 afterPropertiesSet()
和自定义的初始化方法,并且 afterPropertiesSet()
在自定义的初始化方法之前执行,所以它们之间的执行顺序是:
@PostConstruct > afterPropertiesSet() > initMethod()
今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
上一篇
已是最后文章
下一篇
已是最新文章