본문 바로가기
프로그래밍/Spring

[Spring] Spring의 정의와 기본 개념

by 사바라다 2020. 2. 21.

안녕하세요. 대다수의 Java를 주 언어로 사용하는 분들이 사용하는 Web Framework가 바로 Spring FrameWork입니다. 오늘은 Spring정의와 기본 개념, 그리고 Spring의 목표에 대해서 알아보도록 하겠습니다.

정의

토비의 스프링을 보면 Spring은 아래와 같이 정의되어 있습니다.

자바 엔터프라이즈 애플리케이션 개발에 사용되는 애플리케이션 프레임워크

엔터프라이즈 서비스이라는 것은 실제 기업에서 사용할 수 있을 정도의 시스템으로 UI, 서비스 로직을 포함하여 있는 것이 아니라 보안, 트랜잭션과 같은 엔터프라이즈 시스템에서 요구되는 기술을 포함하는 서비스입니다.

목적

어떤 기술이든 그 자체로는 도구에 불과하며 용도에 맞게 잘 활용해서 궁극적으로 이루고자 하는 목표를 이루는 것이 중요합니다. 스프링의 목적은 엔터프라이즈 어플리케이션 개발을 편하게하는것입니다.

엔터프라이즈 시스템 개발은 기본적으로 편하지 않고 복잡합니다. 토비의 스프링에서는 아래와 같이 2가지 이유를 들어 설명합니다.

기술적인 제약조건과 요구사항이 늘어가기 때문

엔터프라이즈 시스템은 많은 사용자의 요청을 동시에 처리해야 하기 때문에 서버의 자원을 효율적으로 공유하고 분배해서 사용할 수 있어야 합니다. 또한 중요한 기업의 핵심 정보를 처리하기 때문에 보안과 안정성, 확장성 면에서도 뛰어나야 합니다. 따라서 뛰어난 성능과 서비스의 안정성이 요구되며 그런 점을 고려한 개발 기술이 필요합니다. 데이터베이스와의 연동, 타 시스템과의 연동 등 복잡함이 증가될 수 밖에없습니다.

엔터프라이즈 어플리케이션이 구현해야 할 핵심기능인 비즈니스 로직의 복잡함이 증가하기 때문

현대는 엔터프라이즈 시스템을 이용하여 기업의 핵심 업무를 처리하는 비율이 늘어가고 있습니다. 점차 대부분의 업무 처리는 컴퓨터를 이용하지 않고는 진행되지 않을만큼 엔터프라이즈 시스템의 의존도가 높아지고 있습니다. 기업 업무 자체만으로도 복잡합니다만 다양한 예외사항과 처리해야하는 정보의 규모도 상당합니다. 또한 기능 요구사항 및 시스템의 변경이 있을 수도 있습니다. 이런 점들로 인해 개발의 부담은 커지고 난이도는 더욱 증가하는 것입니다.

이런 2가지의 복잡성은 엔터프라이즈 시스템이라면 모두 갖추고 있어야할 필수적인 요건들입니다. 기능을 삭제하던가 보안을 약하게 가져간다던가로 해결될 수 있는 부분이 아닙니다. 엔터프라이즈 시스템의 복잡성은 제거하는 것이 아닌 시스템의 복잡성과의 명확한 분리하는것이 최선입니다.

원리

Spring은 기술적인 제약조건과 비즈니스로직의 복잡함이라는 두 가지의 복잡성을 어떻게 분리할까요 ? 바로 비즈니스로직의 코드에서 기술적인 복잡함을 제거함에 있습니다. 코드 하나를 보도록 하겠습니다. Java에서 DB를 사용할때 Jdbc를 사용합니다. 그러면 기본적인 코드는 아래와 같이 구현할 수 있습니다.

public void  DBTest() {
    String serverURL = "jdbc:mysql://localhost:3306/sys";    //    주소:포트/db명
    String id = "root"; // 계정명
    String pw = "1234"; // 비밀번호

    try {
        Class.forName("com.mysql.jdbc.Driver");
        Connection con = DriverManager.getConnection(serverURL, id, pw);

        String sql = "insert into emp(empno, ename, age, deptno, mgr) values(1, '오라클', 22, 0423, 05)";

        PreparedStatement pstmt = con.prepareStatement(sql);
        pstmt.executeUpdate();
    } catch (ClassNotFoundException e) {
        System.out.println("드라이버가 존재하지 않습니다");
    } catch (SQLException e) {
        e.printStackTrace();
    }finally {
        pstmt.close();
        conn.close();
    }
}

위 코드는 기술적인 제약조건과 비즈니스로직을 모두 가지고 있는 코드입니다. jdbc를 사용하며 이를 사용하기 위해서 db에 연결하며 쿼리를 실행하여 결과를 가져옵니다. 비즈니스는 emp 테이블에 insert하고자 하는 것이며 기술적인 제약조건은 DB의 연결과 쿼리 실행이 될 것입니다. Spring에서는 이런 코드를 아래와 같이 간단히 구현합니다.

@Autowired
private JdbcTemplate jdbcTemplate;

public void DBTest() {
    String sql = "insert into emp(empno, ename, age, deptno, mgr) values(1, '오라클', 22, 0423, 05)";
    jdbcTemplate.update(sql);
}

JdbcTemplate는 DB와의 Connection에 대해서 추상화되어 대신 처리해 주며 있으며 우리는 이제 비즈니스에만 집중할 수 있게 되었습니다.

여기에 요구사항으로 2개의 insert가 발생되어야 하며 이때 Transaction을 만족시켜야한다는 요구사항이 추가되었습니다. 그러면 각각 소스는 아래와 같이 수정되어야 할것입니다.

public void  DBTest() {
    String serverURL = "jdbc:mysql://localhost:3306/sys";    //    주소:포트/db명
    String id = "root"; // 계정명
    String pw = "1234"; // 비밀번호

    try {
        Class.forName("com.mysql.jdbc.Driver");
        Connection con = DriverManager.getConnection(serverURL, id, pw);
        con.setAutoCommit(false); // transaction 유지를 위해 AutoCommit false

        String sql_1 = "insert into emp(empno, ename, age, deptno, mgr) values(1, '오라클', 22, 0423, 05)";
        String sql_2 = "insert into emp(empno, ename, age, deptno, mgr) values(2, 'mysql', 23, 0424, 06)";

        PreparedStatement pstmt_1 = con.prepareStatement(sql_1);
        pstmt.executeUpdate();

        PreparedStatement pstmt_2 = con.prepareStatement(sql_2);
        pstmt.executeUpdate();

        conn.commit();
    } catch (ClassNotFoundException e) {
        System.out.println("드라이버가 존재하지 않습니다");
    } catch (SQLException e) {
        e.printStackTrace();
        conn.rollback(); // rollback
    }finally {
        pstmt_1.close();
        pstmt_2.close();
        conn.close();
    }
}

transaction을 유지하기 위해서 autoCommit을 false로 했으며 2개의 insert가 모두 성공했을 때만 commit하며 하나라도 실패하면 rollback을 하도록 처리했습니다. 코드가 중간중간 변경됨을 알 수 있습니다.

아래는 Spring을 통해 구현했습니다. @Transactional 어노테이션 하나로 구현이 마무리됬습니다.

@Autowired
private JdbcTemplate jdbcTemplate;

@Transactional
public void DBTest() {
    String sql_1 = "insert into emp(empno, ename, age, deptno, mgr) values(1, '오라클', 22, 0423, 05)";
    String sql_2 = "insert into emp(empno, ename, age, deptno, mgr) values(2, 'mysql', 23, 0424, 06)";

    jdbcTemplate.update(sql_1);
    jdbcTemplate.update(sql_2);
}

이게 Spring에서 제공하는 기술 제약과 비즈니스 로직의 분리입니다. 일반 Java 코드의 경우 기술 제약의 변경이든 비즈니스 로직의 변경이든 모두 메서드 안의 코드를 수정해야합니다. 하지만 Spring을 사용했을 경우 기술 제약의 변경에 대해서 기존 메서드 안에서의 소스 수정이 없습니다. 이렇게 기술 제약와 비즈니스 로직을 분리하는 것입니다.

Spring은 적용한 기술이 메서드나 Class 코드에 직접 반영되지 않는 특징을 가지고 있습니다. 이런 기술을 비침투적인(non-invasive) 기술이라고 합니다. 이런 비침투적인 기술로 인해 기술 제약과 비즈니스 로직을 완벽하게 분리할 수 있게 되었습니다. 그리고 POJO 프로그래밍이 가능하게 되었습니다.

Spring이 비침투적인 기술로 만들기위한 3가지 핵심있습니다. IoC/DI, AOP(Aspect Oriented Programing), PSA(Portable Service Abstraction)입니다.

Spring Core Triangle, https://www.slideshare.net/deview/spring-framework-58742119

마무리

오늘은 이렇게 Spring의 정의와 기본 개념에 대해서 알아보았습니다. 사실 코드를 따라가는 예제보다 이런 개념에 대해서 서술하는 포스팅이 더 조심스럽습니다. 그럼에도 최선을 다해보도록 하겠습니다.

도움이 되셨다면 하트와 아랫 광고 한번 클릭 부탁드려요 !

감사합니다.

참조

토비의 스프링 3.1

https://www.slideshare.net/deview/spring-framework-58742119

댓글