The lifecycle callbacks are methods defined in the bean class but not in business interface which the container calls when specific lifecycle event or transition occurs. The following two annotations are used to define lifecycle callbacks on stateless session beans.
@PostConstruct
- Used to mark a method defined in the bean class so that the container can invoke that marked method just after the creation of stateless session bean instance and dependency injection of any resources.
- This callback can be used to initialize any resources such as database connection, files etc required for the bean.
@PreDestroy
- Used to mark a method defined in the bean class so that the container can invoke that marked method before the stateless session bean is destroyed.
- This callback can be used to release or close any resources used by the bean.
Rules for @PostConstruct and @PreDestroy
- Their method signature must return a void and take no arguments.
- The method should not throw Checked Exception.
- The method can have access modifiers – public, private, package-private and protected.
- The method may be FINAL.
Example
The example stateless session bean described below is used to insert ‘Person’ data into the database. We use PostConstruct to open the database connection and PreDestroy to close the connection.
Create a ‘Person’ Transfer Object class and add getters and setters.
package com.ibytecode.to; import java.io.Serializable; import java.util.Date; public class Person implements Serializable{ private int id; private String name; private Date bdate; private Character gender; public Person(int id, String name, Date bdate, Character gender) { super(); this.id = id; this.name = name; this.bdate = bdate; this.gender = gender; } //Getters and Setters }
Create a local or remote business interface for the bean. We used remote interface.
package com.ibytecode.business; import javax.ejb.Remote; import com.ibytecode.to.Person; @Remote public interface IPerson { void addPerson(Person person); }
Create the stateless session bean and implement the remote interface.
package com.ibytecode.businesslogic; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.annotation.Resource; import javax.ejb.Stateless; import javax.sql.DataSource; import com.ibytecode.business.IPerson; import com.ibytecode.to.Person; @Stateless public class PersonBean implements IPerson { private Connection connection; @Resource(name = "java:/MySQLDS") private DataSource dataSource; public PersonBean() {} @PostConstruct public void initialize() { System.out.println("In PostConstruct"); try { connection = dataSource.getConnection(); } catch (SQLException sqle) { sqle.printStackTrace(); } } public void addPerson(Person person) { try { Statement statement = connection.createStatement(); statement.execute("INSERT INTO PERSON1 VALUES(" + person.getId() + ", "+ "'" + person.getName() + "'," + person.getBdate()+ ",'" + person.getGender() + "')"); } catch (Exception sqle) { sqle.printStackTrace(); } } @PreDestroy public void releaseResources() { System.out.println("In PreDestroy"); try { if(connection != null) { connection.close(); } } catch (SQLException e) { e.printStackTrace(); } } }
- In this code, after the stateless session bean instance is created by the container, it will inject the datasource specified by jndi name java:/MySQLDS.
- Next, the container will call the method of the bean which is annotated with @PostConstruct, in our case, initialize() method to do any resource initialization. In our case, we open the database connection.
- When the bean instance is no longer required, the container may destroy the bean. Before destroying, the container will invoke the method annotated with @PreDestroy, in our case, releaseResources() method. In this method, we close the database connection.
Create a java application client.
package com.ibytecode.client; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import javax.naming.Context; import javax.naming.NamingException; import com.ibytecode.business.IPerson; import com.ibytecode.businesslogic.PersonBean; import com.ibytecode.to.Person; public class PersonBeanClient{ public static void main(String[] args) { IPerson bean = doLookup(); String str = "1985/05/19"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd"); Date d = null; try { d = sdf.parse(str); } catch (ParseException e) { e.printStackTrace(); } Person p1 = new Person(1, "Raj", d, 'f'); bean.addPerson(p1); System.out.println("Person added"); } //JNDI Lookup differs based on different containers private static IPerson doLookup() { //Refer the example link for the complete code . . . . } }