Java tutorial
/** * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ package com.arto.core.intercepter; import com.arto.core.bootstrap.MqClient; import com.arto.core.event.MqEvent; import com.arto.core.exception.MqClientException; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.ResourceLoaderAware; import org.springframework.core.Ordered; import org.springframework.core.io.ResourceLoader; import org.springframework.jdbc.datasource.ConnectionHolder; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.stereotype.Component; import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.util.Assert; import org.springframework.util.ReflectionUtils; import javax.sql.DataSource; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.sql.Connection; import java.util.List; /** * ??jdbc???????. * (?????????) * * Created by xiong.j on 2017/2/15. */ @Component @Aspect public class TxMessageAspect implements Ordered, ResourceLoaderAware, ApplicationContextAware { private ApplicationContext applicationContext; private ResourceLoader resourceLoader; @Autowired private DataSourceTransactionManager transactionManager; //?TXAction @Pointcut("@annotation(com.arto.core.annotation.TxMessage)") public void pointcutTxMessage() { } @Around("pointcutTxMessage()") public Object doTransactionMessage(ProceedingJoinPoint pjp) throws Throwable { // ??? DataSource dataSource = transactionManager.getDataSource(); // ?? assertTransactional(dataSource); // ?? ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource); final Connection conn = conHolder.getConnection(); // ??? Method setterMethod = ReflectionUtils.findMethod(ConnectionHolder.class, "setConnection", Connection.class); ReflectionUtils.makeAccessible(setterMethod); // ?commit ReflectionUtils.invokeMethod(setterMethod, conHolder, Proxy.newProxyInstance( resourceLoader.getClassLoader(), new Class<?>[] { Connection.class }, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { return method.invoke(conn, args); } finally { // ?commit?????? if ("commit".equals(method.getName())) { List<MqEvent> txMessages = TxMessageContextHolder.getTxMessages(); if (txMessages != null) { MqEvent message; for (int i = 0; i < txMessages.size(); i++) { message = txMessages.get(i); MqClient.getPipeline(message.getType()).offer(message); } } TxMessageContextHolder.clear(); } else if ("rollback".equals(method.getName())) { TxMessageContextHolder.clear(); } } } })); // ? return pjp.proceed(); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } @Override public void setResourceLoader(ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; } @Override public int getOrder() { return Ordered.LOWEST_PRECEDENCE; } private void assertTransactional(DataSource dataSource) throws Throwable { Assert.notNull(dataSource, "Can't get datasource from bean 'transactionManager'."); ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource); if (conHolder == null || conHolder.getConnectionHandle() == null || !conHolder.isSynchronizedWithTransaction()) { throw new MqClientException("It's not in spring jdbc transaction."); } } }