从 Java 使用 @Transactional 方法手动创建 Spring @Service 实例
Create Spring @Service instance with @Transactional methods manually from Java
假设有 @Service
和 @Repository
接口,如下所示:
@Repository
public interface OrderDao extends JpaRepository<Order, Integer> {
}
public interface OrderService {
void saveOrder(Order order);
}
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderDao orderDao;
@Override
@Transactional
public void saveOrder(Order order) {
orderDao.save(order);
}
}
这是工作应用程序的一部分,一切都配置为访问单个数据库,一切正常。
现在,我希望有可能 使用自动连接的 OrderDao 使用 pure Java[创建 OrderService 的独立工作实例=51=] 在 Java 代码 中指定了 jdbcUrl,像这样:
final int tenantId = 3578;
final String jdbcUrl = "jdbc:mysql://localhost:3306/database_" + tenantId;
OrderService orderService = someMethodWithSpringMagic(appContext, jdbcUrl);
如您所见,我想介绍 多租户架构 以及 每个数据库一个租户 策略到现有 Spring基于应用程序。
请注意,在使用自我实现的类似 jdbcTemplate 的逻辑以及 JDBC 事务正常工作之前,我可以很容易地 实现 ,所以这是 非常有效的任务。
另请注意,我需要非常简单的事务逻辑来启动事务,在该事务范围内的服务方法中执行多个请求,然后在出现异常时提交it/rollback .
Web 上关于 Spring 多租户的大多数解决方案建议在 xml 配置 AND/OR 中使用基于注解的配置指定具体的持久性单元 不灵活 因为为了添加新数据库 url 整个应用程序应该停止,xml config/annotation 代码应该更改并启动应用程序。
所以,基本上我正在寻找一段能够创建 @Service
的代码,就像 Spring 在从 XML 配置/注释中读取属性后在内部创建它一样.我也在考虑为此使用 ProxyBeanFactory
,因为 Spring 使用 AOP
来创建服务实例(所以我想简单的好旧的可重用 OOP 不是去这里的方法).
Spring是否足够灵活以允许这种相对简单的代码重用案例?
任何提示将不胜感激,如果我找到了这个问题的完整答案,我会post在这里为后代提供:)
为带注释的服务创建事务代理并不是一项艰巨的任务,但我不确定您是否真的需要它。要为 tenantId 选择数据库,我猜你只需要专注于 DataSource
界面。
例如,使用简单的驱动程序管理的数据源:
public class MultitenancyDriverManagerDataSource extends DriverManagerDataSource {
@Override
protected Connection getConnectionFromDriverManager(String url,
Properties props) throws SQLException {
Integer tenant = MultitenancyContext.getTenantId();
if (tenant != null)
url += "_" + tenant;
return super.getConnectionFromDriverManager(url, props);
}
}
public class MultitenancyContext {
private static ThreadLocal<Integer> tenant = new ThreadLocal<Integer>();
public static Integer getTenantId() {
return tenant.get();
}
public static void setTenatId(Integer value) {
tenant.set(value);
}
}
当然,如果要使用连接池,则需要详细说明一下,例如每个租户使用一个连接池。
HIbernate 有 out of the box support for multi tenancy, check that out before trying your own. Hibernate requires a MultiTenantConnectionProvider
and CurrentTenantIdentifierResolver
,其中有开箱即用的默认实现,但您始终可以编写自己的实现。如果它只是模式更改,那么实现起来实际上非常简单(在返回连接之前执行查询)。否则持有一个数据源映射并从中获取一个实例,或者创建一个新实例。
大约 8 年前,我们已经编写了一个通用解决方案,并记录在案 here and the code is here。它不是专门针对休眠的,基本上可以与您需要切换的任何东西一起使用。我们将它用于 DataSource
s 以及一些网络相关的东西(主题等等)。
假设有 @Service
和 @Repository
接口,如下所示:
@Repository
public interface OrderDao extends JpaRepository<Order, Integer> {
}
public interface OrderService {
void saveOrder(Order order);
}
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderDao orderDao;
@Override
@Transactional
public void saveOrder(Order order) {
orderDao.save(order);
}
}
这是工作应用程序的一部分,一切都配置为访问单个数据库,一切正常。
现在,我希望有可能 使用自动连接的 OrderDao 使用 pure Java[创建 OrderService 的独立工作实例=51=] 在 Java 代码 中指定了 jdbcUrl,像这样:
final int tenantId = 3578;
final String jdbcUrl = "jdbc:mysql://localhost:3306/database_" + tenantId;
OrderService orderService = someMethodWithSpringMagic(appContext, jdbcUrl);
如您所见,我想介绍 多租户架构 以及 每个数据库一个租户 策略到现有 Spring基于应用程序。
请注意,在使用自我实现的类似 jdbcTemplate 的逻辑以及 JDBC 事务正常工作之前,我可以很容易地 实现 ,所以这是 非常有效的任务。
另请注意,我需要非常简单的事务逻辑来启动事务,在该事务范围内的服务方法中执行多个请求,然后在出现异常时提交it/rollback .
Web 上关于 Spring 多租户的大多数解决方案建议在 xml 配置 AND/OR 中使用基于注解的配置指定具体的持久性单元 不灵活 因为为了添加新数据库 url 整个应用程序应该停止,xml config/annotation 代码应该更改并启动应用程序。
所以,基本上我正在寻找一段能够创建 @Service
的代码,就像 Spring 在从 XML 配置/注释中读取属性后在内部创建它一样.我也在考虑为此使用 ProxyBeanFactory
,因为 Spring 使用 AOP
来创建服务实例(所以我想简单的好旧的可重用 OOP 不是去这里的方法).
Spring是否足够灵活以允许这种相对简单的代码重用案例?
任何提示将不胜感激,如果我找到了这个问题的完整答案,我会post在这里为后代提供:)
为带注释的服务创建事务代理并不是一项艰巨的任务,但我不确定您是否真的需要它。要为 tenantId 选择数据库,我猜你只需要专注于 DataSource
界面。
例如,使用简单的驱动程序管理的数据源:
public class MultitenancyDriverManagerDataSource extends DriverManagerDataSource {
@Override
protected Connection getConnectionFromDriverManager(String url,
Properties props) throws SQLException {
Integer tenant = MultitenancyContext.getTenantId();
if (tenant != null)
url += "_" + tenant;
return super.getConnectionFromDriverManager(url, props);
}
}
public class MultitenancyContext {
private static ThreadLocal<Integer> tenant = new ThreadLocal<Integer>();
public static Integer getTenantId() {
return tenant.get();
}
public static void setTenatId(Integer value) {
tenant.set(value);
}
}
当然,如果要使用连接池,则需要详细说明一下,例如每个租户使用一个连接池。
HIbernate 有 out of the box support for multi tenancy, check that out before trying your own. Hibernate requires a MultiTenantConnectionProvider
and CurrentTenantIdentifierResolver
,其中有开箱即用的默认实现,但您始终可以编写自己的实现。如果它只是模式更改,那么实现起来实际上非常简单(在返回连接之前执行查询)。否则持有一个数据源映射并从中获取一个实例,或者创建一个新实例。
大约 8 年前,我们已经编写了一个通用解决方案,并记录在案 here and the code is here。它不是专门针对休眠的,基本上可以与您需要切换的任何东西一起使用。我们将它用于 DataSource
s 以及一些网络相关的东西(主题等等)。