Spring – @PostConstruct 和 @PreDestroy 注解与示例
Spring 是最流行的Java EE 框架之一。它是一个开源轻量级框架,允许Java EE 7 开发人员构建简单、可靠且可扩展的企业应用程序。该框架主要侧重于提供各种方法来帮助您管理业务对象。与Java数据库连接 (JDBC)、JavaServer Pages (JSP) 和Java Servlet 等经典Java框架和应用程序编程接口 (API) 相比,它使 Web 应用程序的开发更加容易。该框架使用各种新技术,如面向方面编程 (AOP)、普通Java对象 (POJO) 和依赖注入 (DI) 来开发企业应用程序。现在谈论 Spring Annotation
Spring Annotations are a form of metadata that provides data about a program. Annotations are used to provide supplemental information about a program. It does not have a direct effect on the operation of the code they annotate. It does not change the action of the compiled program.
所以发生的情况是,每当我们使用依赖注入配置 Spring Beans 时,有时我们希望确保在 bean 开始为客户端请求提供服务之前一切都正确初始化。同样,当 context 被销毁时,我们可能不得不关闭 spring bean 使用的一些资源。
Spring @PostConstruct 注解
所以一般来说,每当我们在 Spring Bean 中使用 @PostConstruct 注解来注解一个方法时,它都会在 Spring Bean 初始化之后执行。我们只能有一个使用@PostConstruct 注释的方法。此注解是 Common Annotations API 的一部分,也是 JDK模块 javax.annotation-api的一部分。
Spring @PreDestroy 注解
当我们使用 PreDestroy 注解对 Spring Bean 方法进行注解时,它会在 bean 实例从上下文中移除时被调用。请记住,如果您的 spring bean 范围是“原型”,那么它不会完全由 spring 容器管理,并且不会调用 PreDestroy 方法。如果有一个名为 shutdown 或 close 的方法,那么当 bean 被销毁时,spring 容器将尝试自动将它们配置为回调方法。
在项目中添加@PostConstruct 和@PreDestroy 注解
使用Java 9+ 的开发人员,@PostConstruct 和 @PreDestroy 注释都是Java EE 的一部分。由于Java EE 在Java 9 中已被弃用并在Java 11 中被删除,我们必须添加一个额外的依赖项才能使用这些注解:
A.如果您使用的是 Maven
javax.annotation
javax.annotation-api
1.3.2
B.如果手动添加jar
访问链接并在文件列中,您将看到 pom 和 jar。单击 jar,您的 jar 将被下载。通过配置构建将其作为外部 jar 添加到类路径中。您可以参考这篇文章将外部 JAR 文件添加到 IntelliJ IDEA 项目或参考这篇文章将外部 JAR 文件添加到 Eclipse 项目。
Note: If you are on Java 8 or the lower version, then you won’t have to perform the above stuff.
实现:我们将通过简单地创建一个 Spring JDBC 项目来解释 @PostConstruct 和 @PreDestroy 注解。所以我们先创建一个 Spring JDBC 项目。
Prerequisite: JDBC Tutorial
第 1 步:在您首选的 IDE(IntelliJ IDEA 或 Eclipse)中创建一个简单的Java项目。你可以参考这些文章:
- 在 IntelliJ IDEA 中创建第一个Java应用程序
- 如何为Java安装 Eclipse IDE?
第 2 步:在数据库中创建一些表。在本文中,我们使用了 MySQL 数据库。我们的 MySQL 数据库中已经存在以下数据。
所以这里的studentdb是我们的模式名, hostelstudentinfo是表名。同样,您可以创建自己的模式和表,并手动将一些数据放入该表中。
Tip: You can refer to these articles:
- How to Install MySQL on Windows?
- How to Install SQL Workbench For MySQL on Windows?
第 3 步:转到Java项目并创建一个名为StudentDAO的类,在该类中,我们将创建一个方法selectAllRows()来获取 MySQL 数据库中存在的所有数据。我们还将声明我们的四个最重要的属性,以将我们的Java程序与 MySQL 服务器连接起来。
- 司机
- 网址
- 用户
- 密码
例子:
Java
// Java Program to Illustrate StudentDAO class
// Importing required classes
import java.sql.*;
// Class
public class StudentDAO {
// Class data members
private String driver;
private String url;
private String userName;
private String password;
// Setter methods for
// Setter Injection
public void setDriver(String driver)
{
// This keyword refers to current instance itself
this.driver = driver;
}
// Setter
public void setUrl(String url) { this.url = url; }
// Setter
public void setUserName(String userName)
{
this.userName = userName;
}
// Setter
public void setPassword(String password)
{
this.password = password;
}
// Method
public void selectAllRows()
throws ClassNotFoundException, SQLException
{
System.out.println("Retrieving all student data..");
// Loading driver using forname() method
Class.forName(driver);
// Getting a connection
Connection con = DriverManager.getConnection(
url, userName, password);
// Executing a query
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(
"SELECT * FROM studentdb.hostelstudentinfo");
// Iterating over till condition holds true
while (rs.next()) {
int studentId = rs.getInt(1);
String studentName = rs.getString(2);
double hostelFees = rs.getDouble(3);
String foodType = rs.getString(4);
// Print statement
System.out.println(studentId + " " + studentName
+ " " + hostelFees + " "
+ foodType);
}
// Closing the connection
// using close() method
con.close();
}
}
XML
Java
// Java Program to Illustrate Application File
// Importing required classes
import java.sql.SQLException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
// Application class
public class Main {
// Main driver method
public static void main(String[] args)
throws SQLException, ClassNotFoundException
{
// Implementing Spring IoC
// using ApplicationContext
ApplicationContext context
= new ClassPathXmlApplicationContext(
"beans.xml");
// Getting the bean studentDAO
StudentDAO studentDAO = context.getBean(
"studentDAO", StudentDAO.class);
// Calling the method
studentDAO.selectAllRows();
}
}
Java
// Java Program Illustrating Method to Delete Student Record
public void deleteStudentRecord(int studentId)
throws ClassNotFoundException, SQLException
{
// Display message
System.out.println("Deleting student data..");
// Loading driver using forName() Method
Class.forName(driver);
// Getting a connection
Connection con = DriverManager.getConnection(
url, userName, password);
// Executing a query
Statement stmt = con.createStatement();
stmt.executeUpdate(
"delete from studentdb.hostelstudentinfo where Student_id = "
+ studentId);
System.out.println("Record Deleted with the ID "
+ studentId);
// Closing the connections
// using close() method
con.close();
}
Java
// Java Program Illustrating Method to Create StudentDB
// Connection
// Method
public void createStudentDBConnection()
throws ClassNotFoundException, SQLException
{
// Loading driver
Class.forName(driver);
// Getting a connection
con = DriverManager.getConnection(url, userName,
password);
// Executing a query
stmt = con.createStatement();
}
Java
// Java Program to Illustrate StudentDAO Class
// Importing required classes
import java.sql.*;
// Class
public class StudentDAO {
// Class data members
private String driver;
private String url;
private String userName;
private String password;
// Connection Object
Connection con;
// Statement Object
Statement stmt;
// Setter
public void setDriver(String driver)
{
this.driver = driver;
}
// Setter
public void setUrl(String url) { this.url = url; }
// Setter
public void setUserName(String userName)
{
this.userName = userName;
}
// Setter
public void setPassword(String password)
{
this.password = password;
}
// Creating connection
public void createStudentDBConnection()
throws ClassNotFoundException, SQLException
{
// Loading driver
Class.forName(driver);
// Getting a connection
con = DriverManager.getConnection(url, userName,
password);
// Executing query
stmt = con.createStatement();
}
// Method 1
public void selectAllRows()
throws ClassNotFoundException, SQLException
{
System.out.println("Retrieving all student data..");
// Create connection
createStudentDBConnection();
ResultSet rs = stmt.executeQuery(
"SELECT * FROM studentdb.hostelstudentinfo");
while (rs.next()) {
int studentId = rs.getInt(1);
String studentName = rs.getString(2);
double hostelFees = rs.getDouble(3);
String foodType = rs.getString(4);
System.out.println(studentId + " " + studentName
+ " " + hostelFees + " "
+ foodType);
}
// Closing the connection
closeConnection()
}
// Method 2
public void deleteStudentRecord(int studentId)
throws ClassNotFoundException, SQLException
{
System.out.println("Deleting student data..");
// Create connection
createStudentDBConnection();
stmt.executeUpdate(
"delete from studentdb.hostelstudentinfo where Student_id = "
+ studentId);
System.out.println("Record Deleted with the ID "
+ studentId);
// Close the connection
closeConnection();
}
// Method 3
// Close the connection
public void closeConnection() throws SQLException
{
con.close();
}
}
Java
@PostConstruct
public void createStudentDBConnection() throws ClassNotFoundException, SQLException {
// load driver
Class.forName(driver);
// get a connection
con = DriverManager.getConnection(url, userName, password);
// execute query
stmt = con.createStatement();
}
Java
@PostConstruct
public void init() throws SQLException, ClassNotFoundException {
createStudentDBConnection();
}
public void createStudentDBConnection() throws ClassNotFoundException, SQLException {
// load driver
Class.forName(driver);
// get a connection
con = DriverManager.getConnection(url, userName, password);
// execute query
stmt = con.createStatement();
}
Java
public void closeConnection() throws SQLException {
con.close();
}
@PreDestroy
public void destroy() throws SQLException {
closeConnection();
}
Java
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.sql.*;
public class StudentDAO {
private String driver;
private String url;
private String userName;
private String password;
// Connection Object
Connection con;
// Statement Object
Statement stmt;
public void setDriver(String driver) {
this.driver = driver;
}
public void setUrl(String url) {
this.url = url;
}
public void setUserName(String userName) {
this.userName = userName;
}
public void setPassword(String password) {
this.password = password;
}
@PostConstruct
public void init() throws SQLException, ClassNotFoundException {
createStudentDBConnection();
}
public void createStudentDBConnection() throws ClassNotFoundException, SQLException {
// load driver
Class.forName(driver);
// get a connection
con = DriverManager.getConnection(url, userName, password);
// execute query
stmt = con.createStatement();
}
public void selectAllRows() throws ClassNotFoundException, SQLException {
System.out.println("Retrieving all student data..");
ResultSet rs = stmt.executeQuery("SELECT * FROM studentdb.hostelstudentinfo");
while (rs.next()) {
int studentId = rs.getInt(1);
String studentName = rs.getString(2);
double hostelFees = rs.getDouble(3);
String foodType = rs.getString(4);
System.out.println(studentId + " " + studentName + " " + hostelFees + " " + foodType);
}
}
public void deleteStudentRecord(int studentId) throws ClassNotFoundException, SQLException {
System.out.println("Delete student data..");
stmt.executeUpdate("delete from studentdb.hostelstudentinfo where Student_id = " + studentId);
System.out.println("Record Deleted with the ID " + studentId);
}
public void closeConnection() throws SQLException {
con.close();
}
@PreDestroy
public void destroy() throws SQLException {
closeConnection();
}
}
XML
Java
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.sql.SQLException;
public class Main {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
// Using ApplicationContext tom implement Spring IoC
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// Get the bean studentDAO
StudentDAO studentDAO = context.getBean("studentDAO", StudentDAO.class);
// Calling the method
studentDAO.deleteStudentRecord(2);
studentDAO.selectAllRows();
}
}
第 4 步:现在我们必须将外部 JAR 文件添加到 IntelliJ IDEA 项目中。 JAR(Java Archive)是一种包文件格式,通常用于将许多Java类文件和相关的元数据和资源(文本、图像等)聚合到一个文件中,以在Java平台上分发应用程序软件或库。简而言之,JAR 文件是包含 .class 文件、音频文件、图像文件或目录的压缩版本的文件。我们必须将以下外部 jar 文件添加到我们的Java项目中
- 春天
- MySQL 连接器
您可以从以下链接下载 jar 文件:
- 春天:点击这里
- MySQL 连接器:单击此处
第 5 步:让我们在beans.xml文件中创建 StudentDAO 类的 bean,并通过 setter 注入来注入属性的值。你可以参考这篇文章 Spring – Injecting 字面量 Values By Setter Injection。下面是beans.xml文件的代码。
XML
第 6 步:创建 Main 类,让我们测试我们的应用程序是否运行良好。下面是Main 的代码。 Java文件。
Java
// Java Program to Illustrate Application File
// Importing required classes
import java.sql.SQLException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
// Application class
public class Main {
// Main driver method
public static void main(String[] args)
throws SQLException, ClassNotFoundException
{
// Implementing Spring IoC
// using ApplicationContext
ApplicationContext context
= new ClassPathXmlApplicationContext(
"beans.xml");
// Getting the bean studentDAO
StudentDAO studentDAO = context.getBean(
"studentDAO", StudentDAO.class);
// Calling the method
studentDAO.selectAllRows();
}
}
输出:可以看到我们已成功从 MySQL 数据库中获取数据。
Retrieving all student data..
1 Asish 300.5 Veg
2 Vicky 245.89 Non Veg
3 Anshul 123.67 Veg
Note: So what’s the problem with the above code? The problem is, suppose we want to define another method deleteStudentRecord(int studentId) in the StudentDAO class something like as shown in below example as follows:
例子
Java
// Java Program Illustrating Method to Delete Student Record
public void deleteStudentRecord(int studentId)
throws ClassNotFoundException, SQLException
{
// Display message
System.out.println("Deleting student data..");
// Loading driver using forName() Method
Class.forName(driver);
// Getting a connection
Connection con = DriverManager.getConnection(
url, userName, password);
// Executing a query
Statement stmt = con.createStatement();
stmt.executeUpdate(
"delete from studentdb.hostelstudentinfo where Student_id = "
+ studentId);
System.out.println("Record Deleted with the ID "
+ studentId);
// Closing the connections
// using close() method
con.close();
}
现在您可以看到我们必须一次又一次地编写一些代码行。然后想想如果假设我们要执行 100 种不同的操作,我们必须一次又一次地编写相同的代码。所以我们能做些什么。我们可以在方法中编写通用代码,然后调用该方法。我们可以在名为createStudentDBConnection()的方法中编写类似这样的内容
例子
Java
// Java Program Illustrating Method to Create StudentDB
// Connection
// Method
public void createStudentDBConnection()
throws ClassNotFoundException, SQLException
{
// Loading driver
Class.forName(driver);
// Getting a connection
con = DriverManager.getConnection(url, userName,
password);
// Executing a query
stmt = con.createStatement();
}
同样,我们也可以定义另一种方法来关闭连接。我们可以在名为closeConnection()的方法中编写类似这样的内容
public void closeConnection() throws SQLException
{
con.close();
}
我们可以像这样在 selectAllRows() 和 deleteStudentRecord() 中调用这些方法。
例子
Java
// Java Program to Illustrate StudentDAO Class
// Importing required classes
import java.sql.*;
// Class
public class StudentDAO {
// Class data members
private String driver;
private String url;
private String userName;
private String password;
// Connection Object
Connection con;
// Statement Object
Statement stmt;
// Setter
public void setDriver(String driver)
{
this.driver = driver;
}
// Setter
public void setUrl(String url) { this.url = url; }
// Setter
public void setUserName(String userName)
{
this.userName = userName;
}
// Setter
public void setPassword(String password)
{
this.password = password;
}
// Creating connection
public void createStudentDBConnection()
throws ClassNotFoundException, SQLException
{
// Loading driver
Class.forName(driver);
// Getting a connection
con = DriverManager.getConnection(url, userName,
password);
// Executing query
stmt = con.createStatement();
}
// Method 1
public void selectAllRows()
throws ClassNotFoundException, SQLException
{
System.out.println("Retrieving all student data..");
// Create connection
createStudentDBConnection();
ResultSet rs = stmt.executeQuery(
"SELECT * FROM studentdb.hostelstudentinfo");
while (rs.next()) {
int studentId = rs.getInt(1);
String studentName = rs.getString(2);
double hostelFees = rs.getDouble(3);
String foodType = rs.getString(4);
System.out.println(studentId + " " + studentName
+ " " + hostelFees + " "
+ foodType);
}
// Closing the connection
closeConnection()
}
// Method 2
public void deleteStudentRecord(int studentId)
throws ClassNotFoundException, SQLException
{
System.out.println("Deleting student data..");
// Create connection
createStudentDBConnection();
stmt.executeUpdate(
"delete from studentdb.hostelstudentinfo where Student_id = "
+ studentId);
System.out.println("Record Deleted with the ID "
+ studentId);
// Close the connection
closeConnection();
}
// Method 3
// Close the connection
public void closeConnection() throws SQLException
{
con.close();
}
}
但我们又在做同样的事情。我们在selectAllRows()和 deleteStudentRecord() 方法中一次又一次地调用createStudentDBConnection()和closeConnection ()方法。假设我们总共有 100 个这样的实用方法,那么我们必须调用这些方法 100 次。所以我们会告诉我们的 spring 框架,一旦你(spring 框架)创建了 bean,请执行createStudentDBConnection()方法。所以我们要告诉 Spring 框架的方式是添加@PostConstruct注解。总之,我们可以说
Hey Spring, once you create the StudentDAO object please create createStudentDBConnection() by yourself. Don’t wait for us to call it.
所以现在我们可以把@PostConstruct注解 在createStudentDBConnection()之前是这样的
Java
@PostConstruct
public void createStudentDBConnection() throws ClassNotFoundException, SQLException {
// load driver
Class.forName(driver);
// get a connection
con = DriverManager.getConnection(url, userName, password);
// execute query
stmt = con.createStatement();
}
介绍 init()
在实际应用程序中, init()方法是随处可见的方法。我们也可以说init()方法是一个标准名称。例如,在这个项目中,我们可以将createStudentDBConnection()方法标记为 init。这里createStudentDBConnection()是我们的 init() 方法。使用@PostConstruct注释方法以将其用作 init() 方法。我们不需要调用 init() 方法,我们的框架会为我们调用它。我们可以将我们的 init() 方法名称作为任何名称。我们可以说它init()或者我们可以说它createStudentDBConnection()或xyz() 。所以现在我们可以写同样的东西
Java
@PostConstruct
public void init() throws SQLException, ClassNotFoundException {
createStudentDBConnection();
}
public void createStudentDBConnection() throws ClassNotFoundException, SQLException {
// load driver
Class.forName(driver);
// get a connection
con = DriverManager.getConnection(url, userName, password);
// execute query
stmt = con.createStatement();
}
为什么是 init()?
- 您可以在 bean 初始化期间添加自定义代码/逻辑
- 它可用于设置数据库/套接字/文件等资源。
介绍destroy()
在从容器中删除 bean 之前,将调用 destroy() 方法。现在让我们来看看 closeConnection()方法。我们定义了这个方法来清理未使用的引用。例如在这个项目中的con变量。因此,我们可以通过将任何方法标记为@PreDestroy来将其设为 destroy() 方法。所以现在我们可以编写类似的代码
Java
public void closeConnection() throws SQLException {
con.close();
}
@PreDestroy
public void destroy() throws SQLException {
closeConnection();
}
请注意,我们也可以在 closeConnection() 方法之前使用 @PreDestroy 注解。现在是StudentDAO 的完整代码。 Java类是
Java
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.sql.*;
public class StudentDAO {
private String driver;
private String url;
private String userName;
private String password;
// Connection Object
Connection con;
// Statement Object
Statement stmt;
public void setDriver(String driver) {
this.driver = driver;
}
public void setUrl(String url) {
this.url = url;
}
public void setUserName(String userName) {
this.userName = userName;
}
public void setPassword(String password) {
this.password = password;
}
@PostConstruct
public void init() throws SQLException, ClassNotFoundException {
createStudentDBConnection();
}
public void createStudentDBConnection() throws ClassNotFoundException, SQLException {
// load driver
Class.forName(driver);
// get a connection
con = DriverManager.getConnection(url, userName, password);
// execute query
stmt = con.createStatement();
}
public void selectAllRows() throws ClassNotFoundException, SQLException {
System.out.println("Retrieving all student data..");
ResultSet rs = stmt.executeQuery("SELECT * FROM studentdb.hostelstudentinfo");
while (rs.next()) {
int studentId = rs.getInt(1);
String studentName = rs.getString(2);
double hostelFees = rs.getDouble(3);
String foodType = rs.getString(4);
System.out.println(studentId + " " + studentName + " " + hostelFees + " " + foodType);
}
}
public void deleteStudentRecord(int studentId) throws ClassNotFoundException, SQLException {
System.out.println("Delete student data..");
stmt.executeUpdate("delete from studentdb.hostelstudentinfo where Student_id = " + studentId);
System.out.println("Record Deleted with the ID " + studentId);
}
public void closeConnection() throws SQLException {
con.close();
}
@PreDestroy
public void destroy() throws SQLException {
closeConnection();
}
}
在运行应用程序之前,请确保您已在beans.xml文件中添加以下行以使用注释
beans.xml文件的完整代码如下所示
XML
Main 的完整代码。 Java文件在下面给出
Java
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.sql.SQLException;
public class Main {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
// Using ApplicationContext tom implement Spring IoC
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// Get the bean studentDAO
StudentDAO studentDAO = context.getBean("studentDAO", StudentDAO.class);
// Calling the method
studentDAO.deleteStudentRecord(2);
studentDAO.selectAllRows();
}
}
输出:
Delete student data..
Record Deleted with the ID 2
Retrieving all student data..
1 Asish 300.5 Veg
3 Anshul 123.67 Veg