加載依賴項 java編程實現,依賴注入(di)模式_Java依賴注入– DI設計模式示例教程

 2023-11-19 阅读 26 评论 0

摘要:依賴注入(di)模式加載依賴項 java編程實現。Java Dependency Injection design pattern allows us to remove the hard-coded dependencies and make our application loosely coupled, extendable and maintainable. We can implement dependency injection in java to move

依賴注入(di)模式

加載依賴項 java編程實現。Java Dependency Injection design pattern allows us to remove the hard-coded dependencies and make our application loosely coupled, extendable and maintainable. We can implement dependency injection in java to move the dependency resolution from compile-time to runtime.

Java Dependency Injection設計模式允許我們刪除硬編碼的依賴關系,并使我們的應用程序松散耦合,可擴展和可維護。 我們可以在Java中實現依賴注入,以將依賴解析從編譯時移至運行時。

Java依賴注入 (Java Dependency Injection)

ioc注入。Java Dependency injection seems hard to grasp with theory, so I would take a simple example and then we will see how to use dependency injection pattern to achieve loose coupling and extendability in the application.

Java依賴注入似乎很難用理論來理解,因此我將舉一個簡單的例子,然后我們將看到如何使用依賴注入模式來實現應用程序中的松散耦合和可擴展性。

ioc依賴注入的三種方式、Let’s say we have an application where we consume EmailService to send emails. Normally we would implement this like below.

假設我們有一個應用程序,我們在其中使用EmailService發送電子郵件。 通常我們會像下面這樣實現。

package com.journaldev.java.legacy;public class EmailService {public void sendEmail(String message, String receiver){//logic to send emailSystem.out.println("Email sent to "+receiver+ " with Message="+message);}
}

EmailService class holds the logic to send an email message to the recipient email address. Our application code will be like below.

EmailService類包含將電子郵件消息發送到收件人電子郵件地址的邏輯。 我們的應用程序代碼如下所示。

package com.journaldev.java.legacy;public class MyApplication {private EmailService email = new EmailService();public void processMessages(String msg, String rec){//do some msg validation, manipulation logic etcthis.email.sendEmail(msg, rec);}
}

Our client code that will use MyApplication class to send email messages will be like below.

我們的客戶端代碼將使用MyApplication類發送電子郵件,如下所示。

package com.journaldev.java.legacy;public class MyLegacyTest {public static void main(String[] args) {MyApplication app = new MyApplication();app.processMessages("Hi Pankaj", "pankaj@abc.com");}}

At first look, there seems nothing wrong with the above implementation. But above code logic has certain limitations.

乍一看,上述實現似乎沒有錯。 但是以上代碼邏輯有一定的局限性。

  • MyApplication class is responsible to initialize the email service and then use it. This leads to hard-coded dependency. If we want to switch to some other advanced email service in the future, it will require code changes in MyApplication class. This makes our application hard to extend and if email service is used in multiple classes then that would be even harder.

    MyApplication類負責初始化電子郵件服務,然后使用它。 這導致硬編碼的依賴性。 如果將來想切換到其他高級電子郵件服務,則需要在MyApplication類中更改代碼。 這使我們的應用程序難以擴展,如果在多個類中使用電子郵件服務,則將更加困難。
  • If we want to extend our application to provide an additional messaging feature, such as SMS or Facebook message then we would need to write another application for that. This will involve code changes in application classes and in client classes too.

    如果我們想擴展應用程序以提供其他消息傳遞功能,例如SMS或Facebook消息,那么我們需要為此編寫另一個應用程序。 這將涉及應用程序類和客戶端類中的代碼更改。
  • Testing the application will be very difficult since our application is directly creating the email service instance. There is no way we can mock these objects in our test classes.

    由于我們的應用程序是直接創建電子郵件服務實例,因此測試該應用程序將非常困難。 我們無法在測試類中模擬這些對象。

One can argue that we can remove the email service instance creation from MyApplication class by having a constructor that requires email service as an argument.

可以說,我們可以通過使用需要電子郵件服務作為參數的構造函數來從MyApplication類中刪除電子郵件服務實例的創建。

package com.journaldev.java.legacy;public class MyApplication {private EmailService email = null;public MyApplication(EmailService svc){this.email=svc;}public void processMessages(String msg, String rec){//do some msg validation, manipulation logic etcthis.email.sendEmail(msg, rec);}
}

But in this case, we are asking client applications or test classes to initializing the email service that is not a good design decision.

但是在這種情況下,我們要求客戶端應用程序或測試類初始化電子郵件服務,這不是一個好的設計決定。

Now let’s see how we can apply java dependency injection pattern to solve all the problems with the above implementation. Dependency Injection in java requires at least the following:

現在,讓我們看看如何應用Java依賴注入模式來解決上述實現的所有問題。 Java中的依賴注入至少需要滿足以下條件:

  1. Service components should be designed with base class or interface. It’s better to prefer interfaces or abstract classes that would define contract for the services.

    服務組件應使用基類或接口進行設計。 最好選擇為服務定義合同的接口或抽象類。
  2. Consumer classes should be written in terms of service interface.

    消費者類應根據服務接口編寫。
  3. Injector classes that will initialize the services and then the consumer classes.

    將初始化服務的注入器類,然后將初始化使用者類。

Java依賴注入–服務組件 (Java Dependency Injection – Service Components)

For our case, we can have MessageService that will declare the contract for service implementations.

對于我們的情況,我們可以使用MessageService來聲明服務實現的合同。

package com.journaldev.java.dependencyinjection.service;public interface MessageService {void sendMessage(String msg, String rec);
}

Now let’s say we have Email and SMS services that implement the above interfaces.

現在,我們有實現上述接口的電子郵件和SMS服務。

package com.journaldev.java.dependencyinjection.service;public class EmailServiceImpl implements MessageService {@Overridepublic void sendMessage(String msg, String rec) {//logic to send emailSystem.out.println("Email sent to "+rec+ " with Message="+msg);}}
package com.journaldev.java.dependencyinjection.service;public class SMSServiceImpl implements MessageService {@Overridepublic void sendMessage(String msg, String rec) {//logic to send SMSSystem.out.println("SMS sent to "+rec+ " with Message="+msg);}}

Our dependency injection java services are ready and now we can write our consumer class.

我們的依賴項注入Java服務已準備就緒,現在我們可以編寫我們的使用者類。

Java依賴注入–服務使用者 (Java Dependency Injection – Service Consumer)

We are not required to have base interfaces for consumer classes but I will have a Consumer interface declaring contract for consumer classes.

我們不需要具有用于消費者類的基本接口,但是我將具有一個用于聲明消費者類合同的Consumer接口。

package com.journaldev.java.dependencyinjection.consumer;public interface Consumer {void processMessages(String msg, String rec);
}

My consumer class implementation is like below.

我的消費者類實現如下。

package com.journaldev.java.dependencyinjection.consumer;import com.journaldev.java.dependencyinjection.service.MessageService;public class MyDIApplication implements Consumer{private MessageService service;public MyDIApplication(MessageService svc){this.service=svc;}@Overridepublic void processMessages(String msg, String rec){//do some msg validation, manipulation logic etcthis.service.sendMessage(msg, rec);}}

Notice that our application class is just using the service. It does not initialize the service that leads to better “separation of concerns“. Also use of service interface allows us to easily test the application by mocking the MessageService and bind the services at runtime rather than compile time.

請注意,我們的應用程序類僅在使用服務。 它不會初始化導致更好的“ 關注點分離 ”的服務。 服務接口的使用還使我們能夠通過模擬MessageService輕松測試應用程序,并在運行時(而不是在編譯時)綁定服務。

Now we are ready to write java dependency injector classes that will initialize the service and also consumer classes.

現在,我們準備編寫java依賴注入程序類該類將初始化服務以及使用者類。

Java依賴注入–注入器類 (Java Dependency Injection – Injectors Classes)

Let’s have an interface MessageServiceInjector with method declaration that returns the Consumer class.

讓我們有一個帶有方法聲明的MessageServiceInjector接口,該方法聲明返回Consumer類。

package com.journaldev.java.dependencyinjection.injector;import com.journaldev.java.dependencyinjection.consumer.Consumer;public interface MessageServiceInjector {public Consumer getConsumer();
}

Now for every service, we will have to create injector classes like below.

現在,對于每項服務,我們將必須創建如下所示的噴射器類。

package com.journaldev.java.dependencyinjection.injector;import com.journaldev.java.dependencyinjection.consumer.Consumer;
import com.journaldev.java.dependencyinjection.consumer.MyDIApplication;
import com.journaldev.java.dependencyinjection.service.EmailServiceImpl;public class EmailServiceInjector implements MessageServiceInjector {@Overridepublic Consumer getConsumer() {return new MyDIApplication(new EmailServiceImpl());}}
package com.journaldev.java.dependencyinjection.injector;import com.journaldev.java.dependencyinjection.consumer.Consumer;
import com.journaldev.java.dependencyinjection.consumer.MyDIApplication;
import com.journaldev.java.dependencyinjection.service.SMSServiceImpl;public class SMSServiceInjector implements MessageServiceInjector {@Overridepublic Consumer getConsumer() {return new MyDIApplication(new SMSServiceImpl());}}

Now let’s see how our client applications will use the application with a simple program.

現在,讓我們看看我們的客戶端應用程序將如何通過一個簡單的程序使用該應用程序。

package com.journaldev.java.dependencyinjection.test;import com.journaldev.java.dependencyinjection.consumer.Consumer;
import com.journaldev.java.dependencyinjection.injector.EmailServiceInjector;
import com.journaldev.java.dependencyinjection.injector.MessageServiceInjector;
import com.journaldev.java.dependencyinjection.injector.SMSServiceInjector;public class MyMessageDITest {public static void main(String[] args) {String msg = "Hi Pankaj";String email = "pankaj@abc.com";String phone = "4088888888";MessageServiceInjector injector = null;Consumer app = null;//Send emailinjector = new EmailServiceInjector();app = injector.getConsumer();app.processMessages(msg, email);//Send SMSinjector = new SMSServiceInjector();app = injector.getConsumer();app.processMessages(msg, phone);}}

As you can see that our application classes are responsible only for using the service. Service classes are created in injectors. Also if we have to further extend our application to allow facebook messaging, we will have to write Service classes and injector classes only.

如您所見,我們的應用程序類僅負責使用服務。 服務類別是在注射器中創建的。 同樣,如果我們必須進一步擴展我們的應用程序以允許Facebook消息傳遞,我們將只必須編寫Service類和注射器類。

So dependency injection implementation solved the problem with hard-coded dependency and helped us in making our application flexible and easy to extend. Now let’s see how easily we can test our application class by mocking the injector and service classes.

因此,依賴項注入實現解決了具有硬編碼依賴項的問題,并幫助我們使應用程序靈活且易于擴展。 現在,讓我們看看通過模擬注入器和服務類來測試應用程序類有多么容易。

Java依賴注入–帶有模擬注入器和服務的JUnit測試用例 (Java Dependency Injection – JUnit Test Case with Mock Injector and Service)

package com.journaldev.java.dependencyinjection.test;import org.junit.After;
import org.junit.Before;
import org.junit.Test;import com.journaldev.java.dependencyinjection.consumer.Consumer;
import com.journaldev.java.dependencyinjection.consumer.MyDIApplication;
import com.journaldev.java.dependencyinjection.injector.MessageServiceInjector;
import com.journaldev.java.dependencyinjection.service.MessageService;public class MyDIApplicationJUnitTest {private MessageServiceInjector injector;@Beforepublic void setUp(){//mock the injector with anonymous classinjector = new MessageServiceInjector() {@Overridepublic Consumer getConsumer() {//mock the message servicereturn new MyDIApplication(new MessageService() {@Overridepublic void sendMessage(String msg, String rec) {System.out.println("Mock Message Service implementation");}});}};}@Testpublic void test() {Consumer consumer = injector.getConsumer();consumer.processMessages("Hi Pankaj", "pankaj@abc.com");}@Afterpublic void tear(){injector = null;}}

As you can see that I am using anonymous classes to mock the injector and service classes and I can easily test my application methods. I am using JUnit 4 for the above test class, so make sure it’s in your project build path if you are running above test class.

如您所見,我正在使用匿名類 模擬注入器和服務類,并且可以輕松測試我的應用程序方法。 我在上述測試類中使用的是JUnit 4,因此,如果您在測試類之上運行,請確保它在您的項目構建路徑中。

We have used constructors to inject the dependencies in the application classes, another way is to use a setter method to inject dependencies in application classes. For setter method dependency injection, our application class will be implemented like below.

我們使用構造函數將依賴項注入應用程序類中,另一種方法是使用setter方法將依賴項注入應用程序類中。 對于setter方法依賴項注入,我們的應用程序類將如下實現。

package com.journaldev.java.dependencyinjection.consumer;import com.journaldev.java.dependencyinjection.service.MessageService;public class MyDIApplication implements Consumer{private MessageService service;public MyDIApplication(){}//setter dependency injection	public void setService(MessageService service) {this.service = service;}@Overridepublic void processMessages(String msg, String rec){//do some msg validation, manipulation logic etcthis.service.sendMessage(msg, rec);}}
package com.journaldev.java.dependencyinjection.injector;import com.journaldev.java.dependencyinjection.consumer.Consumer;
import com.journaldev.java.dependencyinjection.consumer.MyDIApplication;
import com.journaldev.java.dependencyinjection.service.EmailServiceImpl;public class EmailServiceInjector implements MessageServiceInjector {@Overridepublic Consumer getConsumer() {MyDIApplication app = new MyDIApplication();app.setService(new EmailServiceImpl());return app;}}

One of the best example of setter dependency injection is Struts2 Servlet API Aware interfaces.

設置程序依賴項注入的最佳示例之一是Struts2 Servlet API Aware接口 。

Whether to use Constructor based dependency injection or setter based is a design decision and depends on your requirements. For example, if my application can’t work at all without the service class then I would prefer constructor based DI or else I would go for setter method based DI to use it only when it’s really needed.

使用基于構造函數的依賴項注入還是基于setter是設計決策,取決于您的要求。 例如,如果我的應用程序如果沒有服務類就無法工作,那么我會更喜歡基于構造函數的DI,否則我會選擇基于setter方法的DI來僅在確實需要它時才使用它。

Dependency Injection in Java is a way to achieve Inversion of control (IoC) in our application by moving objects binding from compile time to runtime. We can achieve IoC through Factory Pattern, Template Method Design Pattern, Strategy Pattern and Service Locator pattern too.

Java中的依賴注入是一種通過將對象綁定從編譯時移到運行時來在我們的應用程序中實現控制反轉IoC )的方法。 我們也可以通過工廠模式 , 模板方法設計模式 , 策略模式和服務定位器模式來實現IoC。

Spring Dependency Injection, Google Guice and Java EE CDI frameworks facilitate the process of dependency injection through use of Java Reflection API and java annotations. All we need is to annotate the field, constructor or setter method and configure them in configuration xml files or classes.

Spring Dependency InjectionGoogle GuiceJava EE CDI框架通過使用Java Reflection API和Java注釋簡化了依賴項注入的過程。 我們所需要做的就是注釋字段,構造函數或設置方法,并在配置xml文件或類中對其進行配置。

Java依賴注入的好處 (Benefits of Java Dependency Injection)

Some of the benefits of using Dependency Injection in Java are:

在Java中使用依賴注入的一些好處是:

  • Separation of Concerns

    關注點分離
  • Boilerplate Code reduction in application classes because all work to initialize dependencies is handled by the injector component

    減少應用程序類中的代碼,因為初始化依賴項的所有工作都由注入器組件處理
  • Configurable components makes application easily extendable

    可配置的組件使應用程序易于擴展
  • Unit testing is easy with mock objects

    使用模擬對象可以輕松進行單元測試

Java依賴注入的缺點 (Disadvantages of Java Dependency Injection)

Java Dependency injection has some disadvantages too:

Java依賴注入也有一些缺點:

  • If overused, it can lead to maintenance issues because the effect of changes are known at runtime.

    如果使用過度,則會導致維護問題,因為在運行時知道更改的效果。
  • Dependency injection in java hides the service class dependencies that can lead to runtime errors that would have been caught at compile time.

    Java中的依賴項注入隱藏了服務類依賴關系,這可能導致運行時錯誤,而這些錯誤在編譯時就會被捕獲。
Download Dependency Injection Project下載依賴注入項目

That’s all for dependency injection pattern in java. It’s good to know and use it when we are in control of the services.

這就是java中依賴注入模式的全部內容。 當我們控制服務時,很高興知道并使用它。

翻譯自: https://www.journaldev.com/2394/java-dependency-injection-design-pattern-example-tutorial

依賴注入(di)模式

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/5/183158.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息