@PostConstruct注解详解
简介
javaEE5引入了@PostConstruct和@PreDestroy两个作用于Servlet生命周期的注解,实现Bean初始化之前和销毁之前的自定义操作
使用场景
在项目中主要是在Servlet初始化之前加载一些缓存数据等
API使用说明
PostConstruct 注释用于在依赖关系注入完成之后需要执行的方法上,以执行任何初始化。此方法必须在将类放入服务之前调用。支持依赖关系注入的所有类都必须支持此注释。即使类没有请求注入任何资源,用 PostConstruct 注释的方法也必须被调用。只有一个方法可以用此注释进行注释。应用 PostConstruct 注释的方法必须遵守以下所有标准:该方法不得有任何参数,除非是在 EJB 拦截器 (interceptor) 的情况下,根据 EJB 规范的定义,在这种情况下它将带有一个 InvocationContext 对象 ;该方法的返回类型必须为 void;该方法不得抛出已检查异常;应用 PostConstruct 的方法可以是 public、protected、package private 或 private;除了应用程序客户端之外,该方法不能是 static;该方法可以是 final;如果该方法抛出未检查异常,那么不得将类放入服务中,除非是能够处理异常并可从中恢复的 EJB。
特点:
1、只有一个非静态方法能使用此注解
2、被注解的方法不得有任何参数
3、被注解的方法返回值必须为void
4、被注解方法不得抛出已检查异常
5、此方法只会被执行一次
servlet执行流程
注意事项
使用此注解时会影响服务启动时间。服务启动时会扫描WEB-INF/classes的所有文件和WEB-INF/lib下的所有jar包。
@PostConstruct注解的用法
@PostConstruct是java5的时候引入的注解,指的是在项目启动的时候执行这个方法,也可以理解为在spring容器启动的时候执行,可作为一些数据的常规化加载,比如数据字典之类的。
被@PostConstruct修饰的方法会在服务器加载Servle的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行
也就是加载顺序
服务器加载Servlet -> servlet 构造函数的加载 -> postConstruct ->init(init是在service 中的初始化方法. 创建service 时发生的事件.) ->Service->destory->predestory->服务器卸载serlvet
那么问题:spring中Constructor、@Autowired、@PostConstruct的顺序
Constructor >> @Autowired >> @PostConstruct
依赖注入的字面意思就可以知道,要将对象p注入到对象a,那么首先就必须得生成对象p与对象a,才能执行注入。所以,如果一个类A中有个成员变量p被@Autowired注解,那么@Autowired注入是发生在A的构造方法执行完之后的。
@PostConstruct应用场景:
如果想在生成对象时候完成某些初始化操作,而偏偏这些初始化操作又依赖于依赖注入,那么就无法在构造函数中实现。为此,可以使用@PostConstruct注解一个方法来完成初始化,@PostConstruct注解的方法将会在依赖注入完成后被自动调用。
@PostConstructpublic void start() {try {int connect = producer.connect();if (connect == 0) {log.info("producer start success! groupName:{},namesrvAddr:{}", rocketMqProperties.getProducer().getGroupName(), rocketMqProperties.getNamesrvAddr());}} catch (MQException e) {e.printStackTrace();}
}@PreDestroypublic void stop() {try {if (producer != null) {producer.close();log.info("producer closed");}}catch (MQException a){a.printStackTrace();}
}
在最近的工作中,get到一个很实用的注解,分享给诸位。
痛点
做过微信或支付宝支付的童鞋,可能遇到过这种问题,就是填写支付结果回调,就是在支付成功之后,支付宝要根据我们给的地址给我们进行通知,通知我们用户是否支付成功,如果成功我们就要去处理下面相应的业务逻辑,如果在测试服务,那么这个回调地址我们就需要填写测试服务的,如果发布到线上那么我们就需要改成线上的地址。
针对上面的场景,我们一般都会通过如下的方式,进行一个动态配置,不需要每次去改,防止出现问题。
public class PayTest {@Value("${spring.profiles.active}")private String environment;public Object notify(HttpServletRequest request) {if ("prod".equals(environment)) {// 正式环境} else if ("test".equals(environment)) {// 测试环境}return "SUCCESS";}
}
上面的代码看起来没有一点问题,但是身为搬砖的我们咋可能这样搬,姿势不对呀!
问题:
扩展性太差,如果这个参数我们还需要在别的地方用到,那么我们是不是还要使用@Value的注解获取一遍,假如有天我们的leader突然说吗,test这个单词看着太low了,换个高端一点的,换成dev,那么我们是不是要把项目中所有的test都要改过来,如果少还好,要是很多,那我们怕不是凉了。
所以我们能不能将这些配置参数搞成一个全局的静态变量,这样的话我们直接饮用就好了,哪怕到时候真的要改,那我也只需要改动一处就好了。
注意大坑
有的朋友可能就比较自信了,那我直接加个static修饰下不就好了,如果你真是打算这样做,那你就准备卷好铺盖走人吧。直接加static获取到的值其实是一个null,至于原因,大家复习下类以及静态变量变量的加载顺序。
@PostConstruct注解
那么既然说出了问题,肯定就有解决方法,不然你以为我跟你玩呢。
首先这个注解是由Java提供的,它用来修饰一个非静态的void方法。它会在服务器加载Servlet的时候运行,并且只运行一次。
改造:
@Component
public class SystemConstant {public static String surroundings;@Value("${spring.profiles.active}")public String environment;@PostConstructpublic void initialize() {System.out.println("初始化环境...");surroundings = this.environment;}
}
结果:
我们可以看到在项目启动的时候进行了初始化
到这里我们已经可以拿到当前运行的环境是测试还是正式,这样就可以做到动态配置
最后想说
其实这个注解远不止这点用处,像我之前写的Redis工具类,我使用的是RedisTemplate操作Redis,导致写出来的方法没办法用static修饰,每次使用Redis工具类只能先注入到容器然后再调用,使用了这个注解就可以完美的解决这种尴尬的问题。代码如下。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;/*** @ClassName RedisUtil* @Description TODO* @Version 1.0*/
@Component
public class RedisUtil {private static RedisTemplate<Object, Object> redisTemplates;@Autowiredprivate RedisTemplate<Object, Object> redisTemplate;@PostConstructpublic void initialize() {redisTemplates = this.redisTemplate;}/*** 添加元素** @param key* @param value*/public static void set(Object key, Object value) {if (key == null || value == null) {return;}redisTemplates.opsForValue().set(key, value);}
}
@PostConstruct注解详解相关推荐
- Spring框架@PostConstruct注解详解
文章目录 前言 业务背景 通过依赖查找实现 `@PostConstruct`注解实现 @PostConstruct注解原理 `@PostConstruct`注解 `@PostConstruct`注解源 ...
- 26.SpringBoot事务注解详解
转自:https://www.cnblogs.com/kesimin/p/9546225.html @Transactional spring 事务注解 1.简单开启事务管理 @EnableTrans ...
- mybatis注解详解
mybatis注解详解 首 先当然得下载mybatis-3.0.5.jar和mybatis-spring-1.0.1.jar两个JAR包,并放在WEB-INF的lib目录下 (如果你使用maven,则 ...
- 开启注解缓存_Spring Boot 2.x基础教程:进程内缓存的使用与Cache注解详解
随着时间的积累,应用的使用用户不断增加,数据规模也越来越大,往往数据库查询操作会成为影响用户使用体验的瓶颈,此时使用缓存往往是解决这一问题非常好的手段之一.Spring 3开始提供了强大的基于注解的缓 ...
- spring-boot注解详解(一)
spring-boot注解详解(一) @SpringBootApplication @SpringBootApplication = (默认属性)@Configuration + @EnableAut ...
- Spring零配置之@Configuration注解详解
转载自 Spring零配置之@Configuration注解详解 @Configuration介绍 Spring3.0之前要使用Spring必须要有一个xml配置文件,这也是Spring的核心文件,而 ...
- Spring Boot注解详解
文章目录 使用注解的优势 注解详解(配备了完善的释义) 注解列表如下 JPA注解 springMVC相关注解 全局异常处理 项目中具体配置解析和使用环境 使用注解的优势 采用纯java代码,不在需要配 ...
- 【SpringBoot 】SpringBoot注解详解
[SpringBoot ]SpringBoot注解详解 一.注解(annotations)列表 @SpringBootApplication:包含了@ComponentScan.@Configura ...
- java method 注解_JAVA 注解详解及简单实例
JAVA 注解详解及简单实例 何为注解 注解(Annotation)又称为元数据,在JDK1.5后引入,它的作用是: 生成文档 这是注解的原始用途,可以通过注解生成JavaDoc文档 跟踪代码的依赖 ...
最新文章
- 我们每天都在做无用功?
- Java字符串那些事儿
- oracle乘法运算,oracle实现相乘话语
- maven打包跳过测试
- R语言与虚拟变量模型
- python tkinter listbox_Python3 tkinter基础 Listbox for+insert 将list中元素导入listbox中
- Java基础学习总结(48)——Java 文档注释
- 什么是Apache Flink
- Serverless Computing:现状与基础知识
- 在有的公司,高手遍地走,天才不如狗
- 如何批量将 Json 转为 Excel 格式
- Excel如何查找重复内容
- 【总结整理】高德LBS开放平台学习
- Android权限请求第三方库的比较
- 吃什么怎么吃关系着民族的命运
- http和tcp区别
- 2018-8-10-三种方式设置特定设备UWP-XAML-view
- 微信公众平台开发-分享接口的实现
- 游戏设计模式---命令模式
- Yapi集成到Jenkins实现接口自动化—最全面的流程讲解
热门文章
- 图形的装饰教案计算机,《电脑图案设计师》教案教学设计
- linux安装卸载mysql,Linux6 系列 安装、卸载mysql
- java如何解决高并发症,JAVA线上故障紧急处理详细过程!
- 楚留香ai人脸识别_戴口罩居然也能人脸识别?这些AI黑科技真的藏不住了.........
- setuptools安装_在Ubuntu 18.04系统上安装ERPNext ERP
- linux需要什么基础,学linux需要什么基础?
- duration java_Java Duration类| toMinutes()方法与示例
- 面试官 | AJAX请求为什么不安全?
- AndroidStudio使用入门
- Yolov5系列AI常见数据集(1)车辆,行人,自动驾驶,人脸,烟雾