2015-08-26 4 views
4

У меня есть приложение 3.2.14.RELEASE spring, и я использую java config для проводов и ввода компонентов.Spring Java Config - @DependsOn chaining

В моем случае мне нужно

  1. настроить SSH туннель
  2. создать DataSource так, что он использует тот же SSH туннель сессии
  3. создать класс Query, который выполняет запрос SQL с помощью JdbcTemplate

Я настроить мой ApplicationContext связывают это с @DependsOn аннотациями связать три фасоли

package com.b.e.kpireport; 

@Configuration 
@ComponentScan(basePackages = {"com.b.e.kpireport" }) 
public class ApplicationContext { 

    @Bean(name = "sshTunnel") 
    public SSHTunnel getSSHTunnel() { 
     return new SSHTunnel(); 
    } 

    @Bean(name = "dataSource") 
    @DependsOn("sshTunnel") 
    public DataSource getDataSource() { 

     DriverManagerDataSource dataSource = new DriverManagerDataSource(); 
     dataSource.setDriverClassName(driver); 
     dataSource.setUrl(jdbcUrl); 
     dataSource.setUsername(username); 
     dataSource.setPassword(password); 
     logger.info("getDataSource():"+jdbcUrl+":"+username+"/"+password+":"+driver); 
     return dataSource; 
    } 

    @Bean 
    @DependsOn("dataSource") 
    public Query getQuery() { 
     return new Query(); 
    } 
} 

Класс запроса выглядит

class Query { 

    private JdbcTemplate jdbcTemplate; 

    @Autowired 
    private DataSource dataSource; 

    @Autowired 
    private SSHTunnel sshTunnel; 

    public void runQuery() { 
     sshTunnel.openSession(); 
     jdbcTemplate = new JdbcTemplate(dataSource); 
     jdbcTemplate.execute(sql); 
    } 

Независимо то, что я пытался, я вижу, что DataSource инициализируется перед SSHTunnel

Aug 26, 2015 5:20:44 PM com.b.e.kpireport.ApplicationContext getDataSource 
INFO: getDataSource():jdbc:mysql://localhost:3006/centstorage:davidobrien/MnBufeuwncv3eR:com.mysql.jdbc.Driver 
Aug 26, 2015 5:20:44 PM com.b.e.kpireport.SSHTunnel openSession 
INFO: openSession 

Любые предложения о том, как я могу гарантировать, правильный порядок инициализации боба?

+0

и когда вы пытаетесь использовать 'public DataSource getDataSource (SSHTunnel tunnel)' - даже если вам это не нужно - это помогает? – sodik

+0

Кстати: вы открываете сессию ssh только при запуске запроса - так что это должно быть после создания источника данных. – sodik

+0

@sodik - сеанс ssh в настоящее время открыт первым, и я могу исследовать это больше, но это все еще не затрагивает порядок создания bean-компонента в этом вопросе. Также в каком классе вы добавляете метод выше, я предполагаю, что это Query.class? – emeraldjava

ответ

0

Решение может быть на самом деле просто:

@Configuration 
public class ApplicationContext { 
    @Bean(name = "sshTunnel") 
    public SSHTunnel getSSHTunnel() { 
     return new SSHTunnel(); 
    } 

    @Bean(name = "dataSource") 
    public DataSource getDataSource() { 
     getSHTunnel(); 
     DriverManagerDataSource dataSource = new DriverManagerDataSource(); 
     // ... 
     return dataSource; 
    } 

    @Bean 
    public Query getQuery() { 
     return new Query(getSSHTunnel(), getDataSource()); 
    } 
} 

Мы используем эту модель вызова методов класса конфигурации (внутри класса) очень часто. При создании контекста методы не будут вызываться непосредственно в вашем классе, но в его подклассе Spring создает динамически. Это гарантирует, что даже если вы вызовете метод (например, getSSHTunnel()) несколько раз, соответствующий компонент будет создан только один раз (т. Е. Будет создан только один туннель).

Я также предпочитаю передавать зависимости через конструктор, а не с @Autowired - он менее волшебный и легче тестировать. Это необязательно.

Я не знаю, почему использование @DependsOn не работает для вас. Когда я пробовал его локально, он работал (с той же версией Spring). В любом случае, приведенное выше является примером того, как обойтись без него целиком.


Редактировать в ответ на комментарий:

Но в этом случае вы можете просто удалить все пружинные аннотации, так как вы не делаете какие-либо инъекции зависимостей. Вы в основном просто получили простой старый объект java

Это неправда. Как я уже сказал, вызов метода в объекте @Configuration не вызывает ваш метод напрямую, но его версия переопределяется Spring returning the bean according to configuration. Это позволяет выполнять надлежащую инъекцию зависимости, например. в тестах, как это:

@Configuration 
public class TestDependencies { 
    @Bean(name="dataSource") 
    public DataSource getDataSource() { 
     return new MockDataSource(); 
    } 
} 
... 
ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationContext.class, TestDependencies.class); 
context.getBean("dataSource"); // returns MockDataSource 

Другими словами, вызов методов, как getDataSource() фактически эквивалентно тому, что зависимость @Autowired или с помощью context.getBean().У этого подхода нет никаких ошибок AFAIK (если вы не передадите аргументы методам @Bean, в противном случае все станет немного странно), и мы использовали его в течение длительного времени.

+0

Но в этом случае вы можете просто удалить все весенние аннотации, так как вы не выполняете инъекции зависимостей. Вы просто получили простой старый объект java – emeraldjava

+0

Это неправда, см. Редактирование в моем ответе, комментарий слишком ограничивал объяснение. – Mifeet

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