Spring의 모듈은 위와 같고 우리는 필요한 기능만 사용하면 된다.
Spring의 모든 모듈을 사용하기 위해서는 Bean 을 알아야한다.
spring은 JAVA기반으로 되어있고 필요한 기능이라 하면 자바의 클래스(+기타 파일)로 만들어져있다.
이 클래스를 사용하면 되는데 library처럼 직접 'new'를 이용해 객체를 만들지 않는다.
spring의 IoC 컨테이너가 관리하는 자바객체를 통해서 해당 클래스의 기능을 사용합니다.
이 자바객체(빈)을 등록해서 사용해야되는데 빈을 잘 등록하고 원활하게
사용하기 위해서는 DI를 알아야만 합니다.
DI란
DI란 Dependency Injection의 약자로서 우리말로는 의존주입이라고 합니다.
DI전에는 또 Dependency, 의존에 대해서 알아야 합니다.
여기서부터 만드는 자바클래스는 모두 com.di.step1의 패키지에 있습니다.
IFreeBoardDao .java
package com.di.step1;
public interface IFreeBoardDao {
public void getBoardListDao();
}
FreeBoardDaoOracle.java
package com.di.step1;
public class FreeBoardDaoOracle implements IFreeBoardDao{
@Override
public void getBoardListDao() {
System.out.println("Oracle Dao 실행되었습니다.");
}
}
IFreeBoardService.java
package com.di.step1;
public interface IFreeBoardService {
public void getBoardListService();
}
FreeBoardServiceImpl1.java
FreeBoardServiceImpl2.java
FreeBoardServiceImpl3.java
package com.di.step1;
public class FreeBoardServiceImpl1 implements IFreeBoardService{
IFreeBoardDao freeBoardDao=new FreeBoardDaoOracle();
@Override
public void getBoardListService() {
freeBoardDao.getBoardListDao();
}
}
package com.di.step1;
public class FreeBoardServiceImpl2 implements IFreeBoardService{
IFreeBoardDao freeBoardDao=new FreeBoardDaoOracle();
@Override
public void getBoardListService() {
freeBoardDao.getBoardListDao();
}
}
package com.di.step1;
public class FreeBoardServiceImpl3 implements IFreeBoardService{
IFreeBoardDao freeBoardDao=new FreeBoardDaoOracle();
@Override
public void getBoardListService() {
freeBoardDao.getBoardListDao();
}
}
그리고 Main메소드가 있는 TestBoard.java를 만들어봅시다.
package com.di.step1;
public class Test {
public static void main(String[] args) {
IFreeBoardService freeBoardService1=new FreeBoardServiceImpl1();
freeBoardService1.getBoardListService();
IFreeBoardService freeBoardService2=new FreeBoardServiceImpl2();
freeBoardService2.getBoardListService();
IFreeBoardService freeBoardService3=new FreeBoardServiceImpl3();
freeBoardService3.getBoardListService();
}
}
이 main 메소드를 실행하면 FreeBoardServiceImpl1, 2, 3의 메소드가 각각 실행됩니다.
이 각각의 FreeBoaredServiceImpl1,2,3에서는 같은 FreeBoardDaoOracle을 실행합니다.
즉 3개의 Service전부 같은 Dao를 실행해 "OracleDao가 실행되었습니다"라는 문구가 3번 실행될 뿐입니다.
이 때 FreeBoardServiceImpl1,2,3 는 모두
FreeBoardDaoOracle의 getBoardListDao메소드를 호출 합니다.
이와 같이 특정 클래스에서 다른객체의 메소드를 호출할 때 이를 의존한다고 합니다.
여기서는 FreeBoardServiceImpl1,2,3가 FreeBoardDaoOracle에 의존한다고 할 수 있습니다.
이렇게 프로그램을 만들고 지금까지 문제없이 Oracle Dao가 실행이 되었었는데,
회사에서 갑자기 Oracle대신 Mysql을 사용하기로 결정이 났습니다.
그래서 부랴부랴 FreeBoardDaoMysql을 만들었습니다.
FreeBoardDaoMysql.java
package com.di.step1;
public class FreeBoardDaoMysql implements IFreeBoardDao{
@Override
public void getBoardListDao() {
System.out.println("Mysql Dao 실행됩니다.");
}
}
이제 Dao에서 FreeBoardDaoOracle 대신에 FreeBoardDaoMysql이 실행되도록 해야합니다.
이런, 변경사항을 적용하려고 하니 FreeBoardServiceImpl1,2,3 에서 모두 바꿔줘야 되는군요.
변경사항은 단순히 Oracle에서 Mysql로 바꾸라는거였는데
이를 적용하기 위해선 총 3곳을 수정해야 합니다.
이렇게 수정해야할 곳이 많다는 건 변경에 약하고, 확장성, 유지보수 등등이
모두 힘들다는걸 의미합니다.
그러면 어떻게 하면 확장,유지보수, 변경 등에 강하게 만들 수 있을까요?
사실 step1에서 이와 같은 일이 일어난 이유는 의존객체를 직접 생성했기 때문입니다.
물론 의존객체를 직접생성하는게 무조건 나쁜 건 아닙니다만 의존객체를 직접 생성하지 않고
외부에서 받으면 그에 따른 장점이 있습니다.
이를 step2에서 확인해 보겠습니다.
우선 com.di.step2 패키지를 만들고 step1의 있는 내용을 복사해주세요.
그리고 FreeBoardServiceImpl2,3은 삭제해주겠습니다.
이 상태에서 FreeBoardServiceImpl1 의 내용을 바꾸겠습니다.
FreeBoardDaoOracle 객체를 직접 생성하지않고
외부(여기에선 Test.java의 메인메소드)에서 받는 걸로 바꾸겠습니다.
외부에서 받는 방법은 생성자, Setter방식이 있습니다만 여기서는 생성자 방식으로 설명하겠습니다.
바뀐 FreeBoardServiceImpl1.java
package com.di.step2;
public class FreeBoardServiceImpl1 implements IFreeBoardService{
IFreeBoardDao freeBoardDao;
public FreeBoardServiceImpl1(IFreeBoardDao freeBoardDao) {
this.freeBoardDao=freeBoardDao;
}
@Override
public void getBoardListService() {
freeBoardDao.getBoardListDao();
}
}
FreeBoardServiceImpl1의 생성자를 보시면 객체를 생성할 때
반드시 IFreeBoardDao 객체를 받아야합니다.
이제 이 FreeBoardServiceImpl1을 2개 복사해서 FreeBoardServiceImpl2,3을 만들어줍시다.
이제 Test.java의 main메소드를 다음과 같이 만들어줘야 합니다.
package com.di.step2;
public class Test {
public static void main(String[] args) {
IFreeBoardDao freeBoardDao= new FreeBoardDaoOracle();
IFreeBoardService freeBoardService1=new FreeBoardServiceImpl1(freeBoardDao);
freeBoardService1.getBoardListService();
IFreeBoardService freeBoardService2=new FreeBoardServiceImpl2(freeBoardDao);
freeBoardService2.getBoardListService();
IFreeBoardService freeBoardService3=new FreeBoardServiceImpl3(freeBoardDao);
freeBoardService3.getBoardListService();
}
}
여기서 봐야 할 건 FreeBoardServiceImpl객체를 만들 때
IFreeBoardDao 타입의 객체를 생성자의 파라미터로 제공해줍니다.
이렇게 어떤 객체를 외부에서 주는거를 Injection(주입) 이라고 합니다.
또 FreeBoardService가 FreeBoardDao한테 의존하고 있는 상황에서
해당 의존객체를 외부에서 주입하는 것을 Dependency Injection(의존주입) 이라고 합니다.
자, 이제 main메소드를 실행하면 "Oracle Dao 실행되었습니다"가 3번 나옵니다.
이런 상황에서 Oracle 대신 Mysql을 사용하기 위해
FreeBoardDaoOracle 객체 대신 FreeBoardDaoMysql 객체를 사용하려고 합니다.
step1과 같은 상황이지만 이제 FreeBoardServiceImpl1,2,3에서 전부 바꿔주는 대신
Test의 메인메소드에서만
IFreeBoardDao freeBoardDao= new FreeBoardDaoOracle(); 부분을
IFreeBoardDao freeBoardDao= new FreeBoardDaoMysql(); 로 바꿔주기만 하면 됩니다.
의존주입을 적용했더니 변경사항에 대해 수정할 곳이 줄어든 것을 확인할 수 있습니다.
DI를 적용했더니 변경에 좀 더 유연한 걸 확인할 수 있었는데,
다음과 같이 Test2.java가 있다고 가정해봅시다.
Test2.java
package com.di.step2;
public class Test2 {
public static void main(String[] args) {
IFreeBoardDao freeBoardDao= new FreeBoardDaoOracle();
IFreeBoardService freeBoardService1=new FreeBoardServiceImpl1(freeBoardDao);
freeBoardService1.getBoardListService();
IFreeBoardService freeBoardService2=new FreeBoardServiceImpl2(freeBoardDao);
freeBoardService2.getBoardListService();
IFreeBoardService freeBoardService3=new FreeBoardServiceImpl3(freeBoardDao);
freeBoardService3.getBoardListService();
}
}
DI를 적용해서 FreeBoardServiceImpl객체를 만들 때
IFreeBoardDao 구현클래스의 객체를 주입 받았지만
위와 같이 Test, Test2가 있으면
Oracle 대신 Mysql을 사용하는 상황에서는 2군데를 변경해주어야 합니다.
이를 해결하기 위해선 어떻게 해야 할 까요?
바로 Assembler라는 클래스를 적용하면 됩니다. 여기서부터는 step3입니다.
com.di.step3패키지에 step2내용을 복사해 줍시다.
그리고 Test, Test2의 main메소드 내용을 지워줍시다.
그리고 Asssembler라는 클래스를 만들어주세요.
Assembler는 생성자에서 FreeBoardDaoOracle, FreeBoardService1,2,3 객체를 만들어 필드에 저장합니다.
Asssembler.java
package com.di.step3;
public class Assembler {
IFreeBoardDao freeBoardDao;
IFreeBoardService freeBoardservice1;
IFreeBoardService freeBoardservice2;
IFreeBoardService freeBoardservice3;
public Assembler() {
freeBoardDao=new FreeBoardDaoMysql();
freeBoardservice1=new FreeBoardServiceImpl1(freeBoardDao);
freeBoardservice2=new FreeBoardServiceImpl2(freeBoardDao);
freeBoardservice3=new FreeBoardServiceImpl3(freeBoardDao);
}
public IFreeBoardDao getFreeBoardDao() {
return freeBoardDao;
}
public void setFreeBoardDao(IFreeBoardDao freeBoardDao) {
this.freeBoardDao = freeBoardDao;
}
public IFreeBoardService getFreeBoardservice1() {
return freeBoardservice1;
}
public void setFreeBoardservice1(IFreeBoardService freeBoardservice1) {
this.freeBoardservice1 = freeBoardservice1;
}
public IFreeBoardService getFreeBoardservice2() {
return freeBoardservice2;
}
public void setFreeBoardservice2(IFreeBoardService freeBoardservice2) {
this.freeBoardservice2 = freeBoardservice2;
}
public IFreeBoardService getFreeBoardservice3() {
return freeBoardservice3;
}
public void setFreeBoardservice3(IFreeBoardService freeBoardservice3) {
this.freeBoardservice3 = freeBoardservice3;
}
}
이제 Test , Test2 메인메소드를 다음과 같이 작성합시다. (Test랑 Test2랑 내용은 같습니다.)
package com.di.step3;
public class Test {
public static void main(String[] args) {
Assembler assembler=new Assembler();
IFreeBoardService freeBoardService1=assembler.getFreeBoardservice1();
freeBoardService1.getBoardListService();
IFreeBoardService freeBoardService2=assembler.getFreeBoardservice2();
freeBoardService2.getBoardListService();
IFreeBoardService freeBoardService3=assembler.getFreeBoardservice3();
freeBoardService3.getBoardListService();
}
}
이제 Oracle 대신 Mysql로 변경하라는 지시가 있어도 Assembler 클래스 1군데만 바꾸면 됩니다.
이렇게 Assembler를 이용하면 DI를 쉽게 적용가능하고 변경에 좀 더 유연하게 됩니다.
그럼 이 DI를 Asssembler라는 조립기를 통해 배웠는데
왜 스프링을 배우는데 Assembler를 알아봤을까요?
바로 스프링이 이 Assembler 클래스처럼 스프링에서 제공하는 객체를 관리하기 때문입니다.
step4부터는 스프링에서 Assembler처럼 객체를 관리하는 방법에 대해서 하겠습니다.
step3의 패키지를 복사합니다.
Spring이 Assembler처럼 객체관리하는 방법을 제공한다 했으므로 Assembler클래스를 삭제합니다.
또 이제 Assebler를 이용하면 Test, Test2있어도 변경에 강하다는건 확인했으니 Test2는 지우고
Test만 남깁시다. Test의 내용은 Assembler가 아닌 spring에 맞게 작성할 거니 일단 지웁시다.
그리고 src/main/resources에 di라는 폴더를 만들어줍시다.
폴더에서 new-other를 한 후 spring을 검색해줍니다.
spring Bean Cponfiguration File을 선택해줍시다.
이름은 step4로 하겠습니다.
만들어진 파일을 보면 xml 파일로 되어있는것을 볼 수 있습니다.
spring은 이 xml을 읽어서 객체를 관리한다.
(물론 xml외에도 java파일이나 그외 여러파일을 읽어서 관리할 수 있다.)
spring은 step4.xml을 읽은 후 xml에서 명시된 대로 특정 java클래스의 객체를 생성하고 관리한다.
이 때 spring이 생성한 객체를 'Bean'이라 한다.
우선 spring이 BoardDaoOracle객체를 만들도록 step4.xml을 다음과 같이 작성해보자.
step4.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<bean id="boardDaoOracle" class="com.di.step4.FreeBoardDaoOracle"></bean>
<bean id="freeBoardService1" class="com.di.step4.FreeBoardServiceImpl1">
</bean>
</beans>
spring은 step4.xml을 읽어서 boardDaoOracle과 freeBoardService1객체를 만들려 한다.
id는 객체의 이름이다.
이 때 FreeBoardServiceImpl1 Bean정의 부분에서 에러가 난다.
Multiple annotations found at this line: - No constructor with 0 arguments defined in class
왜 나는 걸까?
이쯤 다시 FreeBoardServiceImpl1.java를 살펴보자.
package com.di.step4;
public class FreeBoardServiceImpl1 implements IFreeBoardService{
IFreeBoardDao freeBoardDao;
public FreeBoardServiceImpl1(IFreeBoardDao freeBoardDao) {
this.freeBoardDao=freeBoardDao;
}
@Override
public void getBoardListService() {
freeBoardDao.getBoardListDao();
}
}
spring이 FreeBoardServiceImpl1객체를 만들려하는데 FreeBoardServiceImpl1은 생성자가 1개뿐이다.
그리고 그 생성자는 IBoardDao에 해당하는 객체를 주입받아야 한다.
그래서 step4.xml에서 주입에 관한 내용 없이 객체를 생성할 수 없다는 에러가 나는 것이다.
에러가 나지 않고 정상적으로 freeBoardService1 빈(객체)을 생성하기 위해선
Bean태그에 주입에 관한 내용을 작성해주면 된다.
또 만드는 김에 freeBoardService1도 만들어 줍니다.
step4.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<bean id="boardDaoOracle" class="com.di.step4.FreeBoardDaoOracle"></bean>
<bean id="freeBoardService1" class="com.di.step4.FreeBoardServiceImpl1">
<constructor-arg ref="boardDaoOracle"></constructor-arg>
</bean>
<bean id="freeBoardService2" class="com.di.step4.FreeBoardServiceImpl2" c:freeBoardDao-ref="boardDaoOracle">
</bean>
<bean id="freeBoardService3" class="com.di.step4.FreeBoardServiceImpl3">
<constructor-arg ref="boardDaoOracle"></constructor-arg>
</bean>
</beans>
constructor-arg태그의 사용법이 어렵지는 않을 것이다.
freeBoardService2부분에 c:boardDao-ref속성은 contructor-arg태그를 좀 더 쉽게 사용하기 위해서
spring에서 제공해주는 기능으로 contructor-arg태그랑 차이점은 없다.
c:boardDao-ref속성을 사용하기 위해서는 namespace에서 다음과 같이 체크해줘야 한다.
contrcutor-arg나 c:boardDao-ref나 사용법보다는 FreeBoardServiceImpl객체를 만드는데
boardDaoOracle객체를 주입받아야한다는 사실만 기억하자.
이제 Test의 내용을 작성해봅시다.
Test에서는 우리가 만들었던 step4.xml을 읽어서 객체를 저장하고
관리해주는 컨테이너 객체를 사용해야합니다.
컨테이너에 대해서는 나중에 좀더 자세히 다루도록 하고 일단 다음과 같이 Test를 작성해봅시다.
Test.java
package com.di.step4;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
public class Test {
public static void main(String[] args) {
AbstractApplicationContext context=new GenericXmlApplicationContext("di/step4.xml");
FreeBoardServiceImpl1 freeBoardServiceImpl1= context.getBean("freeBoardService1",FreeBoardServiceImpl1.class);
FreeBoardServiceImpl2 freeBoardServiceImpl2= context.getBean("freeBoardService2",FreeBoardServiceImpl2.class);
FreeBoardServiceImpl3 freeBoardServiceImpl3= context.getBean("freeBoardService3",FreeBoardServiceImpl3.class);
freeBoardServiceImpl1.getBoardListService();
freeBoardServiceImpl2.getBoardListService();
freeBoardServiceImpl3.getBoardListService();
context.close();
}
}
코드를 보시면 step3와 굉장히 비슷한 걸 알 수 있습니다.
단지 step3에서 Assembler가 FreeBoardService1,2,3, FreeBoardDaoOracle의 객체를
가지고 있었다면 이제는 저 context라는 객체가 step4.xml을 읽은 후에
객체를 가지고 있다는 것만 다릅니다.
실행하면 문제없이 step3와 같이 결과가 문제없이 나올것입니다.
자, 이번엔 step4.xml을 다음과 같이 수정하고
(freeBoardService1을 만드는데 의존객체 주입을 명시해주지않은 상태에서)
Test를 실행해봅시다.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<bean id="boardDaoOracle" class="com.di.step4.FreeBoardDaoOracle"></bean>
<bean id="freeBoardService1" class="com.di.step4.FreeBoardServiceImpl1">
<!-- <constructor-arg ref="boardDaoOracle"></constructor-arg> -->
</bean>
<bean id="freeBoardService2" class="com.di.step4.FreeBoardServiceImpl2" c:freeBoardDao-ref="boardDaoOracle">
</bean>
<bean id="freeBoardService3" class="com.di.step4.FreeBoardServiceImpl3">
<constructor-arg ref="boardDaoOracle"></constructor-arg>
</bean>
</beans>
다음과 같은 에러가 나오는 걸 볼 수 있습니다.
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'freeBoardService1' defined in class path resource [di/step4.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.di.step4.FreeBoardServiceImpl1]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.di.step4.FreeBoardServiceImpl1.<init>()
해석을 해보면 freeBoardService1을 만드는데 에러가 났다. FreeBoardService1()메소드는 없더라...
이런 뜻입니다.
FreeBoardService1에는 FreeBoardService1(IFreeBoardDao freeeBoardDao)만 있습니다.
즉 여기에 맞춰서 의존객체를 주입해줘야만 FreeBoardService1객체를 만들 수 있는데
그러지 않아서 'freeBoardService1객체 못 만들겠다' 하고 에러가 난 것입니다.
이 Error createing bean with name " someThing" 에러는 spring에서 가장 자주 보이는 에러니
에러가 나는 이유를 꼭 DI와 연결해서 기억하고 있어야합니다.
이제 step4의 내용을 복사해 step5를 만들어줍시다.
그리고 src/main/resources에는 step5.xml(new other-spring Bean Configuration File)을
만들어줍니다.
그리고 step5.xml의 namespace에서 context를 체크해줍니다.
그리고 다음과 같이 작성해줍시다.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<context:component-scan base-package="com.di.step5"></context:component-scan>
<!-- package를 스캔해서 @(전부는 아니고 몇개종류의)가 붙어있는 클래스들은 객체를 만들어서 가지고 있겠다.-->
</beans>
context:component-scan은 base-package의 패키지를 스캔해서 특정
@이 붙어있는 클래스들은 빈 등록을 하는 태그입니다.
step5.xml을 위와 같이 작성 한 후 저희는 com.di.step5 패키지에 있는 클래스에 @을 붙어주면 됩니다.
FreeBoardDaoOracle.java (Mysql에는 아직 @을 붙이지 말자)
package com.di.step5;
import org.springframework.stereotype.Component;
@Component
public class FreeBoardDaoOracle implements IFreeBoardDao{
@Override
public void getBoardListDao() {
System.out.println("Oracle Dao 실행되었습니다.");
}
}
FreeBoardServiceImpl1.java (2,3도 같습니다.)
package com.di.step5;
import javax.inject.Inject;
import org.springframework.stereotype.Component;
@Component
public class FreeBoardServiceImpl1 implements IFreeBoardService{
@Inject
IFreeBoardDao freeBoardDao;
@Override
public void getBoardListService() {
freeBoardDao.getBoardListDao();
}
}
이렇게 클래스에 @Component를 붙이면 스프링은 해당 클래스를 빈 등록을 합니다.
또, FreeBoardServiceImpl1을 보면 IFreeBoardDao freeBoardDao에 @Inject가 붙여있는데
이는 step4에서 <constructor-arg></constructor-arg> 와 비슷한 역할을 합니다.
생성자 방식, setter방식, 필드 방식의 의존주입이 있고, 그 중 필드 주입방식을 적용한 것입니다.
필드IFreeBoardDao @Inject를 붙여주면 FreeBoardServiceImpl1객체를 만들 때
IFreeBoardDao에 해당하는 객체를 가지고 있어야 한다는 것입니다.
이렇게 의존객체를 직접 xml에서 주입하는게 아니라 @Inject를 이용해 주입하는것을
의존객체를 자동으로 스프링이 주입한다고 해서 의존 자동 주입이라고 합니다.
(만약 IFreeBoardDao타입인 FreeBoardDaoOracle,Mysql에 @Component가 없다면
Error creating bean with name freeBoardServiceImpl1 에러가 납니다.)
Test에서는 GenericXmlApplicationContext의 파라미터만 step5.xml로 바꿔 step4와 똑같이 작성해줍니다.
이렇게 xml에서 빈을 자동으로 만들지 않고 component-scan과 @을 통해 빈을 등록하는 법까지 했습니다.
실제로 web을 spring으로 만들때 Controller, Service, Dao영역의 객체는 대부분 @을 이용해 빈을 등록하고
그외의 특정 spring기능의 객체는 따로 bean태그를 써서 등록 해줍니다.
마지막으로 별로 중요하진 않지만 이렇게 빈 등록하는 방법이 xml만 있는 건 아닙니다.
먼저 step5를 복사해서 step6를 만듭시다.
그리고 step6에서는 JavaConfig.java라는 클래스를 만듭시다.
package com.di.step6;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = "com.di.step6")
public class JavaConfig {
}
그리고 Test에서는 GenericXmlApplicationContext 대신
AnnotationConfigApplicationContext를 사용해 빈을 등록합니다.
Test.java
package com.di.step6;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(JavaConfig.class);
//AnnotationConfigApplicationContext은 spring4에서하거나
//spring 3에서 할려면 cglib 디펜던시 추가
FreeBoardServiceImpl1 freeBoardServiceImpl1= context.getBean(FreeBoardServiceImpl1.class);
//현재 FreeBoardServiceImpl1에 해당하는 객체가 1개여서 에러가 안나요. 객체를 2개 만들면 에러나요. 그때는 객체이름도 같이 지정해줘야..
FreeBoardServiceImpl2 freeBoardServiceImpl2= context.getBean(FreeBoardServiceImpl2.class);
FreeBoardServiceImpl3 freeBoardServiceImpl3= context.getBean(FreeBoardServiceImpl3.class);
freeBoardServiceImpl1.getBoardListService();
freeBoardServiceImpl2.getBoardListService();
freeBoardServiceImpl3.getBoardListService();
context.close();
}
}
step5와 똑같습니다. 단지 xml 대신 JavaConfig라는 클래스를 이용해 빈을 등록할 뿐입니다.
(혹시 step6가 에러가 난다면 pom.xml에
cglib 라이브러리를 추가하거나 spring 버전을 4로 올립시다.)
DI의 기본 개념을 아는 게 중요하고, spring에서 Error creating bean 에러가 났을 때 왜 나는지 알고
그것을 해결할 수 있으면 Spring web project 개발에 많은 도움이 될 것입니다.
(사실 DI를 모르면 Spring 관련 어떤 것도 할 수 없습니다..)