DI(Dependency Injection)?
17651 ワード
良好なオブジェクト向け設計五原則(SOLID)
AppConfigがインプリメンテーションオブジェクトの作成と接続を担当する役割を考慮すると、制御反転とともに動作原理を考慮することができる.
DI?
Dependency Injectionの略で、依存注入と呼ばれています.import java.time.LocalDateTime;
public class MemberRegisterService {
// MemberRegisterService 클래스가 MemberDao와 의존관계에 있다.
private MemberDao memberDao = new MemberDao();
public void regist(RegisterRequest req) {
// 이메일로 회원 데이터(Member) 조회
Member member = memberDao.selectByEmail(req.getEmail());
/**
코드 생략
**/
}
}
上記のコードから,MemberRegisterServiceクラスはMemberDaoクラスに依存していることが分かる.これは、MemberDaoが変更されると、連鎖反応を受ける可能性があることを意味します.このような関係にあると,前述したSOLIDの原則が破られる.(特にOCP、DIP原則)
クラス内で依存オブジェクトを直接作成するのは簡単ですが、長期的には機能拡張やメンテナンスの観点から問題を引き起こすコードです.
これとは異なり,DIは依存オブジェクトを直接生成するのではなく,依存オブジェクトを受信する方式を用いる.import java.time.LocalDateTime;
public class MemberRegisterService {
private MemberDao memberDao;
// 생성자 주입
public MemberRegisterService(MemberDao memberDao) {
this.memberDao = memberDao;
}
public void regist(RegisterRequest req) {
// 이메일로 회원 데이터(Member) 조회
Member member = memberDao.selectByEmail(req.getEmail());
/**
코드 생략
**/
}
}
上のコードから見ると,以前とは異なり,依存オブジェクトを直接生成するのではなく,ジェネレータを介して依存オブジェクトを伝達する.このようにDIを用いることで,変更の柔軟性を保つことができる.MemberDaoクラスはメンバーデータをDBに格納し、クエリーを高速化するためにキャッシュを適用する必要がある場合は、クラスを継承して新しいクラスを作成する必要があります.このプロセスでは、クラスがMemberDaoに関連付けられている場合は、コードを同じ変更する必要がありますが、DIを適用すると、変更するコードが減少します.すなわち,注入オブジェクトのコードを1つ変更するだけでよい.
ここでは、オブジェクトを作成し、依存オブジェクトに注入する部分をそれぞれAppConfig
として作成します.import test1.ChangePasswordService;
import test1.MemberDao;
import test1.MemberRegisterService;
public class AppConfig {
private MemberDao memberDao;
private MemberRegisterService regSvc;
private ChangePasswordService pwdSvc;
public AppConfig() {
memberDao = new MemberDao();
regSvc = new MemberRegisterService(memberDao);
pwdSvc = new ChangePasswordService();
pwdSvc.setMemberDao(memberDao);
}
public MemberDao getMemberDao() {
return memberDao;
}
public MemberRegisterService getMemberRegisterService() {
return regSvc;
}
public ChangePasswordService getChangePasswordService() {
return pwdSvc;
}
}
このように単独で管理すれば、クラスの変更に柔軟に対応できます.Spring Frameworkの構造は、特定のタイプのクラスだけでなく、これらのAppConfigを汎用化することです.
SpringでのDI
次のコードを見ると、AppConfig
とあまり変わらないと思います.package config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import test1.ChangePasswordService;
import test1.MemberDao;
import test1.MemberRegisterService;
@Configuration
public class AppCtx {
@Bean
public MemberDao memberDao() {
return new MemberDao();
}
@Bean
public MemberRegisterService memberRegSvc() {
return new MemberRegisterService(memberDao());
}
@Bean
public ChangePasswordService changePwdSvc() {
ChangePasswordService pwdSvc = new ChangePasswordService();
pwdSvc.setMemberDao(memberDao());
return pwdSvc;
}
}
前述したように、スプリングが作成するオブジェクトと、依存関係をどのように注入するかを記述すればよい.
import java.time.LocalDateTime;
public class MemberRegisterService {
// MemberRegisterService 클래스가 MemberDao와 의존관계에 있다.
private MemberDao memberDao = new MemberDao();
public void regist(RegisterRequest req) {
// 이메일로 회원 데이터(Member) 조회
Member member = memberDao.selectByEmail(req.getEmail());
/**
코드 생략
**/
}
}
import java.time.LocalDateTime;
public class MemberRegisterService {
private MemberDao memberDao;
// 생성자 주입
public MemberRegisterService(MemberDao memberDao) {
this.memberDao = memberDao;
}
public void regist(RegisterRequest req) {
// 이메일로 회원 데이터(Member) 조회
Member member = memberDao.selectByEmail(req.getEmail());
/**
코드 생략
**/
}
}
import test1.ChangePasswordService;
import test1.MemberDao;
import test1.MemberRegisterService;
public class AppConfig {
private MemberDao memberDao;
private MemberRegisterService regSvc;
private ChangePasswordService pwdSvc;
public AppConfig() {
memberDao = new MemberDao();
regSvc = new MemberRegisterService(memberDao);
pwdSvc = new ChangePasswordService();
pwdSvc.setMemberDao(memberDao);
}
public MemberDao getMemberDao() {
return memberDao;
}
public MemberRegisterService getMemberRegisterService() {
return regSvc;
}
public ChangePasswordService getChangePasswordService() {
return pwdSvc;
}
}
次のコードを見ると、
AppConfig
とあまり変わらないと思います.package config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import test1.ChangePasswordService;
import test1.MemberDao;
import test1.MemberRegisterService;
@Configuration
public class AppCtx {
@Bean
public MemberDao memberDao() {
return new MemberDao();
}
@Bean
public MemberRegisterService memberRegSvc() {
return new MemberRegisterService(memberDao());
}
@Bean
public ChangePasswordService changePwdSvc() {
ChangePasswordService pwdSvc = new ChangePasswordService();
pwdSvc.setMemberDao(memberDao());
return pwdSvc;
}
}
前述したように、スプリングが作成するオブジェクトと、依存関係をどのように注入するかを記述すればよい.@Configuration
:スプリング設定クラス@Bean
:このメソッドで作成したオブジェクトをスプリング空席に設定します.AnnotationConfigApplicationContext
:オブジェクトを作成し、依存オブジェクトを注入するスプリングコンテナ@Autowired
:スプリングシートに依存する他の空孔を自動的に注入するための📌 SpringでのDI方式は?
@Bean設定とモノトーン? @Configuration
public class AppCtx {
@Bean
public MemberDao memberDao() {
return new MemberDao();
}
@Bean
public MemberRegisterService memberRegSvc() {
return new MemberRegisterService(memberDao());
}
@Bean
public ChangePasswordService changePwdSvc() {
ChangePasswordService pwdSvc = new ChangePasswordService();
pwdSvc.setMemberDao(memberDao());
return pwdSvc;
}
}
memberRegSvc()
およびchangePwdSvc()
が実行されるたびにmemberDao()
が実行され、結果として新しいMemberDaoオブジェクトが生成され、返される.
🤔 ではメンバーごとに対象が違うのでしょうか???
いいえ、ちがいます
スプリングコンテナによって生成される空は、モノトーンオブジェクトです.スプリングコンテナは、@Bean
追加のメソッドに対してのみオブジェクトを作成します.これは、上記のコードでmemberDao()
が複数回呼び出されたときに、常に同じオブジェクトが返されることを意味します.
これは、スプリングが実行時に作成した設定クラス内のmemberDao()
メソッドが、一度に作成したオブジェクトを保持し、同じオブジェクトを返すためです.
References
@Configuration
public class AppCtx {
@Bean
public MemberDao memberDao() {
return new MemberDao();
}
@Bean
public MemberRegisterService memberRegSvc() {
return new MemberRegisterService(memberDao());
}
@Bean
public ChangePasswordService changePwdSvc() {
ChangePasswordService pwdSvc = new ChangePasswordService();
pwdSvc.setMemberDao(memberDao());
return pwdSvc;
}
}
Reference
この問題について(DI(Dependency Injection)?), 我々は、より多くの情報をここで見つけました https://velog.io/@songs4805/Spring-DIDependency-Injectionテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol