본문 바로가기

programming/Gukbi

국비 교육 75일차 - spring (Container, DI, DB연동)

728x90
반응형

본격적인 spring 수업이 시작됐다. 어제는 스프링 설치까지만 완료하고 별다른걸 배우지 않았는데, 오늘은 본격적으로 객체 생성방법, 변수 값 설정에 대해 배웠다. 

 

우선 프레임워크란 애플리케이션을 개발할때 애플리케이션의 구조를 결정하는 아키텍쳐를 제공하는 프로그램을 말한다. 기존 골격은 만들어져 있기 때문에, 그 뼈대에 살을 붙이는 작업을 개발자가 수행하게 된다. 

 

스프링의 경우 4가지의 특징이 있다. 

1) 경량 - 스프링은 여러개의 모듈로 구성되어 있고, 각 모듈은 하나 이상의 jar 파일로 구성되어 있다. 이 jar 파일만 있으면 개발과 실행이 모두 가능해지기 때문에, 애플리케이션의 배포가 빠르고 쉬워진다. 

 

2) 느슨한 (낮은) 결합성 - 객체생성을 자바코드로 직접 처리하는 것이 아니라 컨테이너가 대신 처리한다. 또, 객체와 객체 사이의 의존관계 또한 컨테이너가 처리한다. 이는 곧 낮은 결합도를 의미한다. 

 

3) AOP(Aspect Oriented Programming) - 메소드에 반복해서 등장하는 공통로직을 분리할 수 있기 때문에, 응집도가 높은 개발이 가능하다. (유지보수가 용이해진다)

 

4) 컨테이너 - 특정객체의 생성과 관리 담당, 객체 운용에 필요한 다양한 기능을 제공한다. 

 

 

 

스프링 컨테이너

 

 스프링에서 컨테이너가 어떻게 작동하고 있는지 알아보는 코드

 

 

일단 파일 구성은 이렇게 되어 있다. 

 

<?xml version="1.0" encoding="UTF-8"?>
<beans>
	<bean id="sa" class="com.sist.spring.Sawon"/>
</beans>

 app.xml 파일

beans 내장객체를 이용해서 객체 아이디와 클래스 정보를 담아준다. 

 

package com.sist.spring;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import java.util.*;

public class XMLParser extends DefaultHandler {
	Map clsMap = new HashMap();

	@Override
	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
		try
		{
			if(qName.equals("bean"))
			{
				String id=attributes.getValue("id");
				String cls=attributes.getValue("class");
				Class clsName=Class.forName(cls);
				Object obj=clsName.getDeclaredConstructor().newInstance();
				clsMap.put(id, obj);
			}
		}catch(Exception ex) {}
	
	}
	
}

 XMLParser 파일

 

bean객체에 저장되어 있는 id, class 값을 읽어와서 Class를 생성해준다. 그리고 아이디를 키(key)로, 생성된 객체를 값(value)에 Map형식으로 저장해준다. 

 

package com.sist.spring;
import java.util.*;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import java.io.*;
// DL => id로 찾는것 getBean에서 찾는다
public class ApplicationContext {
	private Map clsMap=new HashMap();
	public ApplicationContext(String path)
	{
		try
		{
			// 생성과정
			SAXParserFactory spf=SAXParserFactory.newInstance();
			SAXParser sp=spf.newSAXParser();
			XMLParser xp=new XMLParser();
			// 파일 경로 적어줌
			sp.parse(new File(path), xp);
			clsMap=xp.clsMap;
		} catch (Exception e) {
			
		}
	}
	public Object getBean(String id)
	{
		return clsMap.get(id);
	}
}

 ApplicationContext 파일

 

클래스 경로에 있는 XML 파일을 로딩해서 구동을 해준다. 그래서 파일이 저장된 경로값(path)가 꼭 필요하다. 

 

컨테이너 등록은 완료되었음으로, 사용자가 사용할 객체와 메소들을 만들어준다. 

 

package com.sist.spring;

public class Sawon {
	private String name;
	private String sex;
	private String addr;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public String getAddr() {
		return addr;
	}
	public void setAddr(String addr) {
		this.addr = addr;
	}
	
	public void print()
	{
		System.out.println("이름:"+name);
		System.out.println("성별:"+sex);
		System.out.println("주소:"+addr);
		
	}
}

 변수를 설정하고, getter setter method를 만든다. print메소드까지 만들어주고 이를 MainClass에서 실행한다. 

 

package com.sist.spring;

public class MainClass {

	public static void main(String[] args) {
		String path="C:\\Users\\user\\Documents\\workspace-sts-3.8.4.RELEASE\\SpringContainerProject\\src\\main\\java\\com\\sist\\spring\\app.xml";
		ApplicationContext app=
				new ApplicationContext(path);
		Sawon s=(Sawon)app.getBean("sa");
		s.setName("홍길동");
		s.setSex("남자");
		s.setAddr("서울");
		s.print();
	}

}

 

만들어둔 xml파일의 경로를 읽어와서 저장하고, 객체를 생성한다. setter메소드를 통해 값을 설정하고 print()메소드를 돌려보면 값이 출력된다. 

 

  

 

이렇게 구동하는게 스프링 컨테이너의 기본 구조라고 생각하면 된다. 실제로 이렇게 쓰는 것은 아니고, 흐름을 이해하기 위해 써본 코드이다. 

 

 

/*
 * 	메모리 할당
 * 	@Component : 일반 클래스 
 * 	@Repository : DAO
 * 	@Service : DAO+DAO (BI)
 * 	@Controller : Model (return 경로/파일) 
 * 	@RestController : Model (return 문자열) =>Ajax, Json, XML
 * 	@Bean 
 */

 

 메모리 할당 방법 

 

 

xml 파일에서 객체를 생성하고 값을 할당하는 방법

 

package com.sist.main;
/*
 * 	1) XML ===> DI
 * 	2) Annotation ===> DI(X)
 * 	3) Java ===> DI
 * 	========================
 * 	DI (스프링을 통해서 필요한 데이터를 주입)
 * 	= setter(2)
 * 	= 생성자 (1)
 * 
 * 	<bean id="sa" class="com.sist.main.Sawon"/>
 */
public class Sawon {
	private String name;
	private String sex;
	private String addr;
	public Sawon()
	{
		
	}
	public void setName(String name) {
		this.name = name;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public void setAddr(String addr) {
		this.addr = addr;
	}
	
	// 생성과 동시에 값을 채워줌
	public Sawon(String name, String sex, String addr) {
		
		this.name = name;
		this.sex = sex;
		this.addr = addr;
	}
	
	public void print()
	{
		System.out.println("이름:"+name);
		System.out.println("성별:"+sex);
		System.out.println("주소:"+addr);
	}
	
}

 

 데이터를 주입하는 방법에는 두가지가 있다. 

1) 생성자를 이용하는 방법

2) setter를 이용하는 방법

 

<?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"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	<!-- Setter -->
	<bean id="sa1" class="com.sist.main.Sawon"><!-- Class.forName("com.sist.main.Sawon") -->
		<property name="name" value="이제노"/><!-- sa.setName("홍길동") -->
		<property name="sex" value="왕자"/>
		<property name="addr" value="일산"/>
	</bean>
	<bean id="sa2" class="com.sist.main.Sawon"
		p:name="황런쥔"
		p:sex="공주"
		p:addr="길림"			
	/>
	<!-- 생성자 주입 
		Sawon(String name, String sex, String addr)
	-->
	<bean id="sa3" class="com.sist.main.Sawon">
		<constructor-arg value="종천러 " index="0"/><!-- index는 생략이 가능 -->
		<constructor-arg value="부자 " index="1"/>
		<constructor-arg value="상해 " index="2"/>
	</bean>
	<bean id="sa4" class="com.sist.main.Sawon"
		c:name="박지성"
		c:sex="햄스터"
		c:addr="서울"
	/>
	<bean id="sa5" class="com.sist.main.Sawon"
		c:_0="이동혁"
		c:_1="해찬"
		c:_2="제주"
	/>
	<!-- 객체를 5개 생성했기 때문에 각각 다름 -->
</beans>

 보통은 4번이 가장 쓰기 편해서 저렇게 사용한다고 하는데, 개발자마다 각자 다른 방법을 사용한다고 하니 전부 알아두고 있는 것이 중요할 것 같다. 

 

 

객체를 각각 생성해줬기 때문에 주소값이 다 다른 것을 확인할 수 있다. 

 

 

다음은 db를 연동하는 방법이다. 

스프링은 xml 파일로 제어가 되기 때문에 모든 정보를 xml 파일에 등록해주어야 한다. 

db연동을 위해서 필요한 정보들을 등록한다. 

<?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:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	<!-- 오라클 정보 설정 -->
	<bean id="ds" class="org.apache.commons.dbcp.BasicDataSource"
		p:driverClassName="oracle.jdbc.driver.OracleDriver"
		p:url="jdbc:oracle:thin:@localhost:1521:XE"
		p:username="hr"
		p:password="happy"
	/>
	<!-- myBatis Connection -->
	<bean id="ssf" class="org.mybatis.spring.SqlSessionFactoryBean"
		p:dataSource-ref="ds"
	/>
	<!-- interface 구현 -->
	<bean id="mapper" class="org.mybatis.spring.mapper.MapperFactoryBean"
		p:sqlSessionFactory-ref="ssf"
		p:mapperInterface="com.sist.main.EmpMapper"
	/>
	<!-- DAO에 전송  -->
	<bean id="dao" class="com.sist.main.EmpDAO"
		p:mapper-ref="mapper"
	/>
</beans>

 mybatis와 mapper 정보까지 등록을 하고, dao에 전송하는 코드를 적어준다. 

 

package com.sist.main;

import org.apache.ibatis.annotations.Select;
import java.util.*;
public interface EmpMapper {
	@Select("SELECT empno, ename, job, hiredate, sal FROM emp")
	public List<EmpVO> empListData();
}

 Mapper Interface

sql 문장을 적어주고, 데이터 반환형을 써준다. 

 

package com.sist.main;
import java.util.*;
public class EmpDAO {
	private EmpMapper mapper;

	public void setMapper(EmpMapper mapper) {
		this.mapper = mapper;
	}
	
	public List<EmpVO> empListData()
	{
		return mapper.empListData();
	}
}

 mapper 객체를 생성하고 List 데이터형으로 받아오는 empListData 메소드를 만들어 준다. 

 

package com.sist.main;
import java.util.*;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainClass {

	public static void main(String[] args) {
		ApplicationContext app=
				new ClassPathXmlApplicationContext("app.xml");
		EmpDAO dao=(EmpDAO)app.getBean("dao");
		List<EmpVO> list=dao.empListData();
		for(EmpVO vo:list)
		{
			System.out.println(vo.getEmpno()+" "
					+vo.getEname()+" "
					+vo.getJob()+" "
					+vo.getHiredate().toString()+" "
					+vo.getSal()
					);
			
		}

	}

}

 그리고 MainClass에서 실행해주는 코드를 위와 같이 작성한다. 

 

실행결과는 늘 보던 그 테이블의 결과가 맞다. 잘 가져왔다는 소리다. 

앞으로 이런식으로 mapper를 생성해서 그 안에서 sql문장을 써주고 dao에서 값을 받아와 main에서 실행하는 방식으로 예제들을 연습해볼 것 같다. 

 

 

일단 여기까지 정리해보니 다시 복습해야할 부분들이 머리속에 들어온다. 

1. 생성자

2. 어노테이션

3. 인터페이스

 

이 3가지 개념을 다시 정리해둬야겠다. 말만할게 아니라 이 다음 포스팅에 다시 정리해서 올리도록 하겠다. 

꼭 이렇게 적어둬야 공부를 하기 때문에 공개로 적어둔다...

728x90
반응형