본문 바로가기

면접 질문지 소스

면접질문: Class.forName() 동작과 사용 이유에 대해서 말해주세요

728x90

필요한 사전 지식

 

1. 동적로딩

- Java는 동적로딩을 지원하기 때문에 실행 시에 모든 클래스가 로딩되지 않고, 필요한 시점에 클래스를 로딩할 수 있습니다. 동적로딩은 (a)로드타임 동적로딩, (b) 런타임 동적로딩이 있습니다.

 

(a) 로드타임 동적로딩

- 하나의 클래스를 로딩하는 과정에서 필요한 다른 클래스들을 동적으로 로딩합니다.

class Main{
	public static void main(String[] args){
    	System.out.println("Hello World");
    }
}

- Main.class가 JVM내로 로딩되면서 필요한 System, String 관련 .class들도 미리 JVM에 로딩됩니다.

- 관련 .class를 로딩하지 못한다면 Main.class를 로딩하지 못합니다.

 

(b) 런타임 동적로딩

- 코드를 실행하는 순간 필요한 클래스를 로딩하는 것입니다.

- JVM이 실제로 .class를 실행할 때 코드를 발견하면 관련 .class 파일을 로딩합니다.

try{
		Class.forName("oracle.jdbc.driver.OracleDriver"); 
	}catch (ClassNotFoundException e){
		//에러처리하는 코드 
	}
	Connection conn=null;
	Statement stmt=null;
	ResultSet rs=null;
	
	try{
		conn=DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:xe","jsp","oracle");
		stmt=conn.createStatement(); //쿼리 수행
		rs=stmt.executeQuery("SELECT 1 FROM DUAL");
		if(rs.next())  System.out.print(rs.getInt(1));
		
	}catch (SQLException e){
		//에러처리하는 코드 
	}finally {
		if(rs!=null){try{rs.close();} catch(Exception e){} }
		if(stmt!=null){try{stmt.close();} catch(Exception e){} }
		if(conn!=null){try{conn.close();} catch(Exception e){} }
	}

 

자바에서 DB연결까지

- JAVA에서 JDBC API를 이용해 JDBC Driver를 사용하려면 해당 드라이버가 로드되어야 합니다.

- Class.forName("oracle.jdbc.driver.OracleDriver")은 ' 이 코드를 만나면 OracleDriver 로드하고 실행해' 라는 의미가 됩니다.

- 로드만 했을 뿐 변수를 선언해 oracle 드라이브 객체를 받지도 않았는데 어떻게 바로 conn = DriverManager.getConnection()을 써서 DB에 연결할 수 있었을까요?

- 정답은 바로 Driver 클래스의 static 구문에 있습니다.

// 
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    static {
        try {
           java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
    }
    
    그외 기타 기능
}
static 
    {
        defaultDriver = null;
        Timestamp timestamp = Timestamp.valueOf("2000-01-01 00:00:00.0");
        try
        {
            if(defaultDriver == null)
            {
                defaultDriver = new OracleDriver();
                DriverManager.registerDriver(defaultDriver);
            }
        }
        catch(RuntimeException runtimeexception) { }
        catch(SQLException sqlexception) { }
    }

 

- 로드될 때 Driver를 DriverManager라는 곳에 등록하기 때문에 바로 DB에 연결하는 

Connection conn = DriverManager.getConnection("url","id","pw"); 구문을 사용해 DB에 연결할 수 있습니다.

 

과정 정리

- Class.forName()을 통해 실행도중 오라클 드라이브를 로드

- 로드되면서 OracleDriver에 static{} 구문을 실행하여 DriverManager에 OracleDriver를 등록

- DriverManager.getConnection()을 통해 DB에 연결

- 이후로 쿼리 진행

 

Class.forName()사용 이유

 

질문 : static{} 구문이 로딩될때 사용되는 거라면, OracleDriver driver = new OracleDriver() 로드타임 동적로딩하여 DriverManager에 등록하여 연결해도 되지 않나?

 

OracleDriver oracleDriver=new OracleDriver();
	Connection conn=null;
	Statement stmt=null;
	ResultSet rs=null;
	
	try{
		conn=DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:xe","jsp","oracle");
		stmt=conn.createStatement(); //쿼리 수행
		rs=stmt.executeQuery("SELECT 1 FROM DUAL");
		if(rs.next())  System.out.print(rs.getInt(1));
		
	}catch (SQLException e){
		//에러처리하는 코드 
	}finally {
		if(rs!=null){try{rs.close();} catch(Exception e){} }
		if(stmt!=null){try{stmt.close();} catch(Exception e){} }
		if(conn!=null){try{conn.close();} catch(Exception e){} }
    }

 

- 위의 코드에서 oracleDriver 객체는 사용되지 않습니다. 즉 쓸데없이 객체 1개를 생성하였습니다.

- Class.forName()의 매개변수에 문자열값을 직접 입력하는 것이 아니라 조건에 따라 oracle, mysql일 것입니다.

 

String dirverName=request.getParameter("driverName");
	String connectionInfo="";
	if(dirverName.equals("oracle.jdbc.driver.OracleDriver")){
		connectionInfo="jdbc:oracle:thin:@127.0.0.1:1521:xe";
	}else{
		//오라클 말고 기타 DB Driver
	}
	
	
	try{
		Class.forName(dirverName);
	}catch (ClassNotFoundException e){
		//에러처리하는 코드 
	} 
	Connection conn=null;
	Statement stmt=null;
	ResultSet rs=null;
	
	try{
		conn=DriverManager.getConnection(connectionInfo,"jsp","oracle");
		stmt=conn.createStatement(); //쿼리 수행
		rs=stmt.executeQuery("SELECT 1 FROM DUAL");
		if(rs.next())  System.out.print(rs.getInt(1));
		
	}catch (SQLException e){
		//에러처리하는 코드 
	}finally {
		if(rs!=null){try{rs.close();} catch(Exception e){} }
		if(stmt!=null){try{stmt.close();} catch(Exception e){} }
		if(conn!=null){try{conn.close();} catch(Exception e){} }
	}

 

- Class.forName()을 안쓰게 되면 OracleDriver를 포함한 기타 DB Driver를 전부 로드해야 합니다.

- 로드타임으로 하게 된다면 어떤 driver를 사용할지 모르므로 모든 Driver를 로드하게 됩니다.

- 하지만 Class.forName()을 사용한다면 실행도중 한가지 Driver만 로드하게 됩니다.

 

결론 Class.forName()을 사용하게 된다면

- Driver의 경우 로드만 하고, 객체 생성을 안해도 됩니다.

- 특정 조건에 따라 Driver 로드를 다르게 할때 쓸데없이 모든 Driver를 로드할 필요가 없습니다.

- 로드되는 시점이 컴파일이 아닌 런타임이기 때문에 static{} 구문에 실행시점을 조절할 수 있습니다.