0% found this document useful (0 votes)
19 views31 pages

Workshop 5

Uploaded by

Surendra
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
19 views31 pages

Workshop 5

Uploaded by

Surendra
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 31

Declarative and Programmatic Transaction Management Examples

Programmatic means you have transaction management code surrounding your


business code. Declarative means you separate transaction management from the
business code. You can use annotations or XML based configuration.

Programmatic management is more flexible during development time but less flexible
during application life. declarative management is less flexible during development time
but more flexible during application life

Declarative Transaction Management Example

1. Create a Java Project Named DeclarativeTran and include following jar files in
Java Build Path.

aspectjweaver- aopalliance- Commons- mysqlconnector.ja


1.8.9.jar 1.0.0.jar logging-1.2.jar r
spring-aop- spring-aspects- spring-beans- spring-context-
4.2.2.RELEASE.ja 4.2.2.RELEASE.ja 4.2.2.RELEASE.ja 4.2.2.RELEASE.ja
r r r r
spring-context- spring-core- spring-expression- spring-jdbc-
support- 4.2.2.RELEASE.ja 4.2.2.RELEASE.ja 4.2.2.RELEASE.ja
4.2.2.RELEASE.ja r r r
r
spring-tx-
4.2.2.RELEASE.ja
r

2. Open PhpMyAdmin and create following two tables inside your database.
 create table cust_info(id int not null auto_increment, name varchar(20),
address varchar(20), primary key (id))
 create table cust_bal(id int not null, bal int, foreign key(id) references
cust_info(id))
3. Create a package named ch5.declare.demo and add following Java files inside it.
4. Create a POJO class named CustBal which contains all fields from cust_info and
cust_bal table. This class is mainly used when retrieving records.

package ch5.declare.demo;

public class CustBal {


int id;
String name;
String address;
int bal;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public int getBal() {
return bal;
}
public void setBal(int bal) {
this.bal = bal;
}
}

5. Create an interface called CustDAO where we define our business methods

package ch5.declare.demo;

import java.util.List;

import javax.sql.DataSource;

public interface CustDAO {

public void setDataSource(DataSource datasource);


public void create(String name,String address, int bal);
public List<CustBal> retAllCust();
}

6. Create a class named CustDAOImpl class where we implement our business


methods
package ch5.declare.demo;

import java.util.List;
import javax.sql.DataSource;

import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;

public class CustDAOImpl implements CustDAO{

private JdbcTemplate jdbcTemplate;


@Override
public void setDataSource(DataSource datasource) {
// TODO Auto-generated method stub
this.jdbcTemplate=new JdbcTemplate(datasource);
}

@Override
public void create(String name, String address, int bal) {
try
{
jdbcTemplate.update("insert into cust_info(name,address)
values(?,?)",name,address);
int id=jdbcTemplate.queryForObject("select max(id) from
cust_info", Integer.class);
jdbcTemplate.update("insert into cust_bal(id,bal)
values(?,?)",id,bal);
System.out.println("Record Created for \n"+
"id="+id+",Name="+name+",Address="+address+",Balance="+bal);
throw new RuntimeException("Error Simulation");
}
catch(Exception e)
{
System.out.println("Error While Creating Record.."+e);
throw e;
}

@Override
public List<CustBal> retAllCust() {
// TODO Auto-generated method stub
List<CustBal> list=jdbcTemplate.query("select * from
cust_info,cust_bal where cust_info.id=cust_bal.id", new
CustBalanceMapper());
return list;
}

In above example, We have included a code to throw RunTimeException ( ). This


will cause the code to enter inside the catch block and throw the error. Hence, the
transaction will be automatically rolled back.

7. Create a class named CustBalanceMapper where we map database records into


CustBal class object.

package ch5.declare.demo;

import java.sql.ResultSet;
import java.sql.SQLException;

import org.springframework.jdbc.core.RowMapper;

public class CustBalanceMapper implements RowMapper<CustBal> {

@Override
public CustBal mapRow(ResultSet rs, int rowNum) throws
SQLException {
// TODO Auto-generated method stub
CustBal cinfo=new CustBal();
cinfo.setId(rs.getInt("id"));
cinfo.setName(rs.getString("name"));
cinfo.setAddress(rs.getString("address"));
cinfo.setBal(rs.getInt("bal"));
return cinfo;
}

8. Create an XML file named beans.xml

<?xml version="1.0" encoding="UTF-8"?>


<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

<!-- Initialization for data source -->


<bean id="dataSource"

class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
<property name="username" value="root"/>
<property name="password" value="opmcm6718"/>
</bean>

<tx:advice id="txAdvice" transaction-manager="transactionManager">


<tx:attributes>
<tx:method name="create" rollback-for="Exception" />
</tx:attributes>
</tx:advice>

<aop:config>
<aop:pointcut id="createOperation" expression="execution(*
ch5.declare.demo.CustDAOImpl.create(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="createOperation"/>
</aop:config>

<!-- Initialization for TransactionManager -->


<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionMana
ger">
<property name="dataSource" ref="dataSource" />
</bean>

<!-- Definition for custdaoimpl bean -->


<bean id="custdaoimpl" class="ch5.declare.demo.CustDAOImpl">
<property name="dataSource" ref="dataSource" />
</bean>

</beans>

In above xml file, we have created a transaction manager with


id="transactionManager" and configured this transaction manager in such a way
that if on execution of method named "create", if any exception occurs, then all
transactions should be rolled back as shown below:

<tx:advice id="txAdvice" transaction-


manager="transactionManager">
<tx:attributes>
<tx:method name="create" rollback-for="Exception" />
</tx:attributes>
</tx:advice>
Moreover, we have used transactionmanager as an advice through aop as
shown below:

<aop:config>
<aop:pointcut id="createOperation" expression="execution(*
ch5.declare.demo.CustDAOImpl.create(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="createOperation"/>
</aop:config>
Hence, transactionmaner automatically comes in action if create methods throws
Exception [ in our case RuntimeException]

9. Create a file named TestApp.java and include following codes inside it:

package ch5.declare.demo;

import java.util.List;

import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestApp {

public static void main(String[] args) {


// TODO Auto-generated method stub
ApplicationContext context = new
ClassPathXmlApplicationContext("ch5/declare/demo/beans.xml");
CustDAO custdao = (CustDAO)context.getBean("custdaoimpl");
System.out.println("Starting to create Record");
custdao.create("Mukesh", "GTG", 1200);
System.out.println("Record Created Successfully...");
System.out.println("Following are Database Values...");
List<CustBal> custdetails= custdao.retAllCust();
for(CustBal vals:custdetails)
{
System.out.print("ID="+vals.getId());
System.out.print(" ,Name="+vals.getName());
System.out.print(" ,Address="+vals.getAddress());
System.out.println(" ,Balance="+vals.getBal());
}
}

Programmatic Transaction Management

In this approach we will not define Transaction Manager in an XML file through AOP
rather we will define hard code Transaction Manager in CustDaoImpl class i.e. We will
initiate the transaction by writing code and in case of any error after the transaction is
started, then rollback code also we specify programmatically inside catch block.

1. Create a package named ch5.prog.demo inside src folder of above Project that
you had created for declarative transaction management.
2. We are going to use the same project and same database tables and hence not
necessary to import separate jar files and re-create the tables.
3. Inside ch5.demo.prog package create following Java classes and files.
4. Create a POJO class named CustBal which contains all fields from cust_info and
cust_bal table. This class is mainly used when retrieving records.

package ch5.prog.demo;
public class CustBal {
int id;
String name;
String address;
int bal;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public int getBal() {
return bal;
}
public void setBal(int bal) {
this.bal = bal;
}
}

5. Create an interface called CustDAO where we define our business methods


package ch5.prog.demo;

import java.util.List;

import javax.sql.DataSource;

public interface CustDAO {

public void setDataSource(DataSource datasource);


public void create(String name,String address, int bal);
public List<CustBal> retAllCust();
}
6. Create a class named CustDAOImpl class where we implement our business
methods
package ch5.prog.demo;
import java.util.List;

import javax.sql.DataSource;

import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import
org.springframework.transaction.support.DefaultTransactionDefinition;

public class CustDAOImpl implements CustDAO{

private JdbcTemplate jdbcTemplate;


private DataSource dataSource;
private PlatformTransactionManager transactionManager;
public PlatformTransactionManager getTransactionManager() {
return transactionManager;
}

public void setTransactionManager(PlatformTransactionManager


transactionManager) {
this.transactionManager = transactionManager;
}

@Override
public void setDataSource(DataSource datasource) {
// TODO Auto-generated method stub
this.dataSource=datasource;
this.jdbcTemplate=new JdbcTemplate(datasource);
}

@Override
public void create(String name, String address, int bal) {
TransactionDefinition def = new
DefaultTransactionDefinition();
TransactionStatus status =
transactionManager.getTransaction(def);
try
{

jdbcTemplate.update("insert into
cust_info(name,address) values(?,?)",name,address);
int id=jdbcTemplate.queryForObject("select max(id) from
cust_info", Integer.class);
jdbcTemplate.update("insert into cust_bal(id,bal)
values(?,?)",id,bal);
//throw new RuntimeException("Error Simulation");
transactionManager.commit(status);
System.out.println("Record Created for \n"+
"id="+id+",Name="+name+",Address="+address+",Balance="+bal);
//throw new RuntimeException("Error Simulation");

}
catch(Exception e)
{
System.out.println("Error While Creating Record.."+e);
transactionManager.rollback(status);
throw e;
}

@Override
public List<CustBal> retAllCust() {
// TODO Auto-generated method stub
List<CustBal> list=jdbcTemplate.query("select * from
cust_info,cust_bal where cust_info.id=cust_bal.id", new
CustBalanceMapper());
return list;
}
}
Note that here we have to specify transaction start, commit and rollback code
manually.

In above example, We have used PlatformTransactionManager to implement


programmatic approach of transaction management. To start a new transaction We
need to have a instance of TransactionDefinition with the appropriate transaction
attributes. For this example we will simply create an instance of
DefaultTransactionDefinition to use the default transaction attributes.

Once the TransactionDefinition is created, we can start our transaction by calling


getTransaction() method, which returns an instance of TransactionStatus. The
TransactionStatus objects helps in tracking the current status of the transaction and
finally, if everything goes fine, we can use commit() method of
PlatformTransactionManager to commit the transaction, otherwise we can use
rollback() to rollback the complete operation.

7. Create a class named CustBalanceMapper where we map database records into


CustBal class object

package ch5.prog.demo;

import java.sql.ResultSet;
import java.sql.SQLException;

import org.springframework.jdbc.core.RowMapper;

public class CustBalanceMapper implements RowMapper<CustBal> {

@Override
public CustBal mapRow(ResultSet rs, int rowNum) throws
SQLException {
// TODO Auto-generated method stub
CustBal cinfo=new CustBal();
cinfo.setId(rs.getInt("id"));
cinfo.setName(rs.getString("name"));
cinfo.setAddress(rs.getString("address"));
cinfo.setBal(rs.getInt("bal"));
return cinfo;
}

}
8. Create an XML file named beans.xml

<?xml version="1.0" encoding="UTF-8"?>


<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

<!-- Initialization for data source -->


<bean id="dataSource"

class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
<property name="username" value="root"/>
<property name="password" value="opmcm6718"/>
</bean>
<!-- Initialization for TransactionManager -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionMana
ger">
<property name="dataSource" ref="dataSource" />
</bean>

<!-- Definition for custdaoimpl bean -->


<bean id="custdaoimpl" class="ch5.prog.demo.CustDAOImpl">
<property name="dataSource" ref="dataSource" />
<property name="transactionManager" ref="transactionManager" />
</bean>

</beans>

9. Create a file named TestApp.java and include following codes inside it:
package ch5.prog.demo;

import java.util.List;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestApp {

public static void main(String[] args) {


// TODO Auto-generated method stub
ApplicationContext context = new
ClassPathXmlApplicationContext("ch5/prog/demo/beans.xml");
CustDAO custdao = (CustDAO)context.getBean("custdaoimpl");
System.out.println("Starting to create Record");
custdao.create("Mukesh", "GTG", 1200);
System.out.println("Record Created Successfully...");
System.out.println("Following are Database Values...");
List<CustBal> custdetails= custdao.retAllCust();
for(CustBal vals:custdetails)
{
System.out.print("ID="+vals.getId());
System.out.print(" ,Name="+vals.getName());
System.out.print(" ,Address="+vals.getAddress());
System.out.println(" ,Balance="+vals.getBal());
}
}

Reference:

1. http://www.tutorialspoint.com/spring/declarative_management.htm
2. http://www.tutorialspoint.com/spring/programmatic_management.htm

Annotations based Transaction Management

We have demonstrated earlier the usage of Transaction Management through XML


based approach(declarative) and manually by specifying transaction start,commit and
rollback code.
However, if we put @Transactional annotation just before declaration of any class or
method, then the transaction management capability will automatically be added to the
class or method. The annotation can be set at class or method level. The transaction
attributes can be specified along with the @Transactional annotation. You can s
One potential downside is that this powerful mechanism hides what is going on under
the hood, making it hard to debug when things don't work.
o ensure the working of annotation driven transactions we also need to add one more
element in the XML file.

<tx:annotation-driven transaction-manager="transactionManager"/>

Reference:

1. http://stackoverflow.com/questions/10740021/transactionalpropagation-
propagation-required
2. https://mybolder.com/2015/12/07/spring-transactional-propagation-and-isolation/
3. http://www.skill-guru.com/blog/2010/12/19/transactionalreadonlytrue-in-spring/

Annotations for Exposing MBeans

In the Java programming language, an MBean (managed bean) is a Java object that
represents a manageable resource, such as an application, a service, a component, or
a device.

Reference

1.

http://www.brainoverload.nl/java/73/mbeans-using-spring-and-annotations

http://www.javalobby.org/java/forums/t49130.html

http://vijaykiran.com/2005/10/jmx-helloworld/

MBean

MBean is defined as managed bean. An MBean can represent a device, an application,


or any resource that needs to be managed. JMX allows to check or change variables or
invoke methods in a local or remotely running application via a management GUI such
as JConsole. Let us devlop a sample application that Exposes MBean. Exposing
MBean means methods implemented inside a concrete class that implements MBean
interface can be accessed and executed by using jConsole.

Exposing Java Bean as an MBean without spring

Let us develop a sample application in which we expose Mbean and access it from
jconsole.

Steps:

1. Create a Java Project Named MBean


2. Inside src folder create named ch5.mbean.withoutspring and create following
classes inside it.
3. Create an interface named DemoMBean and put following codes inside it: [ Note
that the suffix of this class should be MBean]. Here you will define methods, that
you want to expose.
4. Create a class called Demo that implements DemoMBean interface and put
following codes inside it.[ Mind the name of this class, here MBean is dropped
off]
5. Create a class named DemoAgent and put following codes inside it. In this, class
we write code to register mbean in Mbean Server.

To Execute above application, Right Click on DemoAgent.java->Run As -> Run


Configurations->Inside Arguments Tab and in VM Arguments section, put the
following codes:

-Djava.rmi.server.hostname=localhost -Dcom.sun.management.jmxremote -
Dcom.sun.management.jmxremote.authenticate=false -
Dcom.sun.management.jmxremote.ssl=false -
Dcom.sun.management.jmxremote.port=10001

At last, click on Run Button


6. Open the command prompt and type jconsole. You will see following GUI

7. Click on Connect->Click on Insecure Connection button, you will see following


GUI
Click on MBeans Tab and expand the ch5.mbean.withoutspring tree and click on
sayHello method and click on sayHello( )button, you will see above dialog box
and in spring Console, you will see the execution output of sayHello ( ) method
that belongs to Demo class.

Exposing Java Bean as an MBean with spring

Follow the following steps to expose Java Bean as an MBean with spring.

1. Add following jar files in Java Build Path.


commons-logging-1.2.jar Spring-aop- Spring-beans- Spring-context-
4.2.2.RELEASE.jar 4.2.2.RELEASE.jar 4.2.2.RELEASE.jar
Spring-core- Spring-expression-
4.2.2.RELEASE.jar 4.2.2.RELEASE.jar

2. Create a package named ch5.mbean.withspring and add create following Java


files inside it.

3. Create an interface named DemoMBean and put following codes inside it.
package ch5.mbean.withspring;
public interface DemoMBean {

public void sayHello();


}

4. Create a class named Demo and put following codes inside it.
package ch5.mbean.withspring;

public class Demo implements DemoMBean {

@Override
public void sayHello() {
System.out.println("Hello World !");

5. Create an XML file named beans.xml and put following codes inside it.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.5.xsd">

<bean id="myMBean" class="ch5.mbean.withspring.Demo" />


<bean id="mbeanServer"
class="org.springframework.jmx.support.MBeanServerFactoryBean">
<property name="locateExistingServerIfPossible" value="true" />
</bean>

<bean class="org.springframework.jmx.export.MBeanExporter" lazy-


init="false">
<property name="beans">
<map>
<entry key="bean:name=MyMBeanName" value-ref="myMBean"/>
</map>
</property>
<property name="server" ref="mbeanServer"/>
</bean>

</beans>
6. Create a class named TestApp and put following codes inside it.
package ch5.mbean.withspring;

import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestApp {

public static void main(String[] args) {


ApplicationContext context = new
ClassPathXmlApplicationContext("ch5/mbean/withspring/beans.xml");

try{Thread.sleep(100000);}catch(Exception e)
{e.printStackTrace();}
System.out.println("Completed !");

7. Run TestApp
8. Start jconsole and select and establish connectivity with
ch5.mbean.withspring.TestApp and Click on "Insecure Connection" button.
9. Click on Mbeans tab and expand bean tree and click on "sayHello" button as
shown below. sayHello method of DemoMBean will be executed.

Annotations for Exposing MBeans


You can expose MBeans by writing various annotations on bean class. Let us develop a
sample application for this.

1. Create a package named ch5.annotation.mbean inside src folder and put


following files inside it.
2. Create a java file named Demo which contains various methods and attributes
that we are going to expose to jconsole and put following source code inside it.
package ch5.mbean.annotation;

import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedOperationParameter;
import
org.springframework.jmx.export.annotation.ManagedOperationParameters;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.stereotype.Component;
@Component
@ManagedResource(objectName="modelMBean:type=demo",
description="Calculator performing basic arithmetic on integers")
public class Demo {

private int operand1;


private int operand2;
public Demo()
{
System.out.println("Demo Mbean Created");
}
@ManagedOperation(description="Addition operation")
public int add() {
return operand1 + operand2;
}

@ManagedOperation(description="Multiplication operation")
public int multiply() {
return operand1 * operand2;
}

@ManagedOperation(description="Division operation")
@ManagedOperationParameters({
@ManagedOperationParameter(name="operand1",
description="Dividend"),
@ManagedOperationParameter(name="operand2",
description="Divisor")
})
public int divide(int operand1, int operand2) {
if(operand2 == 0) {
throw new IllegalArgumentException("Can not divide by zero");
}
return operand1 / operand2;
}

@ManagedAttribute
public int getOperand1() {
return operand1;
}

@ManagedAttribute
public void setOperand1(int operand1) {
this.operand1 = operand1;
}

@ManagedAttribute
public int getOperand2() {
return operand2;
}

@ManagedAttribute
public void setOperand2(int operand2) {
this.operand2 = operand2;
}
@ManagedOperation(description="sayHello method")
public void sayHello() {
System.out.println("Hello World !");

}
3. Create a java file named TestApp and put following source code inside it.
package ch5.mbean.annotation;

import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestApp {

public static void main(String[] args) {


ApplicationContext context = new
ClassPathXmlApplicationContext("ch5/mbean/annotation/beans.xml");

try{Thread.sleep(100000);}catch(Exception e)
{e.printStackTrace();}
System.out.println("Completed !");

4. Create an XML file named beans.xml and put following source code inside it.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.5.xsd">

<context:component-scan base-package="ch5.mbean.annotation"/>

<context:mbean-export/>

</beans>

Note: in above source code, the various annotations have following meanings:

@ManagedResource – defines an MBean

@ManagedAttribute – defines an attribute of an MBean

@ManagedOperation – defines an operation of an MBean

Reference:

1. https://blog.synyx.de/2012/05/how-to-monitor-and-manage-your-java-application-
with-jmx/
2. http://actimem.com/java/jmx-spring/

Support for Publishing and receiving JMX Notifications


Publish JMX Notification

Spring IoC Container supports the beans that are going to be exposed as MBeans to publish JMX
Notification. These bean class must implement the NotificationPublisherAware interface so that
they can publish notifications. In the following example, we have a bean class called
JmxTestBean which is exposed as MBean and implements NotificationPublisheraware interface.
Hence, this class is capable of sending notification, whenever add( ) method is called. Whenever
you open jconsole and click on Notification node in the tree you have to click subscribe button.
Now, whenever the add( ) method is called by clicking the button, you can see corresponding
notification being appeared in Notification node of the tree.

Let us develop a sample program that sends JMX notification whenever add( ) method is called.

1. Create a package named ch5.notification.demo and create following files inside it.
2. Create a file named JmxTestBean.java inside ch5.notification.demo package and put
following source code inside it.
package ch5.notification.demo;

import org.springframework.jmx.export.notification.NotificationPublisherAware;
import org.springframework.jmx.export.notification.NotificationPublisher;
import javax.management.Notification;

public class JmxTestBean implements NotificationPublisherAware {


private NotificationPublisher publisher;

// other getters and setters omitted for clarity

public int add(int x, int y) {


int answer = x + y;
this.publisher.sendNotification(new Notification("add", this, 0));
return answer;
}
public void dontExposeMe() {
throw new RuntimeException();
}

public void setNotificationPublisher(NotificationPublisher notificationPublisher) {


this.publisher = notificationPublisher;
}
}

3. Create XML file named beans.xml and put following codes inside it.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.5.xsd">

<bean id="myMBean" class="ch5.notification.demo.JmxTestBean" />


<bean id="mbeanServer"
class="org.springframework.jmx.support.MBeanServerFactoryBean">
<property name="locateExistingServerIfPossible" value="true" />
</bean>

<bean class="org.springframework.jmx.export.MBeanExporter" lazy-


init="false">
<property name="beans">
<map>
<entry key="bean:name=MyMBeanName" value-ref="myMBean"/>
</map>
</property>
<property name="notificationListenerMappings">
<map>
<entry key="bean:name=MyMBeanName">
<bean
class="ch5.notification.demo.ConsoleLoggingNotificationListener"/>
</entry>
</map>
</property>
<property name="server" ref="mbeanServer"/>
</bean>
</beans>
4. Create a file named TestApp.java and put following codes inside it.
package ch5.notification.demo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestApp {
public static void main(String[] args) {
ApplicationContext context = new
ClassPathXmlApplicationContext("ch5/notification/demo/beans.xml");
try{Thread.sleep(100000);}catch(Exception e){e.printStackTrace();}
System.out.println("Completed !");
}

}
5. Run TestApp.java
6. Go to command prompt and type jconsole and establish connectivity with TestApp-
>Click Insecure Connection Button-> Click on MBeans Tab-> Click on Notifications
Node-> Click on Subscribe button

7. Click on Operations-> Supply(x=10,y=20)-> Click on add button-> Open the


Notification node once again, you can see notification being created over there.
Receive JMX Notification

Once notification occurs, it can be received by a class. Let us create a class named
ConsoleLoggingNotificaionListener inside ch5.notification.demo package and put following
codes inside it. In order for this class to receive notification published above, you have to include
this notification listener in beans.xml file as shown below:
<bean class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
<property name="beans">
<map>
<entry key="bean:name=MyMBeanName" value-ref="myMBean"/>
</map>
</property>
<property name="notificationListenerMappings">
<map>
<entry key="bean:name=MyMBeanName">
<bean class="ch5.notification.demo.ConsoleLoggingNotificationListener"/>
</entry>
</map>
</property>
<property name="server" ref="mbeanServer"/>
</bean>

Source code for ConsoleLoggingNotificationListener class is shown below:


package ch5.notification.demo;

import javax.management.AttributeChangeNotification;
import javax.management.Notification;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
public class ConsoleLoggingNotificationListener

implements NotificationListener, NotificationFilter {

public void handleNotification(Notification notification, Object handback) {

System.out.println(notification);

System.out.println(handback);

public boolean isNotificationEnabled(Notification notification) {

return
AttributeChangeNotification.class.isAssignableFrom(notification.getClass());

}
Reference:

1. http://vard-lokkur.blogspot.com/2010/11/jmx-notification-publishing.html
2. http://docs.spring.io/spring/docs/2.5.x/reference/jmx.html#jmx-notifications-
publishing
3. http://marxsoftware.blogspot.com/2008/02/publishing-jmx-notifications-with.html

Monitoring Remote Services


MBeans can be accessed remotely using RMI. MBeans exposed on Remote server
can be monitored either by using jconsole or creating a custom java application. We are
going to demonstrate both of the approach in following section.

Exposing MBean for Remote Access

In order to expose MBean on remote machine such that it can be accessed by client
using RMI protocol, you have to add following additional codes in your beans.xml file
inside ch5.mbean.withspring package.
<bean
class="org.springframework.jmx.support.ConnectorServerFactoryBean"
depends-on="rmiRegistry">
<property name="objectName" value="connector:name=rmi" />
<property name="serviceUrl"

value="service:jmx:rmi://localhost/jndi/rmi://localhost:10099/myconnector" />
</bean>

<bean id="rmiRegistry"
class="org.springframework.remoting.rmi.RmiRegistryFactoryBean">
<property name="port" value="10099" />
</bean>

The complete source code of beans.xml file should look like following:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.5.xsd">
<bean id="rmiRegistry"
class="org.springframework.remoting.rmi.RmiRegistryFactoryBean">
<property name="port" value="10099" />
</bean>

<bean id="myMBean" class="ch5.mbean.withspring.Demo" />


<bean id="mbeanServer"
class="org.springframework.jmx.support.MBeanServerFactoryBean">
<property name="locateExistingServerIfPossible" value="true" />
</bean>

<bean class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">


<property name="beans">
<map>
<entry key="bean:name=MyMBeanName" value-ref="myMBean"/>
</map>
</property>
<property name="server" ref="mbeanServer"/>
</bean>
<bean
class="org.springframework.jmx.support.ConnectorServerFactoryBean"
depends-on="rmiRegistry">
<property name="objectName" value="connector:name=rmi" />
<property name="serviceUrl"

value="service:jmx:rmi://localhost/jndi/rmi://localhost:10099/myconnector" />
</bean>

</beans>

Once, Mbean is exposed for remote access, now, the MBean named "MyBeanName"
can be accessed remotely using the following URLs:

service:jmx:rmi://localhost/jndi/rmi://localhost:10099/myconnector

Monitoring Remote Services using jconsole

Server Side:

1. Open Command prompt and type rmiregistry 10099 [ rmiregistry will be started]
2. Run TesApp.java

Client Side:

3. Open Command Promt and type jconsole and type following URL on remote
process text box as shown below:
4. Now, click on Connect->Insecure Connection-> You will be able to monitor
MBean named "MyBean" as shown below:
Monitoring Remote Services using Custom Application

In client side,

1. Create a source code file named MonitorRemoteService.java and put following


codes inside it.
package ch5.mbean.withspring;

import javax.management.MBeanAttributeInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

public class MonitorRemoteService {

public static void main(String[] args) {

try
{
String host="localhost";
String port="10099";
JMXServiceURL target = new
JMXServiceURL("service:jmx:rmi:///jndi/rmi://"+host+":"+port+"/myconnector");
JMXConnector connector = JMXConnectorFactory.connect(target);
MBeanServerConnection remote = connector.getMBeanServerConnection();
ObjectName bean = new ObjectName("bean:name=MyMBeanName");
MBeanInfo info = remote.getMBeanInfo(bean);
MBeanAttributeInfo[] attributes = info.getAttributes();
String description= info.getDescription();
System.out.println("Description="+description);
MBeanOperationInfo ops[]= info.getOperations();

for (MBeanOperationInfo operation : ops)


{

System.out.println("Operation Name="+operation.getName());

}
System.out.println("Completed");
connector.close();
}
catch(Exception e)
{
e.printStackTrace();
}

}
}

2. Run above file

Note: Above code is able to monitor various aspects of MBean named MyBean
[ Attributes, Operations, Notifications etc] that is exposed in Server Side over RMI.

Reference:

1. https://docs.oracle.com/javase/tutorial/jmx/remote/custom.html

You might also like