1、场景
Spring-Bean初始化操作的额外操作,比如需在Spring加载完成阶段,添加其他的一些功能,或者需要运行某些特殊的方法脚本。
比如完成下述代码的示例:
package com.im;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ImApplication {
public static void main(String[] args) {
SpringApplication.run(ImApplication.class, args);
System.out.println("运行方法1");
System.out.println("运行方法2");
System.out.println("运行方法3");
System.out.println("运行方法4");
}
}
运行结果:
输入图片说明
这段代码的意思就是,在加载玩springbean后,期望运行,方法1、方法2、方法3、方法4,四个方法而且顺序不变,那么此时的代码这么写肯定是可行的但是可能让人觉着不太美观,因为代码块可能很大,很杂,一个优秀的方法代码逻辑----功能单一,一个方法就围绕一个功能来展开,而不可以一个方法实现多个功能,这样的方法不便于维护,也没有可读性。
2、使用CommandLineRunner接口来解决上述的问题
package com.im;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@SpringBootApplication
public class ImApplication {
public static void main(String[] args) {
SpringApplication.run(ImApplication.class, args);
}
}
@Component
@Order(1)
class Function1 implements CommandLineRunner{
@Override
public void run(String... args) throws Exception {
System.out.println("运行方法1");
}
}
@Component
@Order(2)
class Function2 implements CommandLineRunner{
@Override
public void run(String... args) throws Exception {
System.out.println("运行方法2");
}
}
@Component
@Order(3)
class Function3 implements CommandLineRunner{
@Override
public void run(String... args) throws Exception {
System.out.println("运行方法3");
}
}
@Component
@Order(4)
class Function4 implements CommandLineRunner{
@Override
public void run(String... args) throws Exception {
System.out.println("运行方法4");
}
}
运行结果:
个人认为,这种写法是比较优秀的写法,方法功能以组件的形式隔离开来,将一个后置方法一组件的形式开发,便于功能隔离,而且代码直观,便于我们维护和扩展。
3、另外一种形式,@PostConstruct
@PostConstruct源码:
/*
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
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:
* <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注解使用在方法上,一般在依赖注入完成之后才开始执行其标识的方法的初始化。这个方法必须在类注入之前被调用。这个注解所支持的类必须支持依赖注入,这个被标注的方法调用时甚至不需要任何资源的注入(他本身就是在bean注入之前的调用的,所以此时的bean还尚未初始化好),被该注解注释的方法必须满足如下的标准:
•PostConstruct拦截器方法不能抛出applicationexceptions,但是如果相同的拦截器方法除了生命周期事件之外插入onbusiness或timeout方法,它也可以被声明为抛出包括java.lang.Exception的已检查异常。如果aPostConstruct拦截器方法返回一个值,则容器会忽略它。
•在非拦截器类上定义的方法必须具有以下签名:
void <METHOD>()
•应用PostConstruct的方法可以是公共的,受保护的,包私有的或私有的。
•除应用程序客户端外,方法不能是静态的。
•方法可能是最终的。
•如果方法抛出未经检查的异常,则除了在EJB可以处理异常并且从中恢复异常的EJB的情况下,该类不能被置于intoservice中。
从以下版本开始:Common Annotations 1.0参见:javax.annotation.PreDestroyjavax.annotation.Resource
3、两个的区别:
1、CommandLineRunner的init()实在spring初始化完毕后执行的,即为服务初始化的最后一步操作
而@postConstruct的操作实在bean依赖注入之前的,相当于spring的容器初始化前的操作。
对读者:
初次了解,可能有些不对的地方,希望能够查漏补缺,如有错误的描述理解,望得到指示。
网友评论