问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

@PostConstruct注解详细分析,结合案例和使用场景(保姆级教程)

创作时间:
作者:
@小白创作中心

@PostConstruct注解详细分析,结合案例和使用场景(保姆级教程)

引用
CSDN
1.
https://m.blog.csdn.net/Andrew_Chenwq/article/details/144382325

@PostConstruct注解是Java中用于生命周期管理的注解,主要用于执行一些初始化逻辑。本文将详细介绍@PostConstruct注解的使用场景和具体案例,帮助读者更好地理解和应用这一注解。

@PostConstruct 注解

从 Java 9 开始,javax.annotation.PostConstruct 等注解被标记为过时(deprecated),并在后续的 Java 版本中可能会被移除。因此,如果你在使用 Java 9 或更高版本,并且你的项目不是 Java EE 项目,你可能需要考虑使用其他方式来代替 @PostConstruct 注解,比如直接在构造函数中执行初始化操作,或者使用 Spring 的@Bean 注解配合 initMethod 属性来指定初始化方法。

然而,在Spring框架中,@PostConstruct 注解仍然是被支持和推荐的。

一、什么是 @PostConstruct 注解

  • @PostConstruct 是 java 中用于 生命周期管理的注解,是 java 自己的 的注解,不是 spring 的。
  • 当应用程序加载时,@PostConstruct 标注的方法会在 类实例化 并 完成依赖注入 后 自动调用。
  • 作用:主要作用是执行一些 初始化逻辑,例如预加载资源、启动后台任务、校验依赖注入等。
  • 执行时机:首先创建对象(实例化Bean),依赖注入完成(属性赋值),@PostConstruct 标记的方法被自动调用。
  • 注意:
  • 只能标记在 非静态的 void() 方法
  • 每个类中最多只能有一个 @PostConstruct 注解。
  • 如果标注的方法抛出异常,容器会报告错误,可能终止应用程序的启动。
  • 标记的方法只执行一次。
  • 如果想在生成对象时完成某些初始化操作,而偏偏这些初始化操作又依赖于依赖注入,那么就无法在构造函数中实现。为此,可以使用 @PostConstruct 注解来完成。

二、使用案例

1. 数据预热

使用 Redis 进行的数据预热,需要项目启动以后,触发第一次调用才能生成缓存,而利用 @PostConstruct 注解能让预热数据在 Bean 初始化阶段完成,比 Redis 更早。

public interface DataWarmingService {
    String data();
}
@Service
public class DataWarmingServiceImpl implements DataWarmingService {
    @Override
    public String data() {
        System.out.println("执行生成数据的方法");
        return "Data Warming";
    }
}
@Configuration
public class DataWarmingConfig {
    @Autowired
    private DataWarmingService dataWarmingService;

    //定义属性:模拟需要预热的数据
    private static String dataWarm;

    @PostConstruct
    public void init(){
        System.out.println("Autowired 加载完成!");
        dataWarm = dataWarmingService.data();
        System.out.println(dataWarm);
    }
}

启动启动类,运行结果:

分析:

  1. 创建实例:
    DataWarmingServiceImpl 是实现类,被标注为 @Service,Spring 会将其注册为 Bean。DataWarmingConfig 加了 @Configuration 注解,然后也会创建实例。

  2. 依赖注入:
    Spring 发现 DataWarmingConfig 中的 @Autowired 注解,自动将 DataWarmingServiceImpl 注入到 dataWarmingService 属性中。

  3. 调用 @PostConstruct 方法:Spring 在依赖注入完成后,检查 DataWarmingConfig 类中是否存在 @PostConstruct 标注的方法。

2. 加载配置文件

使用 @PostConstruct 将 @Value 注入的实例变量值 赋给 静态变量,可以解决 static 无法直接与 @Value 注解联动的问题。

具体分析:
@Value 注解的特性:@Value 注解修饰的常量不能是静态的,否则会 null,因为 static 的加载在 @Value 之前。因此它只能注入到 实例变量 或 实例方法 中,而不能直接注入到静态变量。

@Component
public class ConstantUtil {
    
    // 使用 @Value 注解从配置文件中注入值
    @Value("${app.name:defaultAppName}") // 如果配置文件中没有 app.name,默认值为 "defaultAppName"
    private String appName;

    // 定义一个静态变量用于全局访问
    private static String STATIC_APP_NAME;

    @PostConstruct
    public void init() {
        STATIC_APP_NAME = this.appName;
    }
}
@Test    
public void test() {
    System.out.println(STATIC_APP_NAME);
}
//输出:defaultAppName(假设这里没有配置文件)

分析:

  1. 类加载阶段:
  • 类 ConstantUtil 被加载,静态变量 STATIC_APP_NAME 被初始化为 null。
  • @Value 注解暂时未生效,因为 Bean 尚未被实例化。
  1. Bean 实例化、依赖注入阶段:
  • Spring 扫描到 @Component 标注的类,将其实例化为 Bean。
  • @Value 注入配置文件中的 app.name 值到实例变量 appName。
  1. @PostConstruct 方法执行:
  • Spring 在完成依赖注入后调用 init() 方法。
  • 方法内,将实例变量 appName 的值赋给静态变量 STATIC_APP_NAME。

再看个例子:

@Component
public class LoadConfig {
    @Value("${server.port:abc}")
    private String port;

    // 模拟静态常量
    public static String server_port;

    @PostConstruct
    public void construct() {
        System.out.println("Before PostConstruct:" + server_port);
        server_port = port;
        System.out.println("After PostConstruct:" + server_port);
    }
}

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号