목차

sun cloud


Maven

: 의존 라이브러리(dependency library)를 일괄적으로 관리하기 위한 도구입니다.

기존에는 사용할 라이브러리 수가 많지 않았기에 직접 jar 파일을 추가해서 사용했지만, 규모가 커질수록 사용해야 할 라이브러리들이 많아질 수 밖에 없기 때문에 더욱 Maven 또는 Gradle과 같은 도구들이 중요하게 사용되고 있습니다.

pom.xml 설정 파일(Project Object Model의 약자입니다)에 필요한 라이브러리를 추가해서 사용하며, 처음 라이브러리를 가져올 때에는 원격 저장소에 있는 라이브러리를 로컬 저장소(.m2 디렉토리)에 받아오고, 그 뒤로는 로컬 저장소에 받아온 라이브러리를 재사용합니다.


Maven repository에서 <dependency> 코드를 가져오면 이클립스에서 원격지의 라이브러리들을 받아올 수 있습니다.

MVN



Maven 적용

이제 본격적으로 프로젝트를 생성해서 Maven을 적용해보도록 하겠습니다.

java project 생성 후 Package Explorer에서 프로젝트에 우클릭을 하면 Configure - convert to maven project 항목이 있습니다.

여기서 설정 파일인 pom.xml을 생성합니다.(생성할 때 다른 항목은 수정할 필요가 없습니다)

image


생성된 pom.xml 하단의 </build> 태그와 </project> 태그 사이에 다음과 같이 코드를 추가하면 라이브러리를 가져올 수 있습니다.

1
2
3
4
5
6
7
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.3.14.RELEASE</version>
    </dependency>
</dependencies>

(현재 레거시 연습을 위해 Maven 4.3.14 버전을 사용하지만, 추후 스프링 부트 사용 시 5.x 버전을 사용할 예정입니다)


Maven 오류 발생 시 대처 방안

위와 같이 적용을 해도 Maven이 제대로 적용되지 않거나 에러가 발생할 수 있습니다. 그럴 경우 아래의 조치를 취해주시면 됩니다.

  1. 해당 프로젝트 우클릭 후 Maven - Update Project
  2. 업데이트로도 안될 경우
    Eclipse Restart
  3. 재시작으로도 안될 경우
    이클립스를 끈 상태에서 m2 디렉토리를 직접 삭제한 뒤 다시 작업

image



예제

xml 설정 방식의 DI 사용 연습을 해보겠습니다.

우선 MemberDAOMemberService 인터페이스를 생성할텐데, 이클립스에서는 편의 상 Impl 클래스를 먼저 생성한 뒤 refactor - Extract Inerface 기능을 사용하면 편리하게 작성할 수 있습니다.

interface를 구현하는 구현체는 관례적으로 끝에 Impl을 붙입니다

또한 싱글톤 패턴을 적용할 때 기존 mvc 구조에서는 직접 명시해야만 했지만, 스프링 프레임워크에서는 IOC 컨테이너(or DI 컨테이너)가 기본적으로 싱글톤 적용을 해주기에 별도의 설정이 필요하지 않습니다.

다음과 같이 간단하게 MemberDAOImpl 클래스를 작성한 뒤, 인터페이스를 추출합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
package model;

public class MemberDAOImpl implements MemberDAO {
    @Override
    public String findMemberById(String id) {
        if(id.equals("java")) {
            return "java 아이유 오리";
        } else {
            return null;
        }
    }
}

1
2
3
4
5
package model;

public interface MemberDAO {
    String findMemberById(String id);
}


이제 MemberServiceImpl 클래스도 작성해보겠습니다. (흔히 Service 계열의 클래스는 트랜잭션 처리를 위한 비즈니스 계층의 컴포넌트로 사용됩니다)

1
2
3
4
5
6
7
8
9
10
11
12
13
package model;
public class MemberServiceImpl implements MemberService {
    private MemberDAO memberDAO;
    public MemberServiceImpl(MemberDAO memberDAO) {
        super();
        this.memberDAO = memberDAO;
    }
    @Override
    public String findMemberById(String id) {
        return memberDAO.findMemberById(id);
    }
}

MemberDAO를 인터페이스 타입으로 참조했기에 결합도를 느슨하게 할 수 있습니다.

스프링 IOC(or DI) Container에서 memberDAO 구현체를 주입합니다.

위의 구현체를 주입하는 것을 Dependency Injection이라고 부르며 xml, annotation 두 가지 방식으로 구현할 수 있습니다.(실무에서는 애너테이션 방식이 주로 사용되지만, 우선 xml 방식을 배운 뒤 애너테이션 방식으로 넘어갈 예정입니다)

spring-config.xml 파일은 다음과 같이 작성합니다.

1
2
3
4
5
6
7
8
9
10
11
12
<?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="memberDAO" class="model.MemberDAOImplVer2"></bean>
    <bean id="memberService" class="model.MemberServiceImpl">
        <constructor-arg>
            <ref bean="memberDAO"/>
        </constructor-arg>
    </bean>
</beans>

<beans> 태그 안에 저희에게 필요한 <bean>들을 작성하며, 의존관계가 필요한 memberService 빈에 memberDAO 빈을 주입받을 수 있도록 <constructor-arg> 태그를 사용했습니다.

의존관계 주입(DI)은 위에서와 같이 생성자에 주입받거나, Setter 메서드 또는 Filed에 주입받는 방법이 있습니다.

Setter 메서드에 의존관계를 주입받는다면 다음과 같이 MemberDAO 생성자 부분을 set() 메서드로 변경한 뒤 spring-config.xml 설정 파일에서 생성자 태그인 <constructor-arg> 태그를 <property> 태그로 변경하면 됩니다.

1
2
3
public void setMemberDAO (MemberDAO memberDAO) {
    this.memberDAO = memberDAO;
}
1
2
3
4
5
6
7
8
9
10
11
<bean id="memberService" class="model.MemberServiceImpl">
    <constructor-arg>
        <ref bean="memberDAO"/>
    </constructor-arg>
</bean>
<!-- 위 태그를 아래 태그로 변경(생성자 -> setter) -->
<bean id="memberService" class="model.MemberServiceImpl">
    <property name="memberDAO">
        <ref bean="memberDAO"/>
    </property>
</bean>

MemberService 인터페이스는 다음과 같이 간단히 작성했습니다.

1
2
3
4
5
package model;

public interface MemberService {
	String findMemberById(String id);
}

image

마지막으로 위에서 작성한 기능들을 동작시킬 Test 클래스를 작성해보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package test;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import model.MemberService;

public class TestDI {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext factory = new ClassPathXmlApplicationContext("spring-config.xml");
        MemberService memberService = (MemberService) factory.getBean("memberService");// DL(Dependency Lookup)
        System.out.println(memberService.findMemberById("java"));
        factory.close();
    }
}

실행해보면 다음과 같이 정상 작동하는 것을 확인할 수 있습니다.

image

이전 수업에서도 말씀드렸지만, 위와 같은 구조가 복잡해보일 수 있습니다. 그럼에도 이러한 방식이 많이 사용되고 강력한 이유는 유지보수와 확장성, 그리고 보다 본질적으로는 프로그램을 더욱 객체지향스럽게 만들 수 있기 떄문입니다.

외부에서 필요한 의존관계를 주입받음으로써 구현체들은 자신들의 역할에만 충실할 수 있게 되며 이는 규모가 커질수록 유지보수성, 확장성이 크게 향상됩니다.

지금보다 개선할 여지가 많이 남았지만 이후의 수업에서 차차 개선해보도록 하겠습니다.



맨 위로 이동하기

Java Web Programming 카테고리 내 다른 글 보러가기

댓글남기기