JSP Performance Optimization

JSP 성능 최적화

소개 (Introduction)

JSP(JavaServer Pages)는 서버 측에서 동적으로 콘텐츠를 생성하는 기술로, 성능 최적화는 애플리케이션의 반응 속도와 처리 능력을 향상시키기 위해 매우 중요합니다. 효과적인 성능 최적화는 더 나은 사용자 경험을 제공하며, 서버 자원의 효율적인 활용을 가능하게 합니다. 여기서는 JSP 애플리케이션의 성능을 최적화하는 다양한 방법과 예제를 상세히 설명합니다.

캐싱 (Caching)

캐싱은 자주 요청되는 데이터를 미리 저장하여, 동일한 요청이 있을 때 빠르게 응답하는 기술입니다.

예제: JSP 페이지 캐싱

JSP 페이지를 캐싱하여 정적 콘텐츠와 같이 취급할 수 있습니다. HTTP 헤더를 설정하여 캐싱을 제어할 수 있습니다.

<%
    // 캐싱 설정
    response.setHeader("Cache-Control", "max-age=3600, must-revalidate");
    response.setHeader("Pragma", "cache");
    response.setDateHeader("Expires", System.currentTimeMillis() + 3600000); // 1시간
%>
<html>
<head>
    <title>캐싱 예제</title>
</head>
<body>
    <h2>이 페이지는 캐싱됩니다.</h2>
    <p>현재 시간: <%= new java.util.Date() %></p>
</body>
</html>

데이터베이스 연결 최적화 (Database Connection Optimization)

데이터베이스 연결을 효율적으로 관리하는 것은 성능 최적화의 중요한 부분입니다. 커넥션 풀(Connection Pool)을 사용하면 데이터베이스 연결을 재사용하여 성능을 향상시킬 수 있습니다.

예제: Apache DBCP를 사용한 커넥션 풀

<!-- context.xml 파일 -->
<Resource name="jdbc/mydb" auth="Container"
          type="javax.sql.DataSource" maxTotal="20" maxIdle="10" maxWaitMillis="-1"
          username="root" password="password" driverClassName="com.mysql.jdbc.Driver"
          url="jdbc:mysql://localhost:3306/mydb"/>
// UserDAO.java 파일에서 커넥션 풀 사용
import javax.naming.InitialContext;
import javax.sql.DataSource;
import java.sql.Connection;

public class UserDAO {
    private DataSource dataSource;

    public UserDAO() {
        try {
            InitialContext ctx = new InitialContext();
            dataSource = (DataSource) ctx.lookup("java:comp/env/jdbc/mydb");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    // 데이터베이스 작업 메서드들 (예: insertUser, getUser)
}

JSP 페이지 최적화 (JSP Page Optimization)

JSP 페이지를 최적화하여 성능을 향상시킬 수 있습니다. 이는 불필요한 연산을 줄이고, 효율적인 코드 작성으로 가능합니다.

예제: 표현 언어(Expression Language)와 JSTL 사용

표현 언어와 JSTL(JSP Standard Tag Library)을 사용하면, JSP 페이지의 스크립트릿을 줄이고 성능을 최적화할 수 있습니다.

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
    <title>JSTL 예제</title>
</head>
<body>
    <h2>JSTL을 사용한 예제</h2>
    <c:set var="currentTime" value="<%= new java.util.Date() %>" />
    <p>현재 시간: ${currentTime}</p>
</body>
</html>

정적 콘텐츠 분리 (Separation of Static Content)

정적 콘텐츠(이미지, CSS, JavaScript)는 별도의 서버나 CDN(Content Delivery Network)에서 제공하여 성능을 향상시킬 수 있습니다.

예제: 정적 콘텐츠 분리

<html>
<head>
    <title>정적 콘텐츠 분리 예제</title>
    <link rel="stylesheet" type="text/css" href="https://cdn.example.com/styles.css">
    <script src="https://cdn.example.com/scripts.js"></script>
</head>
<body>
    <h2>정적 콘텐츠 분리</h2>
    <p>정적 파일은 CDN을 통해 제공됩니다.</p>
</body>
</html>

서블릿과 JSP의 역할 분리 (Separation of Servlet and JSP Roles)

서블릿은 비즈니스 로직과 데이터 처리를 담당하고, JSP는 데이터 표시를 담당하도록 역할을 분리합니다.

예제: 서블릿과 JSP 역할 분리

// UserServlet.java 파일
package com.example.controller;

import com.example.model.User;
import com.example.dao.UserDAO;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;

public class UserServlet extends HttpServlet {
    private UserDAO userDAO;

    public void init() {
        userDAO = new UserDAO();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String action = request.getServletPath();

        if ("/list".equals(action)) {
            listUsers(request, response);
        }
    }

    private void listUsers(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        List<User> userList = userDAO.getAllUsers();
        request.setAttribute("userList", userList);
        RequestDispatcher dispatcher = request.getRequestDispatcher("user-list.jsp");
        dispatcher.forward(request, response);
    }
}
<!-- user-list.jsp 파일 -->
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
    <title>사용자 목록</title>
</head>
<body>
    <h2>사용자 목록</h2>
    <table border="1">
        <tr>
            <th>사용자 이름</th>
            <th>이메일</th>
        </tr>
        <c:forEach var="user" items="${userList}">
            <tr>
                <td>${user.username}</td>
                <td>${user.email}</td>
            </tr>
        </c:forEach>
    </table>
</body>
</html>

압축 (Compression)

HTTP 응답을 압축하여 전송하는 것은 네트워크 대역폭을 줄이고 페이지 로드 속도를 높이는 데 도움이 됩니다.

예제: Gzip 압축 설정

<!-- web.xml 파일 -->
<filter>
    <filter-name>GzipFilter</filter-name>
    <filter-class>com.example.filter.GzipFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>GzipFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
// GzipFilter.java 파일
package com.example.filter;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;

public class GzipFilter implements Filter {
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        HttpServletRequest httpRequest = (HttpServletRequest) request;

        if (acceptsGZipEncoding(httpRequest)) {
            httpResponse.addHeader("Content-Encoding", "gzip");
            GzipResponseWrapper gzipResponse = new GzipResponseWrapper(httpResponse);
            chain.doFilter(request, gzipResponse);
            gzipResponse.close();
        } else {
            chain.doFilter(request, response);
        }
    }

    private boolean acceptsGZipEncoding(HttpServletRequest httpRequest) {
        String acceptEncoding = httpRequest.getHeader("Accept-Encoding");
        return acceptEncoding != null && acceptEncoding.contains("gzip");
    }
}

// GzipResponseWrapper.java 파일
package com.example.filter;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.GZIPOutputStream;

public class GzipResponseWrapper extends HttpServletResponseWrapper {
    private GZIPOutputStream gzipOutputStream = null;
    private ServletOutputStream servletOutputStream = null;

    public GzipResponseWrapper(HttpServletResponse response) throws IOException {
        super(response);
    }

    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        if (servletOutputStream == null) {
            servletOutputStream = new GzipServletOutputStream(getResponse().getOutputStream());
        }
        return servletOutputStream;
    }

    public void close() throws IOException {
        if (gzipOutputStream != null) {
            gzipOutputStream.close();
        }
    }

    class GzipServletOutputStream extends ServletOutputStream {
        private GZIPOutputStream gzipOutputStream;

        public GzipServletOutputStream(OutputStream output) throws IOException {
            this.gzipOutputStream = new GZIPOutputStream(output);
        }

        @Override
        public void write(int b) throws IOException {
            gzipOutputStream.write(b);
        }

        @Override
        public void write(byte[] b, int off, int len) throws IOException {
            gzipOutputStream.write(b, off, len);
        }

        @Override
        public void flush()

 throws IOException {
            gzipOutputStream.flush();
        }

        @Override
        public void close() throws IOException {
            gzipOutputStream.close();
        }
    }
}

위의 방법들을 통해 JSP 애플리케이션의 성능을 최적화할 수 있습니다. 캐싱, 데이터베이스 연결 최적화, JSP 페이지 최적화, 정적 콘텐츠 분리, 서블릿과 JSP의 역할 분리, 그리고 HTTP 응답 압축은 성능을 크게 향상시킬 수 있는 중요한 기법들입니다.

Leave a Reply

Your email address will not be published. Required fields are marked *