spring中RMI服务的事务和AOP顺序

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/buyaore_wo/article/details/82051022

RMI是java中和远程方法调用 ,基于接口,和本地调用有一样的使用体验,这个不再赘述了

AOP面向切面编程,spring中常用来做事务管理,本篇我们就了解一下使用aop管理rmi事务

我们项目中的做法是:

spring rmi向外暴露方法, 使用aop配置事务在rmi方法上

我们先写一个业务逻辑

接口

public interface TxApi {

	void txMethod1();

}

及实现



import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;


@Service("txApi")
public class TxApiImpl implements TxApi {

	private static final Logger LOGGER = LoggerFactory.getLogger(TxApiImpl.class);


	@Override
	public void txMethod1() {
		LOGGER.info("方法内部--------------------");
	}
}

这个业务逻辑有一个txMethod1方法, 在方法实现中我们只输出 "方法内部--------------------"

将这个接口暴露为rmi服务并给rmi调用加上拦截

	<bean id="txApiRmiExporter"
		class="org.springframework.remoting.rmi.RmiServiceExporter"
		destroy-method="destroy">
		<property name="service">
			<ref bean="txApi" />
		</property>
		<property name="serviceName" value="txApiRmi" />
		<property name="serviceInterface"
			value="com.yj.tr.test.spring.tx.biz.TxApi" />
		<property name="registryPort" value="${rmi.registryPort}" />
		<property name="servicePort" value="${rmi.servicePort}" />
		<property name="interceptors">
			<list>
				<ref bean="securityInterceptor" />
			</list>
		</property>
	</bean>
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class SecurityInterceptor implements MethodInterceptor {
	private static final Logger LOGGER = LoggerFactory.getLogger(SecurityInterceptor.class);

	@Override
	public Object invoke(MethodInvocation methodInvocation) throws Throwable {
		Object methodReturnObj = null;

		System.out.println("Rmi-SecurityInterceptor 方法执行前------<<<<<<<<<<<<<<<<");
		LOGGER.info("Rmi-SecurityInterceptor 方法执行前------<<<<<<<<<<<<<<<<");

		methodReturnObj = methodInvocation.proceed();

		System.out.println("Rmi-SecurityInterceptor 方法执行后------<<<<<<<<<<<<<<<<");
		LOGGER.info("Rmi-SecurityInterceptor 方法执行后------<<<<<<<<<<<<<<<<");
		return methodReturnObj;

	}

}

然后在这个业务上通过aop配置事务及方法调用记录,test-spring-tx.xmx配置如下

	<context:component-scan
		base-package="com.yj.tr.test.spring.tx.biz" />
	<context:component-scan
		base-package="com.yj.tr.gds.model.dao.impl" />

	<tx:annotation-driven />
	<bean id="transactionManager"
		class="org.springframework.orm.hibernate3.HibernateTransactionManager">
		<property name="sessionFactory" ref="sessionFactory">
		</property>
	</bean>
	<tx:advice id="transaction"
		transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="*_tx_r" propagation="REQUIRED"
				read-only="true" />
			<tx:method name="*_tx_s" propagation="SUPPORTS" />
			<tx:method name="*" propagation="REQUIRED" />
		</tx:attributes>
	</tx:advice>

	<aop:config>
		<!-- pointcuts -->
		<aop:pointcut id="tx"
			expression="execution(public * com.yj.tr.test.spring.tx.biz.*.*(..))" />

		<!-- transaction advisors -->

		<aop:advisor advice-ref="transaction" pointcut-ref="tx"/>

		<!-- logger advisors -->
		<aop:advisor advice-ref="methodLogger" pointcut-ref="tx" />

	</aop:config>

方法记录类

@Component
public class MethodLogger implements MethodInterceptor {
	private static final Logger LOGGER = LoggerFactory.getLogger(MethodLogger.class);
	private static final Logger LOGGER2 = LoggerFactory.getLogger("method-invoke");

	@Resource
	ComboPooledDataSource dataSource;

	@Override
	public Object invoke(MethodInvocation methodInvocation) throws Throwable {
		System.out.println("aop日志-方法前--->>>>>");
		LOGGER.info("aop日志-方法前--->>>>>");

		Object methodReturnObj = null;

		methodReturnObj = methodInvocation.proceed();

		System.out.println("aop日志-方法后--->>>>>");
		LOGGER.info("aop日志-方法后--->>>>>");
		return methodReturnObj;
	}
}

再写一个rmi客户端调用,引用rmi接口 , test-spring-rmi-import.xml配置如下


	<bean id="txApiRmiClient"
		class="com.yj.org.springframework.remoting.rmi.RmiProxyFactoryBean">
		<property name="serviceUrl"
			value="rmi://${gds.rmi.server.hostname}:${gds.rmi.registryPort}/txApiRmi" />
		<property name="serviceInterface"
			value="com.yj.tr.test.spring.tx.biz.TxApi" />
		<property name="lookupStubOnStartup" value="false"></property>
		<property name="refreshStubOnConnectFailure" value="true"></property>
	</bean>

运行rmi服务端

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ServerApplication {

	public static void main(String[] args) {
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(new String[] { //
				"classpath:test-spring-hibernate.xml", //
				"classpath:test-spring-tx.xml", //
				"classpath:test-spring-rmi-export.xml", //
				"classpath:test-spring-rmi-import.xml",//
		});

		System.out.println("server started");
	}

}

客户端来调用它 (客户端我使用junit测试来跑)

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.yj.tr.test.spring.tx.biz.TxApi;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { //
		"classpath:test-spring-rmi-import.xml",//
})

public class TxRmiApiTest {
	private static final Logger LOGGER = LoggerFactory.getLogger(TxRmiApiTest.class);

	@Resource
	TxApi txApiRmiClient;

	@Test
	public void testTxMethod1_RMI() {
			txApiRmiClient.txMethod1();
	}

}

从服务端的输出看,aop方法、事务、rmi拦截器的输出

Building new Hibernate SessionFactory --[INFO] 2018-08-25 14:37:04
Rmi-SecurityInterceptor 方法执行前------<<<<<<<<<<<<<<<< --[INFO] 2018-08-25 14:37:30
Creating new transaction with name [com.yj.tr.test.spring.tx.biz.TxApiImpl.txMethod1]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT --[DEBUG] 2018-08-25 14:37:30
Opened new Session [org.hibernate.impl.SessionImpl@3632ea8b] for Hibernate transaction --[DEBUG] 2018-08-25 14:37:30
Preparing JDBC Connection of Hibernate Session [org.hibernate.impl.SessionImpl@3632ea8b] --[DEBUG] 2018-08-25 14:37:30
Exposing Hibernate transaction as JDBC transaction [com.mchange.v2.c3p0.impl.NewProxyConnection@14cf4af9] --[DEBUG] 2018-08-25 14:37:30
aop日志-方法前--->>>>> --[INFO] 2018-08-25 14:37:30
方法内部-------------------- --[INFO] 2018-08-25 14:37:30
aop日志-方法后--->>>>> --[INFO] 2018-08-25 14:37:30
Triggering beforeCommit synchronization --[DEBUG] 2018-08-25 14:37:30
Triggering beforeCompletion synchronization --[DEBUG] 2018-08-25 14:37:30
Initiating transaction commit --[DEBUG] 2018-08-25 14:37:30
Committing Hibernate transaction on Session [org.hibernate.impl.SessionImpl@3632ea8b] --[DEBUG] 2018-08-25 14:37:30
Triggering afterCommit synchronization --[DEBUG] 2018-08-25 14:37:30
Triggering afterCompletion synchronization --[DEBUG] 2018-08-25 14:37:30
Closing Hibernate Session [org.hibernate.impl.SessionImpl@3632ea8b] after transaction --[DEBUG] 2018-08-25 14:37:30
Closing Hibernate Session --[DEBUG] 2018-08-25 14:37:30
Rmi-SecurityInterceptor 方法执行后------<<<<<<<<<<<<<<<< --[INFO] 2018-08-25 14:37:30

可以看到rmi的拦截器最先执行, 然后是spring事务管理器,然后再是方法记录, 整个执行过程是

SecurityInterceptor-> transactionManager -> MethodLogger -> MethodLogger -> transactionManager -> SecurityInterceptor

我们通过修改aop的order来指定aop执行顺序(注意新加了order属性配置)

		<aop:advisor advice-ref="transaction" pointcut-ref="tx"  order="2"/>

		<!-- logger advisors -->
		<aop:advisor advice-ref="methodLogger" pointcut-ref="tx" order="1"/>

再运行看日志输出

Building new Hibernate SessionFactory --[INFO] 2018-08-25 14:43:27
Rmi-SecurityInterceptor 方法执行前------<<<<<<<<<<<<<<<< --[INFO] 2018-08-25 14:43:34
aop日志-方法前--->>>>> --[INFO] 2018-08-25 14:43:34
Creating new transaction with name [com.yj.tr.test.spring.tx.biz.TxApiImpl.txMethod1]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT --[DEBUG] 2018-08-25 14:43:34
Opened new Session [org.hibernate.impl.SessionImpl@7966f7ed] for Hibernate transaction --[DEBUG] 2018-08-25 14:43:34
Preparing JDBC Connection of Hibernate Session [org.hibernate.impl.SessionImpl@7966f7ed] --[DEBUG] 2018-08-25 14:43:34
Exposing Hibernate transaction as JDBC transaction [com.mchange.v2.c3p0.impl.NewProxyConnection@54e3813f] --[DEBUG] 2018-08-25 14:43:34
方法内部-------------------- --[INFO] 2018-08-25 14:43:34
Triggering beforeCommit synchronization --[DEBUG] 2018-08-25 14:43:35
Triggering beforeCompletion synchronization --[DEBUG] 2018-08-25 14:43:35
Initiating transaction commit --[DEBUG] 2018-08-25 14:43:35
Committing Hibernate transaction on Session [org.hibernate.impl.SessionImpl@7966f7ed] --[DEBUG] 2018-08-25 14:43:35
Triggering afterCommit synchronization --[DEBUG] 2018-08-25 14:43:35
Triggering afterCompletion synchronization --[DEBUG] 2018-08-25 14:43:35
Closing Hibernate Session [org.hibernate.impl.SessionImpl@7966f7ed] after transaction --[DEBUG] 2018-08-25 14:43:35
Closing Hibernate Session --[DEBUG] 2018-08-25 14:43:35
aop日志-方法后--->>>>> --[INFO] 2018-08-25 14:43:35
Rmi-SecurityInterceptor 方法执行后------<<<<<<<<<<<<<<<< --[INFO] 2018-08-25 14:43:35

现在整个执行顺序变为了

SecurityInterceptor-> MethodLogger ->transactionManager -> transactionManager->  MethodLogger -> SecurityInterceptor

猜你喜欢

转载自blog.csdn.net/buyaore_wo/article/details/82051022