官术网_书友最值得收藏!

Using DI pattern for dependent components

According to the DI pattern, dependent objects are given their dependencies at the time of the creation of the objects by some factory or third party. This factory coordinates each object in the system in such a way that each dependent object is not expected to create their dependencies. This means that we have to focus on defining the dependencies instead of resolving the dependencies of collaborating objects in the enterprise application. Let's look at the following image. You will learn that dependencies are injected into the objects that need them:

Dependency injection between the different collaborating components in the application

To illustrate this point, let's look at TransferService in the next section--a TransferService has dependency with AccountRepository and TransferRepository. Here, TransferService is capable of transferring money by any kind implementation of TransferRepository, that is, we can either use JdbcTransferRepository or JpaTransferRepository, depending on whichever comes along according to the deployment environment.

TransferServiceImpl is flexible enough to take on any TransferRepository it's given:

    package com.packt.chapter1.bankapp; 
    public class TransferServiceImpl implements TransferService { 
      private TransferRepository transferRepository; 
      private AccountRepository  accountRepository; 
      public TransferServiceImpl(TransferRepository transferRepository,
AccountRepository accountRepository) { this.transferRepository =
transferRepository;//TransferRepository is injected this.accountRepository = accountRepository;
//AccountRepository is injected } public void transferMoney(Long a, Long b, Amount amount) { Account accountA = accountRepository.findByAccountId(a); Account accountB = accountRepository.findByAccountId(b); transferRepository.transfer(accountA, accountB, amount); } }

Here you can see that TransferServiceImpl doesn't create its own repositories implementation. Instead, we have given the implementation of repositories at the time of construction as a constructor argument. This is a type of DI known as constructor injection. Here we have passed the repository interface type as an argument of the constructor. Now TransferServiceImpl could use any implementation of repositories, either JDBC, JPA, or mock objects. The point is that TransferServiceImpl isn't coupled to any specific implementation of repositories. It doesn't matter what kind of repository is used to transfer an amount from one account to another account, as long as it implements the repositories interfaces. If you are using the DI pattern of the Spring Framework, loose coupling is one of the key benefits. The DI pattern always promotes P2I, so each object knows about its dependencies by their associated interface rather than associated implementation, so the dependency can easily be swapped out with another implementation of that interface instead of changing to its dependent class implementation.

Spring provides support for assembling such an application system from its parts:

  • Parts do not worry about finding each other
  • Any part can easily be swapped out

The method for assembling an application system by creating associations between application parts or components is known as wiring. In Spring, there are many ways to wire collaborating components together to make an application system. For instance, we could use either an XML configuration file or a Java configuration file.

Now let's look at how to inject the dependencies of TransferRepository and AccountRepository into a TransferService with Spring:

    <?xml version="1.0" encoding="UTF-8"?> 
    <beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd"> 
    <bean id="transferService"  
class="com.packt.chapter1.bankapp.service.TransferServiceImpl"> <constructor-arg ref="accountRepository"/> <constructor-arg ref="transferRepository"/> </bean> <bean id="accountRepository" class="com.
packt.chapter1.bankapp.repository.JdbcAccountRepository"/> <bean id="transferRepository" class="com.
packt.chapter1.bankapp.repository.JdbcTransferRepository"/> </beans>

Here, TransferServiceImpl, JdbcAccountRepository, and JdbcTransferRepository are declared as beans in Spring. In the case of the TransferServiceImpl bean, it's constructed, passing a reference to the AccountRepository and TransferRepository beans as constructor arguments. You might like to know that Spring also allows you to express the same configuration using Java.

Spring offers Java-based configuration as an alternative to XML:

    package com.packt.chapter1.bankapp.config; 
 
    import org.springframework.context.annotation.Bean; 
    import org.springframework.context.annotation.Configuration; 
 
    import com.packt.chapter1.bankapp.repository.AccountRepository; 
    import com.packt.chapter1.bankapp.repository.TransferRepository; 
    import 
com.packt.chapter1.bankapp.repository.jdbc.JdbcAccountRepository; import
com.packt.chapter1.bankapp.repository.jdbc.JdbcTransferRepository; import com.packt.chapter1.bankapp.service.TransferService; import com.packt.chapter1.bankapp.service.TransferServiceImpl; @Configuration public class AppConfig { @Bean public TransferService transferService(){ return new TransferServiceImpl(accountRepository(),
transferRepository()); } @Bean public AccountRepository accountRepository() { return new JdbcAccountRepository(); } @Bean public TransferRepository transferRepository() { return new JdbcTransferRepository(); } }

The benefits of the dependency injection pattern are the same whether you are using an XML-based or a Java-based configuration:

  • Dependency injection promotes loose coupling. You can remove hard-coded dependencies with best practice P2I, and you could provide dependencies from outside the application by using the Factory pattern and its built-in swappable and pluggable implementation
  • The DI pattern promotes the composition design of object-oriented programming rather than inheritance programming

Although TransferService depends on an AccountRepository and TransferRepository, it doesn't care about what type (JDBC or JPA) of implementations of AccountRepository and TransferRepository are used in the application. Only Spring, through its configuration (XML- or Java-based), knows how all the components come together and are instantiated with their required dependencies using the DI pattern. DI makes it possible to change those dependencies with no changes to the dependent classes--that is, we could use either a JDBC implementation or a JPA implementation without changing the implementation of AccountService.

In a Spring application, an implementation of the application context (Spring offers AnnotationConfigApplicationContext for Java-based and ClassPathXmlApplicationContext for XML-based implementations) loads bean definitions and wires them together into a Spring container. The application context in Spring creates and wires the Spring beans for the application at startup. Look into the implementation of the Spring application context with Java-based configuration--It loads the Spring configuration files (AppConfig.java for Java and Sprig.xml for XML) located in the application's classpath. In the following code, the main() method of the TransferMain class uses a AnnotationConfigApplicationContext class to load the configuration class AppConfig.java and get an object of the AccountService class.

Spring offers Java-based configuration as an alternative to XML:

    package com.packt.chapter1.bankapp; 
 
    import org.springframework.context.ConfigurableApplicationContext; 
    import 
org.springframework.context.annotation
.AnnotationConfigApplicationContext; import com.packt.chapter1.bankapp.config.AppConfig; import com.packt.chapter1.bankapp.model.Amount; import com.packt.chapter1.bankapp.service.TransferService; public class TransferMain { public static void main(String[] args) { //Load Spring context ConfigurableApplicationContext applicationContext =
new AnnotationConfigApplicationContext(AppConfig.class); //Get TransferService bean TransferService transferService =
applicationContext.getBean(TransferService.class); //Use transfer method transferService.transferAmmount(100l, 200l,
new Amount(2000.0)); applicationContext.close(); } }

Here we have a quick introduction to the dependency injection pattern. You'll learn a lot more about the DI pattern in the coming chapters of this book. Now let's look at another way of simplifying Java development using Spring's declarative programming model through aspects and proxy patterns.

主站蜘蛛池模板: 铁岭县| 庄浪县| 临高县| 中超| 碌曲县| 哈密市| 南江县| 双柏县| 萨迦县| 阳东县| 恩平市| 百色市| 博兴县| 太康县| 新绛县| 北海市| 柘荣县| 密云县| 阿拉尔市| 淮北市| 临城县| 华蓥市| 白城市| 疏勒县| 徐闻县| 陕西省| 资兴市| 辽宁省| 宜昌市| 育儿| 抚顺县| 明光市| 五指山市| 柘城县| 仪征市| 永泰县| 湘西| 新乡县| 靖江市| 右玉县| 多伦县|