关于@PostConstruct注解的理解
一 @PostConstruct注解的来由
一 构造方法和@Autowired注解
一般情况下我们大多用@Autowired
来完成某个类中的属性的注入。
@Autowired这个注解在构造方法执行后执行,以如下为例:就是在通过构造方法生成FileTaskExecutor
和FileTaskHandlerFactory
这两个对象后,再把生成的这个FileTaskHandlerFactory
对象赋值到FileTaskExecutor
中的fileTaskHandlerFactory
属性上。
有点类似set方法。
@Component("backendFileTaskExecutor")
public class FileTaskExecutor {
@Autowired
private FileTaskHandlerFactory fileTaskHandlerFactory;
}
二 @PostConstruct注解
1 从需求方面讲解@PostConstruct注解的来由
@Autowired
这个注解能解决一部分复杂功能的属性的赋值,当时对于一些比较零散的初始值的创建,用@Autowired
这个注解就有点多余了,因为像如下:BlockingQueue<FileTaskDTO>,Executor ,Limiter ,Map<Long, FileTaskDTO>
这些属性我只想简单的new一个对象或是赋值一个固定值,这个时候我们还要单独的创建一个类(这个类里面单单只是new一个对象,或者设置一个固定值)然后再用@Autowired
注入属性,这样操作就有点鸡肋了。
@Component("backendFileTaskExecutor")
public class FileTaskExecutor {
@Autowired
private FileTaskHandlerFactory fileTaskHandlerFactory;
private BlockingQueue<FileTaskDTO> taskQueue;
private Executor executor;
private Limiter limiter;
private Map<Long, FileTaskDTO> handlingTask;
@PostConstruct
public void initParams() {
taskQueue = new ArrayBlockingQueue<>(MAX_POOL_TASK_SIZE);
handlingTask = new ConcurrentHashMap<>();
limiter = new Limiter(configService.getMaxPermitUsers(), configService.getMaxPermitPerUserTasks());
executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
executor.execute(new Boss());
cleanTempFile();
}
}
所以@PostConstruct这个注解就诞生了,它就是用来处理在@Autowired注入属性后init()方法之前,对一些零散的属性进行赋值的注解。
如上面被@PostConstruct
修饰的的initParams()
方法。
2 @PostConstruct
-
除了拦截器这个特殊情况以外,其他情况都不允许有参数,否则spring框架会报IllegalStateException;而且返回值要是void,但实际也可以有返回值,至少不会报错,只会忽略
-
方法随便你用什么权限来修饰,public、protected、private都可以,反正功能是由反射来实现
-
方法不可以是static的,但可以是final的
所以,综上所述,在spring项目中,在一个bean的初始化过程中,方法执行先后顺序为
Constructor > @Autowired > @PostConstruct
先执行完构造方法,再注入依赖,最后执行初始化操作,所以这个注解就避免了一些需要在构造方法里使用依赖组件的尴尬。
3 其它将属性注入bean对象的方法
- 定义静态常量。
- Constructor
- @Autowired
@PostConstruct
注解- 实现
InitializingBean
接口重写afterPropertiesSet()
方法 - 实现
CommandLineRunner
或者ApplicationRunner
接口,他们在容器启动后启动
值得注意的是第4个是在tomcat服务启动之后才开始的。第3个是在spring容器启动之后,bean对象的构造方法完成后启动的。
他们具有如下关系:
spring容器启动 > Constructor > @Autowired > @PostConstruct > InitializingBean > CommandLineRunner或者
ApplicationRunner`接口
注意:bean
对象的初始化是挨个进行的(上一个完成才能进行下一个),如果某个bean
对象中的@PostConstruct
方法内的逻辑处理过长就会导致spring
的启动时间边长,因为只有在所有的bean对象初始化完成之后springBoot
才会打开端口提供服务。
如果出现如上问题的化可以采用实现CommandLineRunner
或者ApplicationRunner
接口的方法来注入一些数据,因为这一步是在springboot启动完成之后在运行的