前面说,在Spring管理Bean生命周期的过程中,可以自定义初始化及销毁方法,主要有@Bean注解中加入init-method和destroy-method属性的方式、还有Spring提供的InitializingBean和DisposableBean接口的方式。那么在Java规范中,也提供类似这样的方式,就是@PostConstruct和@PreDestroy注解,意思是在对象创建之后和在对象销毁之前。
@PostConstruct
/**
* 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:
* <p>
* <ul>
* <li>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.</li>
* <li>The method defined on an interceptor class MUST HAVE one of the
* following signatures:
* <p>
* void <METHOD>(InvocationContext)
* <p>
* Object <METHOD>(InvocationContext) throws Exception
* <p>
* <i>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.</i>
* </li>
* <li>The method defined on a non-interceptor class MUST HAVE the
* following signature:
* <p>
* void <METHOD>()
* </li>
* <li>The method on which PostConstruct is applied MAY be public, protected,
* package private or private.</li>
* <li>The method MUST NOT be static except for the application client.</li>
* <li>The method MAY be final.</li>
* <li>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.</li></ul>
* @since Common Annotations 1.0
* @see javax.annotation.PreDestroy
* @see javax.annotation.Resource
*/
@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PostConstruct {
}
PostConstruct注释用于在完成依赖注入以执行任何初始化之后需要执行的方法。必须在类投入服务之前调用此方法。支持依赖注入的所有类都必须支持此批注。
@PreDestroy
/**
* The PreDestroy annotation is used on methods as a callback notification to
* signal that the instance is in the process of being removed by the
* container. The method annotated with PreDestroy is typically used to
* release resources that it has been holding. This annotation MUST be
* supported by all container managed objects that support PostConstruct
* except the application client container in Java EE 5. The method on which
* the PreDestroy annotation is applied MUST fulfill all of the following
* criteria:
* <p>
* <ul>
* <li>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.</li>
* <li>The method defined on an interceptor class MUST HAVE one of the
* following signatures:
* <p>
* void <METHOD>(InvocationContext)
* <p>
* Object <METHOD>(InvocationContext) throws Exception
* <p>
* <i>Note: A PreDestroy 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
* PreDestroy interceptor method returns a value, it is ignored by
* the container.</i>
* </li>
* <li>The method defined on a non-interceptor class MUST HAVE the
* following signature:
* <p>
* void <METHOD>()
* </li>
* <li>The method on which PreDestroy is applied MAY be public, protected,
* package private or private.</li>
* <li>The method MUST NOT be static.</li>
* <li>The method MAY be final.</li>
* <li>If the method throws an unchecked exception it is ignored except in the
* case of EJBs where the EJB can handle exceptions.</li>
* </ul>
*
* @see javax.annotation.PostConstruct
* @see javax.annotation.Resource
* @since Common Annotations 1.0
*/
@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PreDestroy {
}
PreDestroy注释在方法上用作回调通知,以表示实例正在被容器移除。用PreDestroy注释的方法通常用于释放它一直持有的资源。
自定义Bean,添加@PostConstruct和@PreDestroy注解
@Component
public class Student {
public Student() {
System.out.println("Student 构造器");
}
@PostConstruct
public void init() {
System.out.println("Student 对象创建之后");
}
@PreDestroy
public void destroy() {
System.out.println("Student 对象销毁之前");
}
}
测试
@Test
public void testBean() {
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(MainConfig.class);
System.out.println("容器创建完成");
//关闭容器
applicationContext.close();
System.out.println("容器关闭");
}
Student 构造器
Student 对象创建之后
容器创建完成
......
Student 对象销毁之前
容器关闭
至于@PostConstruct和@PreDestroy的定义,Java中并没有解释为初始化和销毁,顾名思义,PostConstruct在构造器之后,PreDestroy在销毁之前,实际上在Spring管理Bean的生命周期中,@PostConstruct和@PreDestroy可以自定义的管理Bean的初始化和销毁这两个阶段。
在Spring中Constructor、@Autowired、@PostConstruct的执行顺序
其实从依赖注入的字面意思就可以知道,要将对象p注入到对象a,那么首先就必须得生成对象p与对象a,才能执行注入。所以,如果一个类A中有个成员变量p被@Autowired注解,那么@Autowired注入是发生在A的构造方法执行完之后的。
如果想在生成对象时候完成某些初始化操作,而偏偏这些初始化操作又依赖于依赖注入,那么就无法在构造函数中实现。为此,可以使用@PostConstruct注解一个方法来完成初始化,@PostConstruct注解的方法将会在依赖注入完成后被自动调用。
Constructor >> @Autowired >> @PostConstruct