PostConstruct注解原理说明

首先我们知道这个注解的作用是:在类被初始化的时候 会执行被@PostConstruct注解的方法。
那它到底是怎么工作的,什么时候被执行,都有什么限制规则,会引起什么问题呢 ?
本着一切都要验证的原则,开始解剖,但是从哪里开始下刀呢?既然是类的初始化,自然是想到了BeanFactory这个庞大的工厂,那我们就从spring初始化bean的入口开刀吧。

bean被初始化的过程了解过spring运行原理的应该都知道了,这里简单说明一下:

扫描包找到包含注解的bean,放入BeanFactory,等待被初始化,执行初始化生成bean实例放入BeanFactory。

首先我们看BeanFactory,随便找一个实现类AbstractAutowireCapableBeanFactory进去


image.png

我们知道bean被实例化有两种方式,一种是注入的时候就实例化,一种是第一次用的时候才实例化(懒加载)。先看autowireBean方法

public void autowireBean(Object existingBean) {
        RootBeanDefinition bd = new RootBeanDefinition(ClassUtils.getUserClass(existingBean));
        bd.setScope("prototype");
        bd.allowCaching = ClassUtils.isCacheSafe(bd.getBeanClass(), this.getBeanClassLoader());
        BeanWrapper bw = new BeanWrapperImpl(existingBean);
        this.initBeanWrapper(bw);
        >>>this.populateBean(bd.getBeanClass().getName(), bd, bw);>>>
    }

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
  ...
  if (mbd.getResolvedAutowireMode() == 1 || mbd.getResolvedAutowireMode() == 2) {
                    MutablePropertyValues newPvs = new MutablePropertyValues((PropertyValues)pvs);
                    if (mbd.getResolvedAutowireMode() == 1) {
                       >>>this.autowireByName(beanName, mbd, bw, newPvs);
                    }

                    if (mbd.getResolvedAutowireMode() == 2) {
                        >>>this.autowireByType(beanName, mbd, bw, newPvs);
                    }

                    pvs = newPvs;
                }
  ...
}
protected void autowireByName(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
   ...
   if (this.containsBean(propertyName)) {
                >>>Object bean = this.getBean(propertyName);
                pvs.add(propertyName, bean);
                this.registerDependentBean(propertyName, beanName);
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Added autowiring by name from bean name '" + beanName + "' via property '" + propertyName + "' to bean named '" + propertyName + "'");
                }
            }
  ...
}
public Object getBean(String name) throws BeansException {
        >>>return this.doGetBean(name, (Class)null, (Object[])null, false);
}
protected  T doGetBean(String name, Class requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException {
...
if (mbd.isSingleton()) {
                    sharedInstance = this.getSingleton(beanName, new ObjectFactory() {
                        public Object getObject() throws BeansException {
                            try {
                                >>>return AbstractBeanFactory.this.createBean(beanName, mbd, args);
                            } catch (BeansException var2) {
                                AbstractBeanFactory.this.destroySingleton(beanName);
                                throw var2;
                            }
                        }
                    });
                    bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }
...
}

protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
...
  >>>beanInstance = this.doCreateBean(beanName, mbdToUse, args);
...
}

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
...
  this.populateBean(beanName, mbd, instanceWrapper);//添加依赖bean(如autowired相关实例)
  if (exposedObject != null) {
    >>>exposedObject = this.initializeBean(beanName, exposedObject, mbd);//初始化当前bean
  }
...
}

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    // ...

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        // 初始化前置处理
        >>>wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
        // 调用初始化方法
        invokeInitMethods(beanName, wrappedBean, mbd);
    } catch (Throwable ex) {
        // ...
    }
    if (mbd == null || !mbd.isSynthetic()) {
        // 初始化后置处理
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
}

public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {
        Object result = existingBean;
        Iterator var4 = this.getBeanPostProcessors().iterator();

        do {
            if (!var4.hasNext()) {
                return result;
            }

            BeanPostProcessor beanProcessor = (BeanPostProcessor)var4.next();
            >>>result = beanProcessor.postProcessBeforeInitialization(result, beanName);
        } while(result != null);

        return result;
    }



到这里可以看到,在初始化bean的时候,先循环所有的BeanPostProcessor执行postProcessBeforeInitialization 方法;再调用 bean的初始化;最后执行applyBeanPostProcessorsAfterInitialization方法。而我们的@PostConstruct就是在第一步中的一个 BeanPostProcessor 里处理的。

我们进到BeanPostProcessor里面可以看到它有很多实现。


image.png

而位于spring-beans包下的org.springframework.beans.factory.annotaion.InitDestroyAnnotationBeanPostProcessor成功的引起了我们的怀疑,那就先进去看看吧。

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        //先找到所有待执行方法
        >>>>InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata metadata = this.findLifecycleMetadata(bean.getClass());

        try {
            //通过反射调用相关方法执行
            metadata.invokeInitMethods(bean, beanName);
            return bean;
        } catch (InvocationTargetException var5) {
            throw new BeanCreationException(beanName, "Invocation of init method failed", var5.getTargetException());
        } catch (Throwable var6) {
            throw new BeanCreationException(beanName, "Failed to invoke init method", var6);
        }
    }

private InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata findLifecycleMetadata(Class clazz) {
        if (this.lifecycleMetadataCache == null) {
            >>>> return this.buildLifecycleMetadata(clazz);
        } else {
            InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata metadata = (InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata)this.lifecycleMetadataCache.get(clazz);
            if (metadata == null) {
                synchronized(this.lifecycleMetadataCache) {
                    metadata = (InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata)this.lifecycleMetadataCache.get(clazz);
                    if (metadata == null) {
                        metadata = this.buildLifecycleMetadata(clazz);
                        this.lifecycleMetadataCache.put(clazz, metadata);
                    }

                    return metadata;
                }
            } else {
                return metadata;
            }
        }
    }

private InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata buildLifecycleMetadata(final Class clazz) {
        final boolean debug = this.logger.isDebugEnabled();
        LinkedList initMethods = new LinkedList();
        LinkedList destroyMethods = new LinkedList();
        Class targetClass = clazz;

        do {
            final LinkedList currInitMethods = new LinkedList();
            final LinkedList currDestroyMethods = new LinkedList();
            //反射获取所有方法,基于initAnnotationType和 destroyAnnotationType 分别处理。
            ReflectionUtils.doWithLocalMethods(targetClass, new MethodCallback() {
                public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
                    if (InitDestroyAnnotationBeanPostProcessor.this.initAnnotationType != null && method.getAnnotation(InitDestroyAnnotationBeanPostProcessor.this.initAnnotationType) != null) {
                        InitDestroyAnnotationBeanPostProcessor.LifecycleElement element = new InitDestroyAnnotationBeanPostProcessor.LifecycleElement(method);
                        currInitMethods.add(element);
                        if (debug) {
                            InitDestroyAnnotationBeanPostProcessor.this.logger.debug("Found init method on class [" + clazz.getName() + "]: " + method);
                        }
                    }

                    if (InitDestroyAnnotationBeanPostProcessor.this.destroyAnnotationType != null && method.getAnnotation(InitDestroyAnnotationBeanPostProcessor.this.destroyAnnotationType) != null) {
                        currDestroyMethods.add(new InitDestroyAnnotationBeanPostProcessor.LifecycleElement(method));
                        if (debug) {
                            InitDestroyAnnotationBeanPostProcessor.this.logger.debug("Found destroy method on class [" + clazz.getName() + "]: " + method);
                        }
                    }

                }
            });
           //找到所有的初始化方法 放在initMethods中
            >>>>initMethods.addAll(0, currInitMethods);
            destroyMethods.addAll(currDestroyMethods);
            targetClass = targetClass.getSuperclass();
        } while(targetClass != null && targetClass != Object.class);

        return new InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata(clazz, initMethods, destroyMethods);
    }

那么 initAnnotationType 都有哪些呢

public CommonAnnotationBeanPostProcessor() {
    setOrder(Ordered.LOWEST_PRECEDENCE - 3);
    setInitAnnotationType(PostConstruct.class);
    setDestroyAnnotationType(PreDestroy.class);
    ignoreResourceType("javax.xml.ws.WebServiceContext");
}

CommonAnnotationBeanPostProcessor 是 继承自InitDestroyAnnotationBeanPostProcessor的,到这里,我们可以知道。跟我们前面的猜测一样,解析过程是通过反射来获取@PostConstruct注解的方法,并放到initMethods集合里面去。然后再通过反射调用这个集合里面的所有方法,完成初始化行为的。

最后再通过PostConstruct注解类源码看看它的使用注意事项:

package javax.annotation;

import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;

/**
 * The PostConstruct annotation is used on a method that needs to be executed
 * after dependency injection is done to perform any initialization. This
 * method MUST be invoked before the class is put into service. This
 * annotation MUST be supported on all classes that support dependency
 * injection. The method annotated with PostConstruct MUST be invoked even
 * if the class does not request any resources to be injected. Only one
 * method can be annotated with this annotation. The method on which the
 * PostConstruct annotation is applied MUST fulfill all of the following
 * criteria:
 * 

*

    *
  • The method MUST NOT have any parameters except in the case of * interceptors in which case it takes an InvocationContext object as * defined by the Interceptors specification.
  • *
  • The method defined on an interceptor class MUST HAVE one of the * following signatures: *

    * void <METHOD>(InvocationContext) *

    * Object <METHOD>(InvocationContext) throws Exception *

    * Note: A PostConstruct interceptor method must not throw application * exceptions, but it may be declared to throw checked exceptions including * the java.lang.Exception if the same interceptor method interposes on * business or timeout methods in addition to lifecycle events. If a * PostConstruct interceptor method returns a value, it is ignored by * the container. *

  • *
  • The method defined on a non-interceptor class MUST HAVE the * following signature: *

    * void <METHOD>() *

  • *
  • The method on which PostConstruct is applied MAY be public, protected, * package private or private.
  • *
  • The method MUST NOT be static except for the application client.
  • *
  • The method MAY be final.
  • *
  • If the method throws an unchecked exception the class MUST NOT be put into * service except in the case of EJBs where the EJB can handle exceptions and * even recover from them.
* @since Common Annotations 1.0 * @see javax.annotation.PreDestroy * @see javax.annotation.Resource */ @Documented @Retention (RUNTIME) @Target(METHOD) public @interface PostConstruct { }

至此,针对@PostConstruct总结如下:
1.作用在类的方法上,在依赖注入完成之后初始化方法,这个方法是在类被放入服务之前被调用,调用顺序是 构造函数->依赖注入->PostConstruct
2.所有支持依赖注入的类都要支持这个方法。
3.只有一个方法可以加这个注解,虽然PostConstruct官方的类上有这个描述,但真实运行效果上看的话,可以给多个方法加,而且都可以被执行。
4.被PostContruct修饰的方法要满足以下几点:
-方法不能有任何参数,除非是 拦截器中的 InvocationContext对象。
-方法不能是静态的,除非是启动类。
-方法是final的, 不能被重写。
-如果方法对应的类是容器中的类,不要抛出UncheckedException

你可能感兴趣的:(PostConstruct注解原理说明)