пятница, 22 июня 2018 г.

Зависимые бины и аннотация @DependsOn

Бывают случаи когда ваш бин зависит от 1 или нескольких других бинов приложения Spring - здесь на помощь приходит аннотация @DependsOn, которая заставляет контейнер сначала создавать бины зависимостей - и только потом зависящий от них бин. В параметрах аннотации указываются имена бинов. Аннотацию можно использовать или в файле конфигурации приложения совместно с аннотацией @Bean:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
 
@Configuration
public class AppConfig {

   @Bean("beanOne")
   @DependsOn(value = { "beanTwo", "beanThree" })
   public BeanOne getBeanOne() {
      return new BeanOne();
   }

   @Bean("beanTwo")
   public BeanTwo getBeanTwo() {
      return new BeanTwo();
   }

   @Bean("beanThree")
   public BeanThree getBeanThree() {
      return new BeanThree();
   }
}
 или аннотировать класс бина:
@Component
@DependsOn(value = { "beanTwo", "beanThree" })
 public class BeanOne {
 
   @Autowired
   private BeanTwo beanTwo;

   @Autowired
   private BeanThree beanThree;

...............
}
Аналогичный механизм есть для синглтонов EJB стека JavaEE - только там в качестве параметров аннотации указывают имена классов и кроме того, учитывая что контейнер EJB по-умолчанию использует ленивое создание бинов (в отличие от Spring - он по-умолчанию создает бины сразу при старте приложения), то аналогичная аннотация используется как правило совместно с аннотацией @Startup, которая заставляет EJB создавать бины сразу при старте приложения - пример:
import javax.ejb.DependsOn;
import javax.ejb.Singleton;
import javax.ejb.Startup;

@Singleton
@Startup
@DependsOn("EjbConfig")
public class EjbMain {

    .....................

}

четверг, 21 июня 2018 г.

Spring - класс JdbcDaoSupport и паттерн DAO

Паттерн DAO - Data Access Object - очень коротко - это когда все методы доступа к данным вы собираете (инкапсулируете) в одном классе.
Класс JdbcDaoSupport является оболочкой для JdbcTemplate и позволяет удобно делать свои DAO расширяя класс JdbcDaoSupport - при этом в нашем классе для работы необходимо только указать через конструктор реализацию DataSource при создании экземпляра нашего DAO. Напишем свой класс DaoJDBC который расширяет класс JdbcDaoSupport и сделаем внедрение через конструктор бина, реализующего DataSource:

@Repository
public class DaoJDBC extends JdbcDaoSupport {
   
    @Inject   // или @Autowired
    public DaoJDBC(DataSource dataSource) {
        this.setDataSource(dataSource);
    }

    public void clearAll() {
        String sql = "delete from hosts";
        this.getJdbcTemplate().update(sql);
    }
.................// + другие операции с базой
}
при этом экземпляр JdbcTemplate будет создан автоматически и будет доступен из нашего DAO через this.getJdbcTemplate() - дальше в классе DaoJDBC нам доступен весь инструментарий JdbcTemplate через this.getJdbcTemplate().

Spring - класс JdbcTemplate и внедрение через конструктор - constructor injection.

Spring обеспечивает очень удобную поддержку JDBC с помощью класса JdbcTemplate, которому для работы необходимо только указать через конструктор реализацию DataSource при создании экземпляра JdbcTemplate.
Пусть например мы хотим воспользоваться паттерном DAO (Data Access Object - обьект доступа к данным ) - напишем свой класс DaoJDBC который расширяет класс JdbcTemplate и сделаем внедрение через конструктор бина, реализующего DataSource:
@Repository
public class DaoJDBC extends JdbcTemplate {
   
    @Inject   // или @Autowired
    public DaoJDBC(DataSource dataSource) {
        this.setDataSource(dataSource);
    }

    public void clearAll() {
        String sql = "delete from hosts";
        this.update(sql);
    }
.................// + другие операции с базой
}
 Здесь как раз и происходит внедрение через конструктор бина dataSource,  который мы рассматривали в предыдущей заметке. Дальше в классе DaoJDBC нам доступен весь инструментарий JdbcTemplate через this.
Можно сделать и по-другому - сделать реализацию бина JdbcTemplate в файле конфигурации приложения - а дальше внедрять его куда нам нужно и использовать:
@Inject   // или @Autowired
private JdbcTemplate jdbcTemplate;
В этом случае файл конфигурации приложения следующий:
@Configuration
@ComponentScan(basePackages = {"PKG"})
public class AppContext {

   @Bean(destroyMethod = "close")
    public DataSource dataSource() {
        BasicDataSource bds = new BasicDataSource();
        bds.setDriverClassName("org.apache.derby.jdbc.EmbeddedDriver");
        bds.setUrl("jdbc:derby:./db/primer");
        bds.setPassword("12345");
        bds.setUsername("romka");
        return bds;
    }
    
    @Bean
    public JdbcTemplate jdbcTemplate () {
        return new JdbcTemplate(this.dataSource());
    }
}
И еще - класс JdbcTemplate является безопасным в отношении потоков.
Исходники - https://sourceforge.net/projects/j-pkg/

Spring - интерфейс DataSource и JDBC пул соединений

Для доступа к данным в JDBC необходима реализация интерфейса javax.sql.DataSource - таких реализаций может быть много - в том числе и таких, которые на каждую операцию с БД открывают новое соединение - это очень затратно и медленно - мы их сразу опустим и рассмотрим пул как рабочую схему. Существует много реализаций пула:
- Apache commons dbcp2  (dbcp = database connection pool);
- HikariCP;
а также c3p0, BoneCP, Vibur и много других - настраиваются они все идентично и мы рассмотрим Apache.
Пул постоянно поддерживает несколько готовых соединений с базой - для текущей операции с базой практически мгновенно предоставляется готовое соединение из пула - а затем когда операция будет отработана это соединение менеджер пула помечает как свободное и возвращает в пул - в результате почти не тратится время на создание нового соединения если сравнивать с обычным подходом - это очень краткое и упрощенное описание работы пула.
Необходимо будет добавить зависимость в maven:
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-dbcp2</artifactId>
    <version>2.4.0</version>
</dependency>
в свою очередь эта зависимость "зацепит" и другую - commons-pool2. Будем использовать БД Derby в embedded-mode.
В файл конфигурации приложения Spring надо будет добавить бин, реализующий интерфейс javax.sql.DataSource с помощью класса BasicDataSource из apache commons dbcp2:
@Bean(destroyMethod = "close")
    public DataSource dataSource() {
        BasicDataSource bds = new BasicDataSource();
        bds.setDriverClassName("org.apache.derby.jdbc.EmbeddedDriver");
        bds.setUrl("jdbc:derby:./db/primer");
        bds.setPassword("12345");
        bds.setUsername("romka");
        return bds;
    }
Вот и все пока - а дальше мы покажем как его использовать.
Да чуть не забыл - вот пример с исходниками

суббота, 9 июня 2018 г.

Spring - внешний файл свойств приложения

Файл конфигурации приложения:

@Configuration
@ComponentScan(basePackages = {"jspv"})
@PropertySource(value = {"file:cfg/jivam.properties"})
//@PropertySource(value = {"classpath:hofat.properties"})
public class AppContext {
   
    @Value("${top}")
    private String top;
  
    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }

   
}
то что нужно добавить выделено жирным шрифтом - это аннотация @PropertySource и бин propertySourcesPlaceholderConfigurer. Теперь в любом компоненте Spring из пакета "jspv" можно внедрять свойства из внешнего файла:
    @Value("${top}")
    private String top;
пример содержимого файла свойств:
####
perevod=en
skin=com.jtattoo.plaf.mcwin.McWinLookAndFeel
top=JIVAM - Java Image Viewer And Manipulator, build 26-01-18.
###
исходники лежат на https://sourceforge.net/projects/jivam/files/?source=navbar

Взаимодействие между приложениями и Watch Service

Взаимодействие между разными приложениями Java можно сделать с помощью файловой системы, базы данных и JMS. Рассмотрим случай ФС - в Java ...