MySQL Community & Workbench 설치
Greeter.java : 콘솔에 메시지를 출력하는 자바 클래스
AppContext.java : 스프링 설정 파일
TestApplication.java(main) : 스프링과 Greeter를 실행하는 자바 클래스
Greeter.java
package com.test.test1;
public class Greeter {
private String format;
public String greet(String name) {
return String.format(format, name);
}
public void setFormat(String format) {
this.format = format;
}
}
AppContext.java
package com.test.test1;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppContext {
@Bean
public Greeter greeter() {
Greeter g = new Greeter();
g.setFormat("%s, 안녕하세요.");
return g;
}
}
@Configuration
해당 클래스는 spring 설정 클래스로 동작한다.
@Bean
해당 메서드가 반환하는 값은 Bean 객체로 등록된다.
TestApplication.java
package com.test.test1;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
//@SpringBootApplication
public class Test1Application {
public static void main(String[] args) {
// SpringApplication.run(Test1Application.class, args);
{
Greeter greeter = new Greeter();
greeter.setFormat("Hello, %s!!!");
String message = greeter.greet("Spring");
System.out.println(message);
}
{
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppContext.class);
Greeter greeter = ctx.getBean("greeter", Greeter.class);
greeter.setFormat("안녕, %s!!!");
String message = greeter.greet("스프링");
System.out.println(message);
ctx.close();
}
}
}
의존성 주입(DI. Dependency Injection)
위 예제에서 다음을 비교해보자.
Greeter greeter = new Greeter()
VS
Greeter greeter = ctx.getBean("greeter", Greeter.class);
제어의 역전(IoC)
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppContext.class);
빈(bean)
빈(bean) 객체는 싱글톤(singleton) 범위를 가진다.
=> 스프링은 기본적으로 한 개의 @Bean 어노테이션에 대해 한 개의 빈 객체를 생성
class Singleton {
private static Single instance;
private Singleton() { // 외부에서 생성자를 호출할 수 없도록 private 지정
}
// 인스턴스를 만들지 않고 호출할 수 있도록 static 지정
public static Singleton getInstance() {
if (instance == null)
instance = new Singleton(); // null이면 생성하고
return instance; // 반환
}
}
// 외부에서 호출
Singleton.getInstance();
싱글톤 예제
package com.test.test1;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
//@SpringBootApplication
public class Test1Application {
public static void main(String[] args) {
// SpringApplication.run(Test1Application.class, args);
Greeter g1 = new Greeter(); // new 하면 힙 메모리에 새로운 변수가 만들어지므로
Greeter g2 = new Greeter();
System.out.println("g1 : " + g1);
System.out.println("g2 : " + g2);
System.out.println("g1 == g2 : " + (g1 == g2)); // false
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppContext.class);
// 주소가 동일하다. => 싱글톤이다 !!
Greeter g3 = ctx.getBean("greeter", Greeter.class);
Greeter g4 = ctx.getBean("greeter", Greeter.class);
System.out.println("g3 : " + g3);
System.out.println("g4 : " + g4);
System.out.println("g3 == g4 : " + (g3 == g4)); // true
ctx.close();
}
}
의존(dependency)
한 클래스가 다른 클래스의 메서드를 사용(실행)할 때 의존한다라고 표현 => 변경에 의해 영향을 받는 관계
public class MemberDAO() {
// 이메일 정보가 일치하는 사용자 정보를 조회해서 반환
public Member selectByEmail(String email) {
return null;
}
// 회원 정보를 저장
public void insert(Member member) {
// TODO
}
}
// 서비스에서 각 메서드 사용
public class MemberRegisterService {
private MemberDAO dao = new MemberDAO();
public void regist(Member member) throws Exception {
Member m = dao.selectByEmail(member.getEmail());
if (m != null) {
throw new Exception("이메일이 중복되었습니다.");
}
dao.insert(member);
}
}
MemberRegisterService는 MemberDAO의 selectByEmail 메서드와 insert 메서드를 사용하고 있다.
=> MemberDAO에 의존한다.
=> MemberDAO의 selectByEmail 메서드 또는 insert 메서드를 변경하면 MemberRegisterService도 변경이 필요하다.
의존 관계가 많으면 많을 수록 하나의 변경에 따른 추가 변경이 많아져 복잡해진다.
의존 객체를 구하는 방법
public class MemberRegisterService {
private MemberDAO dao = new MemberDAO();
}
=> 구현은 용이하나, 유지보수에 문제가 있다. 🥵
의존하는 객체를 직접 생성하는 대신, 의존 객체를 전달받는 방식
public class MemberRegisterService {
private MemberDAO dao;
// 바깥쪽에서 전달받아서 쓸 수 있다.
public MemberRegisterService(MemberDAO dao) {
this.dao = dao;
}
}
=> 의존 객체를 주입해 주는 곳만 수정하면 변경을 반영할 수 있다.
class Main {
public static void main(String[] args) {
MemberDAO dao1 = new MemberDAO();
MemberRegisterService mrs1 = new MemberRegisterService(dao1);
MemberDAO dao2 = new NewMemberDAO();
MemberRegisterService mrs2 = new MemberRegisterService(dao2);
}
}
class NewMemberDAO extends MemberDAO {
..
}
이렇게 의존성을 떨어트리니까(외부에서 생성해서 넣어주니까) 나는 수정하지 않아도 된다.
=> DI(의존성 주입)가 필요한 이유
회원 데이터를 관리하는 클래스
- Member(dto 객체)
- WrongIdPasswordException
- MemberDAO(회원관리 DB 연동 역할만!)
회원 가입을 처리하는 클래스
- DuplicateMemberException(동일한 email 이 존재하는가)
- RegisterRequest(사용자가 전달해주는 입력값. request 객체)
- MemberRegisterService(등록 담당)
패스워드 변경을 처리하는 클래스
- MemberNotFoundException(멤버인지?)
- ChangePasswordService(패스워드 변경)
package com.test.test1;
import java.time.LocalDateTime;
public class Member {
private Long id;
private String email;
private String password;
private String name;
private LocalDateTime registerDateTime;
public Member(String email, String password, String name, LocalDateTime registerDateTime) {
this.email = email;
this.password = password;
this.name = name;
this.registerDateTime = registerDateTime;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getEmail() {
return email;
}
public String getPassword() {
return password;
}
public String getName() {
return name;
}
public LocalDateTime getRegisterDateTime() {
return registerDateTime;
}
public void changePassword(String oldPassword, String newPassword) {
if (!this.password.equals(oldPassword)) {
throw new WrongIdPasswordException();
}
this.password = newPassword;
}
}
WrongIdPasswordException ⬇️
package com.test.test1;
public class WrongIdPasswordException extends RuntimeException{
}
데이터를 읽고, 쓰고, 수정하고, 삭제하는 기능 포함
package com.test.test1;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class MemberDAO {
private static long nextId = 0;
// 키: 이메일, 값: Member
private Map<String, Member> map = new HashMap<>();
// 조회
public Member selectByEmail(String email) {
return map.get(email);
}
// 등록
public void insert(Member member) {
member.setId(++nextId);
map.put(member.getEmail(), member);
}
// 수정
public void update(Member member) {
map.put(member.getEmail(), member);
}
// 전체 조회
public Collection<Member> selectAll() {
return map.values();
}
}
package com.test.test1;
public class RegisterRequest {
private String email;
private String password;
private String confirmPassword;
private String name;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getConfirmPassword() {
return confirmPassword;
}
public void setConfirmPassword(String confirmPassword) {
this.confirmPassword = confirmPassword;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isPasswordEqualToConfirmPassword() {
return this.password.equals(this.confirmPassword);
}
}
isPasswordEqualToConfirmPassword() : 비밀번호 입력값과 비밀번호 확인 입력값이 같은지 !!
package com.test.test1;
import java.time.LocalDateTime;
public class MemberRegisterService {
private MemberDAO memberDAO; // 의존 객체
// 생성자를 이용해서 의존성 주입
public MemberRegisterService(MemberDAO memberDAO) {
this.memberDAO = memberDAO;
}
public long regist(RegisterRequest req) {
Member member = memberDAO.selectByEmail(req.getEmail());
if (member != null) {
throw new DuplicateMemberException("이메일 중복 " + req.getEmail());
}
Member newMember = new Member(req.getEmail(), req.getPassword(), req.getName(), LocalDateTime.now());
memberDAO.insert(newMember);
return newMember.getId();
}
}
package com.test.test1;
public class DuplicateMemberException extends RuntimeException {
public DuplicateMemberException(String message) {
super(message); // 상위 클래스에 메시지만 전달
}
}
MemberDAO로 의존성 주입 받기
package com.test.test1;
public class ChangePasswordService {
private MemberDAO memberDAO;
public ChangePasswordService(MemberDAO memberDAO) {
this.memberDAO = memberDAO;
}
public void changePassword(String email, String currentPw, String newPw) {
Member member = memberDAO.selectByEmail(email);
if (member == null) {
throw new RuntimeException("등록된 회원이 없습니다.");
}
member.changePassword(currentPw, newPw);
memberDAO.update(member);
}
}
package com.test.test1.assembler;
import com.test.test1.ChangePasswordService;
import com.test.test1.MemberDAO;
import com.test.test1.MemberRegisterService;
public class Assembler {
private MemberDAO memberDAO;
private MemberRegisterService regSvc;
private ChangePasswordService pwdSvc;
// 필요한 객체들의 인스턴스를 만들고 넣어준다.
public Assembler() {
this.memberDAO = new MemberDAO();
this.regSvc = new MemberRegisterService(this.memberDAO);
this.pwdSvc = new ChangePasswordService(this.memberDAO);
}
public MemberDAO getMemberDAO() {
return this.memberDAO;
}
public MemberRegisterService getRegSvc() {
return this.regSvc;
}
public ChangePasswordService getPwdSvc() {
return this.pwdSvc;
}
}
직접 new 해서 만드는 방법 ⬇️
package com.test.test1.main;
import com.test.test1.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class MainForAssembler {
// new : 새로운 회원 데이터를 추가
// change : 회원의 패스워드를 변경
// exit : 프로그램을 종료
// new : 새로운 회원 데이터를 추가
// change : 회원의 패스워드를 변경
// exit : 프로그램을 종료
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (true) {
System.out.println("명령어를 입력하세요. ");
String command = reader.readLine();
if (command.startsWith("exit")) {
System.out.println("종료합니다.");
break;
}
if (command.startsWith("new")) {
processNewCommand(command.split(" "));
continue;
}
if (command.startsWith("change")) {
processChangeCommand(command.split(" "));
continue;
}
printHelp();
}
}
private static MemberDAO memberDAO = new MemberDAO();
private static MemberRegisterService regSvc = new MemberRegisterService(memberDAO);
private static ChangePasswordService pwdSvc = new ChangePasswordService(memberDAO);
private static void printHelp() {
System.out.println();
System.out.println("잘못된 명령입니다. 아래 명령어 사용법을 확인하세요.");
System.out.println("new email name password confirmPassword");
System.out.println("change email currentPassword newPassword");
System.out.println();
}
private static void processNewCommand(String[] args) {
if (args.length != 5) {
printHelp();
return;
}
// MemberRegisterService regSvc = new MemberRegisterService(new MemberDAO());
RegisterRequest reg = new RegisterRequest();
reg.setEmail(args[1]);
reg.setName(args[2]);
reg.setPassword(args[3]);
reg.setConfirmPassword(args[4]);
if (!reg.isPasswordEqualToConfirmPassword()) {
System.out.println("패스워드와 패스워드 확인이 일치하지 않습니다.");
return;
}
try {
regSvc.regist(reg);
System.out.println("등록되었습니다.");
} catch(DuplicateMemberException e) {
System.out.println("이미 존재하는 이메일입니다.");
}
}
private static void processChangeCommand(String[] args) {
if (args.length != 4) {
printHelp();
return;
}
// ChangePasswordService pwdSvc = new ChangePasswordService(new MemberDAO());
try {
pwdSvc.changePassword(args[1], args[2], args[3]);
System.out.println("패스워드를 변경하였습니다.");
} catch(RuntimeException e) {
System.out.println(e.getMessage());
}
}
}
assembler의 get 메서드를 사용해서 필요하는 곳에서 인스턴스를 받아와 사용 ⬇️
assembler로 생성
package com.test.test1.main;
import com.test.test1.*;
import com.test.test1.assembler.Assembler;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class MainForAssembler {
// new : 새로운 회원 데이터를 추가
// change : 회원의 패스워드를 변경
// exit : 프로그램을 종료
// new : 새로운 회원 데이터를 추가
// change : 회원의 패스워드를 변경
// exit : 프로그램을 종료
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (true) {
System.out.println("명령어를 입력하세요. ");
String command = reader.readLine();
if (command.startsWith("exit")) {
System.out.println("종료합니다.");
break;
}
if (command.startsWith("new")) {
processNewCommand(command.split(" "));
continue;
}
if (command.startsWith("change")) {
processChangeCommand(command.split(" "));
continue;
}
printHelp();
}
}
/*
private static MemberDAO memberDAO = new MemberDAO();
private static MemberRegisterService regSvc = new MemberRegisterService(memberDAO);
private static ChangePasswordService pwdSvc = new ChangePasswordService(memberDAO);
*/
private static Assembler assembler = new Assembler();
private static void printHelp() {
System.out.println();
System.out.println("잘못된 명령입니다. 아래 명령어 사용법을 확인하세요.");
System.out.println("new email name password confirmPassword");
System.out.println("change email currentPassword newPassword");
System.out.println();
}
private static void processNewCommand(String[] args) {
if (args.length != 5) {
printHelp();
return;
}
MemberRegisterService regSvc = assembler.getRegSvc();
RegisterRequest reg = new RegisterRequest();
reg.setEmail(args[1]);
reg.setName(args[2]);
reg.setPassword(args[3]);
reg.setConfirmPassword(args[4]);
if (!reg.isPasswordEqualToConfirmPassword()) {
System.out.println("패스워드와 패스워드 확인이 일치하지 않습니다.");
return;
}
try {
regSvc.regist(reg);
System.out.println("등록되었습니다.");
} catch(DuplicateMemberException e) {
System.out.println("이미 존재하는 이메일입니다.");
}
}
private static void processChangeCommand(String[] args) {
if (args.length != 4) {
printHelp();
return;
}
ChangePasswordService pwdSvc = assembler.getPwdSvc();
try {
pwdSvc.changePassword(args[1], args[2], args[3]);
System.out.println("패스워드를 변경하였습니다.");
} catch(RuntimeException e) {
System.out.println(e.getMessage());
}
}
}
스프링을 이용한 객체 조립과 사용 (스프링을 사용해보자 !! 🌱)
@configuration
@Bean
package com.test.test1.config;
import com.test.test1.ChangePasswordService;
import com.test.test1.MemberDAO;
import com.test.test1.MemberRegisterService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppCtx {
@Bean
public MemberDAO memberDAO() {
return new MemberDAO();
}
@Bean
public MemberRegisterService memberRegSvc() {
return new MemberRegisterService(memberDAO());
}
@Bean
public ChangePasswordService changePwdSvc() {
return new ChangePasswordService(memberDAO());
}
}
package com.test.test1.main;
import com.test.test1.*;
import com.test.test1.config.AppCtx;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class MainForSpring {
private static ApplicationContext ctx = null;
public static void main(String[] args) throws IOException {
// 빈 설정 정보를 읽어와서 ApplicationContext에 저장하자
ctx = new AnnotationConfigApplicationContext(AppCtx.class);
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (true) {
System.out.println("명령어를 입력하세요. ");
String command = reader.readLine();
if (command.startsWith("exit")) {
System.out.println("종료합니다.");
break;
}
if (command.startsWith("new")) {
processNewCommand(command.split(" "));
continue;
}
if (command.startsWith("change")) {
processChangeCommand(command.split(" "));
continue;
}
printHelp();
}
}
private static void printHelp() {
System.out.println();
System.out.println("잘못된 명령입니다. 아래 명령어 사용법을 확인하세요.");
System.out.println("new email name password confirmPassword");
System.out.println("change email currentPassword newPassword");
System.out.println();
}
private static void processNewCommand(String[] args) {
if (args.length != 5) {
printHelp();
return;
}
// MemberRegisterService regSvc = assembler.getRegSvc();
// 필요한 시점에 getBean으로 타입캐스팅을 해서 범용적으로 사용할 수 있다.
MemberRegisterService regSvc = ctx.getBean("memberRegSvc", MemberRegisterService.class);
RegisterRequest reg = new RegisterRequest();
reg.setEmail(args[1]);
reg.setName(args[2]);
reg.setPassword(args[3]);
reg.setConfirmPassword(args[4]);
if (!reg.isPasswordEqualToConfirmPassword()) {
System.out.println("패스워드와 패스워드 확인이 일치하지 않습니다.");
return;
}
try {
regSvc.regist(reg);
System.out.println("등록되었습니다.");
} catch(DuplicateMemberException e) {
System.out.println("이미 존재하는 이메일입니다.");
}
}
private static void processChangeCommand(String[] args) {
if (args.length != 4) {
printHelp();
return;
}
// ChangePasswordService pwdSvc = assembler.getPwdSvc();
// 필요한 시점에 getBean으로 타입캐스팅을 해서 범용적으로 사용할 수 있다.
ChangePasswordService pwdSvc = ctx.getBean("changePwdSvc", ChangePasswordService.class);
try {
pwdSvc.changePassword(args[1], args[2], args[3]);
System.out.println("패스워드를 변경하였습니다.");
} catch(RuntimeException e) {
System.out.println(e.getMessage());
}
}
}
package com.test.test1;
public class MemberPrinter {
public void print(Member member) {
System.out.printf("회원정보: ID=%s, 이메일=%s, 이름=%s, 등록일=%tF\n",
member.getId(), member.getEmail(), member.getName(), member.getRegisterDateTime());
}
}
package com.test.test1;
import java.util.Collection;
public class MemberListPrinter {
private MemberDAO memberDAO;
private MemberPrinter printer;
public MemberListPrinter(MemberDAO memberDAO, MemberPrinter printer) {
this.memberDAO = memberDAO;
this.printer = printer;
}
public void printAll() {
Collection<Member> members = memberDAO.selectAll();
members.forEach(member -> printer.print(member));
}
}
// 생성자로 주입
@Bean
public MemberPrinter memberPrinter() {
return new MemberPrinter();
}
@Bean
public MemberListPrinter memberListPrinter() {
return new MemberListPrinter(memberDAO(), memberPrinter()); // 생성자로 주입
}
if (command.startsWith("list")) {
processListCommand(command.split(" "));
continue;
}
private static void processListCommand(String[] args) {
MemberListPrinter memberListPrinter = ctx.getBean("memberListPrinter", MemberListPrinter.class);
memberListPrinter.printAll();
}
이메일 정보와 일치하는 회원의 정보를 출력하는 기능
package com.test.test1;
public class MemberInfoPrinter {
private MemberDAO memberDAO;
private MemberPrinter printer;
public void setMemberDAO(MemberDAO memberDAO) {
this.memberDAO = memberDAO;
}
public void setMemberPrinter(MemberPrinter printer) {
this.printer = printer;
}
public void printMemberInfo(String email) {
Member member = memberDAO.selectByEmail(email);
if (member == null) {
System.out.println("일치하는 데이터가 없습니다.");
return;
}
printer.print(member);
System.out.println();
}
}
빈을 등록해줘야한다 !
@Bean
public MemberInfoPrinter memberInfoPrinter() {
MemberInfoPrinter infoPrinter = new MemberInfoPrinter();
infoPrinter.setMemberDAO(memberDAO()); // setter 메서드로 주입
infoPrinter.setMemberPrinter(memberPrinter());
return infoPrinter;
}
if (command.startsWith("info")) {
processInfoCommand(command.split(" "));
continue;
}
private static void processInfoCommand(String[] args) {
if (args.length != 2) {
printHelp();
return;
}
MemberInfoPrinter memberInfoPrinter = ctx.getBean("memberInfoPrinter", MemberInfoPrinter.class);
memberInfoPrinter.printMemberInfo(args[1]);
}
package com.test.test1;
public class VersionPrinter {
private int majorVersion;
private int minorVersion;
public void print() {
System.out.printf("이 프로그램의 버전은 %d.%d 입니다.\n", this.majorVersion, this.minorVersion);
}
public void setMajorVersion(int majorVersion) {
this.majorVersion = majorVersion;
}
public void setMinorVersion(int minorVersion) {
this.minorVersion = minorVersion;
}
}
@Bean
public VersionPrinter versionPrinter() {
VersionPrinter versionPrinter = new VersionPrinter();
versionPrinter.setMajorVersion(5);
versionPrinter.setMinorVersion(3);
return versionPrinter;
}
private static void processVersionCommand(String[] args) {
VersionPrinter versionPrinter = ctx.getBean("versionPrinter", VersionPrinter.class);
versionPrinter.print();
}
getBean으로 제공하는 기능을 쓸 수 있다 !
스프링은 런타임에 설정 클래스를 상속한 새로운 설정 클래스를 만들어서 사용한다. => 싱글톤 범위를 제공
@Configuration
public class AppCtx {
@Bean
public MemberDAO memberDAO() {
return new MemberDAO();
}
... (생략) ...
}
public class AppCtxExt extends AppCtx {
private Map<String, Object> beans = ...;
@Override
public MemberDAO memberDAO() {
if (!beans.containsKey("memberDAO")) {
beans.put("memberDAO", super.memberDAO());
}
return (MemberDAO) beans.get("memberDAO");
}
}
최초 호출 됐을 때는 넣어주고(put), 그다음부턴 return 해준다.
=> 싱글톤으로 관리하기
package com.test.test1.config;
import com.test.test1.MemberDAO;
import com.test.test1.MemberPrinter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
// 의존 관계가 없는것들
@Configuration
public class AppConf1 {
@Bean
public MemberDAO memberDAO() {
return new MemberDAO();
}
@Bean
public MemberPrinter memberPrinter() {
return new MemberPrinter();
}
}
package com.test.test1.config;
import com.test.test1.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
// 의존 관계가 있는 것들
@Configuration
public class AppConf2 {
// 필드 정의
// @Autowired: 스프링 빈에 의존하는 다른 빈에 자동으로 주입!!
@Autowired
private MemberDAO memberDAO;
private MemberPrinter memberPrinter;
@Bean
public MemberRegisterService memberRegSvc() {
return new MemberRegisterService(memberDAO);
}
@Bean
public ChangePasswordService changePwdSvc() {
return new ChangePasswordService(memberDAO);
}
@Bean
public MemberListPrinter memberListPrinter() {
return new MemberListPrinter(memberDAO, memberPrinter); // 생성자로 주입
}
@Bean
public MemberInfoPrinter memberInfoPrinter() {
MemberInfoPrinter infoPrinter = new MemberInfoPrinter();
infoPrinter.setMemberDAO(memberDAO); // setter 메서드로 주입
infoPrinter.setMemberPrinter(memberPrinter);
return infoPrinter;
}
@Bean
public VersionPrinter versionPrinter() {
VersionPrinter versionPrinter = new VersionPrinter();
versionPrinter.setMajorVersion(5);
versionPrinter.setMinorVersion(3);
return versionPrinter;
}
}
// ctx = new AnnotationConfigApplicationContext(AppCtx.class);
⬇️
ctx = new AnnotationConfigApplicationContext(AppConf1.class, AppConf2.class);
@Autowired 🩷🩷🩷🩷🩷🩷🩷🩷🩷🩷
설정 파일을 분리하니까 의존 객체들이 생겼다..!!!
필드를 만들어서 memberDAO, memberPrinter를 사용할 수 있도록 @Autowired 사용하자!
그럼 자동으로 인스턴스를 넣어준다.
단, memberDAO와 memberPrinter가 bean으로 등록되어 있어야만 한다.
- 의존 주입 대상에 Autowired를 쓰면 의존 주입을 위한 코드(생성자 이용, setter 메서드 이용)를 사용하지 않아도 된다!!
public class MemberInfoPrinter {
@Autowired
private MemberDAO memberDAO;
@Autowired
private MemberPrinter printer;
.. (생략) ..
@Bean
public MemberInfoPrinter memberInfoPrinter() {
MemberInfoPrinter infoPrinter = new MemberInfoPrinter();
//infoPrinter.setMemberDAO(memberDAO); // setter 메서드로 주입
//infoPrinter.setMemberPrinter(memberPrinter);
return infoPrinter;
}