2015-05-08 3 views
3

Допустим, есть @Service и @Repository интерфейсы, такие как следующие:Создание Spring @Service экземпляра с @Transactional методами вручную из Java

@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); 
    } 

} 

Это часть работы приложения, все настроено, чтобы получить доступ к единой базе данных и все работает отлично.

Теперь, я хотел бы иметь возможность создавать автономные работающий экземпляр OrderService с автоматической проводкой OrderDao с использованием чистой Java с JDBCURL, указанной в Java коде, что-то вроде этого:

final int tenantId = 3578; 
final String jdbcUrl = "jdbc:mysql://localhost:3306/database_" + tenantId; 
OrderService orderService = someMethodWithSpringMagic(appContext, jdbcUrl); 

Как вы можете видеть, я хотел бы представить многоквартирную архитектуру с арендатора на базу данных стратегия для существующего приложения на основе Spring.

Пожалуйста, обратите внимание, что я был в состоянии добиться того, что довольно легко раньше с самостоятельной Реализуемым JdbcTemplate подобной логики также с JDBC транзакции работают правильно, так что это очень действуют задача.

Обратите внимание, что мне нужна довольно простая логика транзакций, чтобы начать транзакцию, выполнить несколько запросов в методе обслуживания в рамках этой транзакции и затем зафиксировать ее/откат при исключении.

Большинство решений в Интернете по поводу мульти-аренды с Spring предлагают указать конкретные единицы сохраняемости в XML-конфигурации и/или используя конфигурацию аннотаций на основе, которая весьма негибкой, потому что для того, чтобы добавить новый URL базы данных всего приложения должна быть остановлена , xml config/аннотационный код должен быть изменен и приложение запущено.

Итак, в основном я ищу фрагмент кода, который может создать @Service так же, как Spring создает его внутри, после того как свойства считываются из XML-конфигов/аннотаций. Я также изучаю использование ProxyBeanFactory, потому что Spring использует AOP для создания экземпляров службы (поэтому я думаю, что простой добрый многопользовательский ООП - это не путь сюда).

весна достаточно гибкой, чтобы позволить этому относительно простой случай повторного использования кода?

Любые намеки будут весьма благодарны и если я найти полный ответ на этот вопрос, я выложу его здесь для будущих поколений :)

+2

HIbernate имеет [из коробки поддержку для нескольких арендаторов] (http://docs.jboss.org/hibernate/orm/4.2/devguide/en-US/html/ch16.html), проверьте это перед попыткой твой собственный. Также около 8 лет назад мы уже писали общее решение, которое было задокументировано [здесь] (https://mdeinum.wordpress.com/2007/01/05/one-application-per-client-database/), а код [ здесь] (https://github.com/mdeinum/spring-utils) –

+0

@ M.Deinum - ** Большое спасибо ** за быстрый и полезный ответ - сейчас я исследую его и расскажу о результатах. BTW, я читал о поддержке 'Hibernate' поддержки многопользовательской аренды, но, к сожалению, в этом проекте используется JpaRepository', и я хотел бы использовать как можно больше существующей кодовой базы, не переписывая ее. – Yura

+0

Вы действительно прочитали инструкцию? Он встроен в спящий режим и прозрачен ... Прежде чем судить, я настоятельно рекомендую прочитать руководство и ссылки, которые я вам дал. –

ответ

2

HIbernate имеет out of the box support for multi tenancy, проверьте это, прежде чем пытаться самостоятельно. Для Hibernate требуются MultiTenantConnectionProvider и CurrentTenantIdentifierResolver, для которых по умолчанию реализованы версии, но вы всегда можете написать свою собственную реализацию. Если это всего лишь изменение схемы, на самом деле это довольно просто реализовать (выполнить запрос перед возвратом соединения). Else держите карту источников данных и получите экземпляр от этого или создайте новый экземпляр.

Около 8 лет назад мы уже писали общее решение, которое было задокументировано here, а код here. Это не характерно для спящего режима и может использоваться в основном для всего, что вам нужно для переключения. Мы использовали его для DataSource с, а также некоторые связанные с Интернетом вещи (например, среди других).

+0

Ваше решение работает как очарование - большое спасибо за помощь! – Yura

+0

У меня есть другой связанный с этим вопрос - вы пытались использовать свое решение с помощью соединителя Tomcat 'Http11NioProtocol' (или аналогичных разъемов), который предоставляет функции« асинхронного ввода-вывода »? Я думаю, не должно быть проблем, так как «я думаю, что Tomcat обрабатывает это прозрачно», и после того, как данные запроса считываются из сети асинхронно, они обрабатываются одним потоком, но, пожалуйста, сообщите – Yura

+0

Нет, мы этого не сделали, в те дни. Таким образом, вы были бы здесь по своему усмотрению :) –

2

Создание транзакционного прокси для аннотированный службы не является сложной задачей, но Я не уверен, что вам это действительно нужно. Чтобы выбрать базу данных для 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); 
    } 
} 

Конечно, если вы хотите использовать пул соединений, вы должны разработать его немного, например, с использованием пула соединений для каждого арендатора.

+0

Спасибо за ваш ответ - это очень похоже на решение @ M.Deinum из комментария, а также должно решить мою проблему. Я думал о таких решениях, но обычно я не очень хочу использовать * общедоступные статические экземпляры *, поэтому я подумал, что, возможно, есть и другие решения, которые полагаются на * нестатические экземпляры *. Однако похоже, что это невозможно с Spring или возможно с большим количеством хлопот - пожалуйста, сообщите – Yura

+0

Мне понравилось ваше решение, но найдено решение, предложенное M.Deinum (указав заменяемый источник данных как «TargetSource») больше «Spring-like «и вот почему я принял его решение :) – Yura

Смежные вопросы