提交 63d3250b 编写于 作者: K KomachiSion

Move back sharding-transaction-spring-boot-starter

上级 b72ed9be
......@@ -254,6 +254,18 @@
<version>${spring-boot.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>${spring-boot.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<version>${spring-boot.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
......
......@@ -16,5 +16,6 @@
<module>sharding-jdbc-spring</module>
<module>sharding-jdbc-orchestration-spring</module>
<module>sharding-transaction-spring</module>
<module>sharding-transaction-spring-boot-starter</module>
</modules>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-spring</artifactId>
<version>4.0.0.M1-SNAPSHOT</version>
</parent>
<artifactId>sharding-transaction-spring-boot-starter</artifactId>
<name>${project.artifactId}</name>
<dependencies>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-transaction-spring</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
</project>
\ No newline at end of file
/*
* 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 org.apache.shardingsphere.transaction.spring.boot;
import org.apache.shardingsphere.transaction.aspect.ShardingTransactionalAspect;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
import org.springframework.boot.autoconfigure.condition.ConditionMessage.Builder;
import org.springframework.boot.autoconfigure.condition.ConditionMessage.Style;
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.util.ClassUtils;
import javax.sql.DataSource;
import java.util.Arrays;
/**
* Spring boot sharding transaction configuration.
*
* @author yangyi
*/
@Configuration
@NoArgsConstructor
public class ShardingTransactionConfiguration {
/**
* Build sharding transaction aspect bean.
*
* @return sharding transaction aspect bean
*/
@Bean
public ShardingTransactionalAspect shardingTransactionalAspect() {
return new ShardingTransactionalAspect();
}
/**
* Build hibernate transaction manager.
*
* @param transactionManagerCustomizers transaction manager customizers
* @return jpa transaction manager
*/
@Bean
@ConditionalOnMissingBean(PlatformTransactionManager.class)
@Conditional(HibernateEntityManagerCondition.class)
public PlatformTransactionManager jpaTransactionManager(final ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
JpaTransactionManager result = new JpaTransactionManager();
if (null != transactionManagerCustomizers.getIfAvailable()) {
transactionManagerCustomizers.getIfAvailable().customize(result);
}
return result;
}
/**
* Build datasource transaction manager.
*
* @param dataSource data source
* @param transactionManagerCustomizers transaction manager customizers
* @return datasource transaction manager
*/
@Bean
@ConditionalOnMissingBean(PlatformTransactionManager.class)
public PlatformTransactionManager dataSourceTransactionManager(final DataSource dataSource, final ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
DataSourceTransactionManager result = new DataSourceTransactionManager(dataSource);
if (null != transactionManagerCustomizers.getIfAvailable()) {
transactionManagerCustomizers.getIfAvailable().customize(result);
}
return result;
}
@NoArgsConstructor
static class HibernateEntityManagerCondition extends SpringBootCondition {
private static final String[] CLASS_NAMES = new String[]{"org.hibernate.ejb.HibernateEntityManager", "org.hibernate.jpa.HibernateEntityManager"};
@Override
public ConditionOutcome getMatchOutcome(final ConditionContext context, final AnnotatedTypeMetadata metadata) {
Builder message = ConditionMessage.forCondition("HibernateEntityManager", new Object[0]);
for (String each : CLASS_NAMES) {
if (ClassUtils.isPresent(each, context.getClassLoader())) {
return ConditionOutcome.match(message.found("class").items(Style.QUOTE, new Object[]{each}));
}
}
return ConditionOutcome.noMatch(message.didNotFind("class", "classes").items(Style.QUOTE, Arrays.asList(CLASS_NAMES)));
}
}
}
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.apache.shardingsphere.transaction.spring.boot.ShardingTransactionConfiguration
\ No newline at end of file
/*
* 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 org.apache.shardingsphere.transaction.spring.boot;
import org.apache.shardingsphere.transaction.aspect.ShardingTransactionalAspect;
import org.apache.shardingsphere.transaction.spring.boot.fixture.ShardingTransactionalTestService;
import org.apache.shardingsphere.transaction.spring.boot.util.TransactionManagerMockUtil;
import org.apache.shardingsphere.core.exception.ShardingException;
import org.apache.shardingsphere.transaction.core.TransactionType;
import org.apache.shardingsphere.transaction.core.TransactionTypeHolder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.sql.Statement;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = ShardingTransactionalSpringBootTest.class)
@SpringBootApplication
@ComponentScan("org.apache.shardingsphere.transaction.spring.boot.fixture")
public class ShardingTransactionalSpringBootTest {
@Autowired
private ShardingTransactionalTestService testService;
@Autowired
private ShardingTransactionalAspect aspect;
private final Statement statement = mock(Statement.class);
private final JpaTransactionManager jpaTransactionManager = mock(JpaTransactionManager.class);
private final DataSourceTransactionManager dataSourceTransactionManager = mock(DataSourceTransactionManager.class);
@Before
public void setUp() throws SQLException {
TransactionManagerMockUtil.initTransactionManagerMock(statement, jpaTransactionManager, dataSourceTransactionManager);
}
@After
public void tearDown() {
aspect.setEnvironment(new DataSource[]{});
}
@Test
public void assertChangeTransactionTypeToXA() {
testService.testChangeTransactionTypeToXA();
assertThat(TransactionTypeHolder.get(), is(TransactionType.LOCAL));
}
@Test
public void assertChangeTransactionTypeToBASE() {
testService.testChangeTransactionTypeToBASE();
assertThat(TransactionTypeHolder.get(), is(TransactionType.LOCAL));
}
@Test
public void assertChangeTransactionTypeToLocal() {
TransactionTypeHolder.set(TransactionType.XA);
testService.testChangeTransactionTypeToLOCAL();
assertThat(TransactionTypeHolder.get(), is(TransactionType.LOCAL));
}
@Test
public void assertChangeTransactionTypeInClass() {
testService.testChangeTransactionTypeInClass();
assertThat(TransactionTypeHolder.get(), is(TransactionType.LOCAL));
}
@Test(expected = ShardingException.class)
public void assertChangeTransactionTypeForProxyWithIllegalTransactionManager() throws SQLException {
TransactionManagerMockUtil.testChangeProxyTransactionTypeToLOCAL(testService, aspect, mock(PlatformTransactionManager.class));
}
@Test(expected = ShardingException.class)
public void assertChangeTransactionTypeForProxyFailed() throws SQLException {
when(statement.execute(anyString())).thenThrow(new SQLException("test switch exception"));
TransactionManagerMockUtil.testChangeProxyTransactionTypeToLOCAL(testService, aspect, dataSourceTransactionManager);
}
@Test
public void assertChangeTransactionTypeToLOCALForProxy() throws SQLException {
when(statement.execute(anyString())).thenReturn(true);
TransactionManagerMockUtil.testChangeProxyTransactionTypeToLOCAL(testService, aspect, dataSourceTransactionManager);
TransactionManagerMockUtil.testChangeProxyTransactionTypeToLOCAL(testService, aspect, jpaTransactionManager);
verify(statement, times(2)).execute("SCTL:SET TRANSACTION_TYPE=LOCAL");
}
@Test
public void assertChangeTransactionTypeToXAForProxy() throws SQLException {
when(statement.execute(anyString())).thenReturn(true);
TransactionManagerMockUtil.testChangeProxyTransactionTypeToXA(testService, aspect, dataSourceTransactionManager);
TransactionManagerMockUtil.testChangeProxyTransactionTypeToXA(testService, aspect, jpaTransactionManager);
verify(statement, times(2)).execute("SCTL:SET TRANSACTION_TYPE=XA");
}
@Test
public void assertChangeTransactionTypeToBASEForProxy() throws SQLException {
when(statement.execute(anyString())).thenReturn(true);
TransactionManagerMockUtil.testChangeProxyTransactionTypeToBASE(testService, aspect, dataSourceTransactionManager);
TransactionManagerMockUtil.testChangeProxyTransactionTypeToBASE(testService, aspect, jpaTransactionManager);
verify(statement, times(2)).execute("SCTL:SET TRANSACTION_TYPE=BASE");
}
}
/*
* 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 org.apache.shardingsphere.transaction.spring.boot.fixture;
import org.apache.shardingsphere.transaction.annotation.ShardingTransactionType;
import org.apache.shardingsphere.transaction.core.TransactionType;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
@Service
@Component
@ShardingTransactionType(TransactionType.XA)
public class ShardingTransactionalTestService {
@ShardingTransactionType
public void testChangeTransactionTypeToLOCAL() {
}
@ShardingTransactionType(TransactionType.XA)
public void testChangeTransactionTypeToXA() {
}
@ShardingTransactionType(TransactionType.BASE)
public void testChangeTransactionTypeToBASE() {
}
public void testChangeTransactionTypeInClass() {
}
}
/*
* 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 org.apache.shardingsphere.transaction.spring.boot.util;
import org.apache.shardingsphere.transaction.aspect.ShardingTransactionalAspect;
import org.apache.shardingsphere.transaction.spring.boot.fixture.ShardingTransactionalTestService;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.hibernate.engine.spi.SessionImplementor;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class TransactionManagerMockUtil {
/**
* Init transaction manager mock.
*
* @param statement mock statement
* @param jpaTransactionManager mock jpa transaction manager
* @param dataSourceTransactionManager mock dataSource transaction manager
* @throws SQLException SQL exception
*/
public static void initTransactionManagerMock(
final Statement statement, final JpaTransactionManager jpaTransactionManager, final DataSourceTransactionManager dataSourceTransactionManager) throws SQLException {
DataSource dataSource = mock(DataSource.class);
Connection connection = mock(Connection.class);
EntityManagerFactory entityManagerFactory = mock(EntityManagerFactory.class);
EntityManager entityManager = mock(EntityManager.class);
SessionImplementor sessionImplementor = mock(SessionImplementor.class);
when(dataSource.getConnection()).thenReturn(connection);
when(connection.createStatement()).thenReturn(statement);
when(sessionImplementor.connection()).thenReturn(connection);
when(entityManager.unwrap(SessionImplementor.class)).thenReturn(sessionImplementor);
when(entityManagerFactory.createEntityManager()).thenReturn(entityManager);
when(jpaTransactionManager.getEntityManagerFactory()).thenReturn(entityManagerFactory);
when(dataSourceTransactionManager.getDataSource()).thenReturn(dataSource);
}
/**
* Test change proxy transaction type to LOCAL with specified transaction manager.
*
* @param testService sharding transaction test service
* @param aspect sharding transaction aspect
* @param transactionManager specified transaction manager
* @throws SQLException SQL exception
*/
public static void testChangeProxyTransactionTypeToLOCAL(final ShardingTransactionalTestService testService, final ShardingTransactionalAspect aspect, final PlatformTransactionManager transactionManager) throws SQLException {
aspect.setTransactionManager(transactionManager);
aspect.setEnvironment(getProxyDataSource());
testService.testChangeTransactionTypeToLOCAL();
}
/**
* Test change proxy transaction type to XA with specified transaction manager.
*
* @param testService sharding transaction test service
* @param aspect sharding transaction aspect
* @param transactionManager specified transaction manager
* @throws SQLException SQL exception
*/
public static void testChangeProxyTransactionTypeToXA(final ShardingTransactionalTestService testService, final ShardingTransactionalAspect aspect, final PlatformTransactionManager transactionManager) throws SQLException {
aspect.setTransactionManager(transactionManager);
aspect.setEnvironment(getProxyDataSource());
testService.testChangeTransactionTypeToXA();
}
/**
* Test change proxy transaction type to BASE with specified transaction manager.
*
* @param testService sharding transaction test service
* @param aspect sharding transaction aspect
* @param transactionManager specified transaction manager
* @throws SQLException SQL exception
*/
public static void testChangeProxyTransactionTypeToBASE(final ShardingTransactionalTestService testService, final ShardingTransactionalAspect aspect, final PlatformTransactionManager transactionManager) throws SQLException {
aspect.setTransactionManager(transactionManager);
aspect.setEnvironment(getProxyDataSource());
testService.testChangeTransactionTypeToBASE();
}
private static DataSource[] getProxyDataSource() throws SQLException {
DataSource dataSource = mock(DataSource.class);
Connection connection = mock(Connection.class);
DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class);
when(databaseMetaData.getDatabaseProductVersion()).thenReturn("5.6.0-Sharding-Proxy x.x.x");
when(connection.getMetaData()).thenReturn(databaseMetaData);
when(dataSource.getConnection()).thenReturn(connection);
return new DataSource[] {dataSource};
}
}
<?xml version="1.0"?>
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>[%-5level] %d{HH:mm:ss.SSS} [%thread] %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="org.apache.shardingsphere" level="warn" additivity="false">
<appender-ref ref="console"/>
</logger>
<root>
<level value="error" />
<appender-ref ref="console" />
</root>
</configuration>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册