자바 스프링 프레임워크(renew ver.) - 신입 프로그래머를 위한 강좌
스프링 컨테이너, 빈(Bean) 객체 생명주기
스프링 컨테이너 초기화 : 빈(Bean) 객체 생성 및 주입
스프링 컨테이너 종료 : 빈(Bean) 객체 소멸
→ 빈 객체의 생명주기는 스프링 컨테이너의 생명주기와 같이 한다.
//스프링 컨테이너 생성(초기화)
GenericXmlApplicationContext ctx =
new GenericXmlApplicationContext("classpath:appCtx.xml");
// 더미 도서 목록 등록
BookRegisterService bookRegisterService =
ctx.getBean("bookRegisterService", BookRegisterService.class);
// 더미 도서 목록 출력
BookSearchService bookSearchService =
ctx.getBean("bookSearchService", BookSearchService.class);
// 더미 회원 목록 등록
MemberRegisterService memberRegisterService =
ctx.getBean("memberRegisterService", MemberRegisterService.class);
// 더미 회원 목록 출력
MemberSearchService memberSearchService =
ctx.getBean("memberSearchService", MemberSearchService.class);
ctx.close(); // 스프링 컨테이너 종료
스프링에서 제공하는 인터페이스(InitializingBean/DisposableBean)
를 구현하여 빈 객체 생성/소멸 시 실행할 작업을 작성할 수 있다.
빈 객체 생성/소멸 시 실행할 작업 지정 방법
1) 스프링에서 제공하는 인터페이스(InitializingBean/DisposableBean)
를 구현
2) init-method, destroy-method 속성 사용
public class BookDao implements InitializingBean, DisposableBean {
// 기타 요소 생략
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("빈(Bean)객체 생성 단계");
}
@Override
public void destroy() throws Exception {
System.out.println("빈(Bean)객체 소멸 단계");
}
}
스프링에서 제공하는 인터페이스를 구현하여 사용한다.
설정파일에서 빈(Bean) 객체를 작성할 때 init-method
, destroy-method
속성을 사용한 후 해당 객체의 클래스파일에서 메서드를 작성한다.
<bean id="bookRegisterService" class="com.brms.book.service.BookRegisterService"
init-method="initMethod" destroy-method="destroyMethod"/>
<bean id="bookSearchService" class="com.brms.book.service.BookSearchService" />
public class BookRegisterService {
@Autowired
private BookDao bookDao;
public BookRegisterService() { }
public void register(Book book) {
bookDao.insert(book);
}
public void initMethod() {
System.out.println("BookRegisterService 빈(Bean)객체 생성 단계");
}
public void destroyMethod() {
System.out.println("BookRegisterService 빈(Bean)객체 소멸 단계");
}
}
속성파일에 만든 메서드의 이름과 객체의 클래스파일에 만든 메서드의 이름이 같아야 한다.
스프링 빈(Bean)을 만드는 작업을 XML파일이 아닌 Java파일에서 어노테이션을 이용해 적용하는 방법을 알아본다.
@Configuration
: 해당 파일이 설정파일임을 스프링에 알려주는 어노테이션<?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="studentDao" class="ems.member.dao.StudentDao" ></bean>
<bean id="registerService" class="ems.member.service.StudentRegisterService">
<constructor-arg ref="studentDao" ></constructor-arg>
</bean>
<bean id="modifyService" class="ems.member.service.StudentModifyService">
<constructor-arg ref="studentDao" ></constructor-arg>
</bean>
<bean id="deleteService" class="ems.member.service.StudentDeleteService">
<constructor-arg ref="studentDao" ></constructor-arg>
</bean>
<bean id="selectService" class="ems.member.service.StudentSelectService">
<constructor-arg ref="studentDao" ></constructor-arg>
</bean>
<bean id="allSelectService" class="ems.member.service.StudentAllSelectService">
<constructor-arg ref="studentDao" ></constructor-arg>
</bean>
<bean id="dataBaseConnectionInfoDev" class="ems.member.DataBaseConnectionInfo">
<property name="jdbcUrl" value="jdbc:oracle:thin:@localhost:1521:xe" />
<property name="userId" value="scott" />
<property name="userPw" value="tiger" />
</bean>
<bean id="dataBaseConnectionInfoReal" class="ems.member.DataBaseConnectionInfo">
<property name="jdbcUrl" value="jdbc:oracle:thin:@192.168.0.1:1521:xe" />
<property name="userId" value="masterid" />
<property name="userPw" value="masterpw" />
</bean>
<bean id="informationService" class="ems.member.service.EMSInformationService">
<property name="info">
<value>Education Management System program was developed in 2015.</value>
</property>
<property name="copyRight">
<value>COPYRIGHT(C) 2015 EMS CO., LTD. ALL RIGHT RESERVED. CONTACT MASTER FOR MORE INFORMATION.</value>
</property>
<property name="ver">
<value>The version is 1.0</value>
</property>
<property name="sYear">
<value>2015</value>
</property>
<property name="sMonth">
<value>1</value>
</property>
<property name="sDay">
<value>1</value>
</property>
<property name="eYear" value="2015" />
<property name="eMonth" value="2" />
<property name="eDay" value="28" />
<property name="developers">
<list>
<value>Cheney.</value>
<value>Eloy.</value>
<value>Jasper.</value>
<value>Dillon.</value>
<value>Kian.</value>
</list>
</property>
<property name="administrators">
<map>
<entry>
<key>
<value>Cheney</value>
</key>
<value>cheney@springPjt.org</value>
</entry>
<entry>
<key>
<value>Jasper</value>
</key>
<value>jasper@springPjt.org</value>
</entry>
</map>
</property>
<property name="dbInfos">
<map>
<entry>
<key>
<value>dev</value>
</key>
<ref bean="dataBaseConnectionInfoDev"/>
</entry>
<entry>
<key>
<value>real</value>
</key>
<ref bean="dataBaseConnectionInfoReal"/>
</entry>
</map>
</property>
</bean>
</beans>
위의 XML설정파일을 아래 Java파일로 변환.
@Configuration
public class MemberConfig {
// <bean id="studentDao" class="ems.member.dao.StudentDao" />
@Bean
public StudentDao studentDao(){
return new StudentDao();
}
/*
<bean id="registerService" class="ems.member.service.StudentRegisterService">
<constructor-arg ref="studentDao" ></constructor-arg>
</bean> */
@Bean
public StudentRegisterService registerService(){
return new StudentRegisterService(studentDao());
}
@Bean
public StudentModifyService modifyService(){
return new StudentModifyService(studentDao());
}
@Bean
public StudentDeleteService deleteService(){
return new StudentDeleteService(studentDao());
}
@Bean
public StudentSelectService selectService(){
return new StudentSelectService(studentDao());
}
@Bean
public StudentAllSelectService allSelectService(){
return new StudentAllSelectService(studentDao());
}
@Bean
public DataBaseConnectionInfo dataBaseConnectionInfoDev(){
DataBaseConnectionInfo infoDev = new DataBaseConnectionInfo();
infoDev.setJdbcUrl("jdbc:oracle:thin:@localhost:1521:xe");
infoDev.setUserId("scott");
infoDev.setUserPw("tiger");
return infoDev;
}
@Bean
public DataBaseConnectionInfo dataBaseConnectionInfoReal(){
DataBaseConnectionInfo infoReal = new DataBaseConnectionInfo();
infoReal.setJdbcUrl("jdbc:oracle:thin:@192.168.0.1:1521:xe");
infoReal.setUserId("masterid");
infoReal.setUserPw("masterpw");
return infoReal;
}
@Bean
public EMSInformationService informationService(){
EMSInformationService info = new EMSInformationService();
info.setInfo("Education Management System program was developed in 2015.");
info.setCopyRight("COPYRIGHT(C) 2015 EMS CO., LTD. ALL RIGHT RESERVED. CONTACT MASTER FOR MORE INFORMATION.");
info.setVer("The version is 1.0");
info.setsYear(2015);
info.setsMonth(1);
info.setsDay(1);
info.seteYear(2015);
info.seteMonth(2);
info.seteDay(28);
ArrayList<String> developers = new ArrayList<>();
developers.add("Cheney");
developers.add("Eloy");
developers.add("Jasper");
developers.add("Dillon");
developers.add("Kian");
info.setDevelopers(developers);
Map<String, String> administrators = new HashMap<String, String>();
administrators.put("Cheney", "cheney@springPjt.org");
administrators.put("Jasper", "jasper@springPjt.org");
info.setAdministrators(administrators);
Map<String, DataBaseConnectionInfo> dbInfos = new HashMap<String, DataBaseConnectionInfo>();
dbInfos.put("dev", dataBaseConnectionInfoDev());
dbInfos.put("real", dataBaseConnectionInfoReal());
info.setDbInfos(dbInfos);
return info;
}
}
// GenericXmlApplicationContext ctx = new GenericXmlApplicationContext("classpath:applicationContext.xml");
AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext(MemberConfig.class);
설정파일이 지나치게 길어지다보면 유지보수 측면에서 불리할 수 있다.
이럴때 설정파일을 여러개로 나누어 작성한다.
→ 보통은 기능별로 나눈다.
예) DB connection을 담당하는 DAO, service, 기타 유틸들
@Autowired
를 이용해 설정파일2에서 A객체를 자동주입하여 사용할 수 있다는 뜻.AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext(MemberConfig1.class, MemberConfig2.class, MemberConfig3.class);
→ 위와 같이 배열형식으로 설정파일을 지정하면 된다.
@Import
@Import
어노테이션을 통해 여러개의 파일을 하나의 파일처럼 사용할 수 있다.
@Configuration
@Import({MemberConfig2.class, MemberConfig3.class})
public class MemberConfigImport
웹 프로그래밍은 보통 Model1, Model2로 구분한다.
장점 : html내에 자바코드를 직접 넣어 개발하므로 개발속도가 빠르다.
단점 : 유지보수 및 코드 가시성이 낮음
Model1의 단점을 해결하기 위해 모듈화를 통한 계층분리를 적용했다.
MVC구조라고 부른다.
요즘 대부분의 웹 프로그램은 Model2를 기본으로 한다.
장점 : 기능이 분리되어 있기 때문에 유지보수에 유리하다.
단점 : 구조가 복잡해질 수 있다.
HandlerMapping → DispatcherServlet → HandlerAdapter → DispatcherServlet → ViewResolver → DispatcherServlet → View
- HandlerMapping : 요청에 따른 알맞은 controller로 요청한다.
- HandlerAdapter : controller의 많은 메서드 중 요청에 가장 알맞은 메서드에 요청을 넣고, model로 요청에 대한 응답을 받는다.
- ViewResolver : 응답에 가장 적합한 view문서를 찾는다.
- View : 데이터를 화면에 표시한다.
DispatcherServlet
는 spring framework에서 제공되는 객체이다.DispatcherServlet
를 거치게 된다.DispatcherServlet의 동작방식에 대한 자세한 내용은 아래 참고자료의 1번 링크를 참고하자.
web.xml애서의 설정
스프링 MVC를 실행하려면 DispatcherServlet
를 설정해야 하는데 이 설정은 web.xml에서 해주어야 한다.
이후 controller와 view부분은 개발자가, 나머지는 spring에서 자동으로 처리한다.
실제로 서비스할때는 웹 서버를 따로 만들고 그 안에 웹컨테이너로 Tomcat을 이용하곤 한다.
톰캣 설치 및 IDE 연동방법은 알고있으므로 생략.
순수 Java를 사용할때 new
키워드로 새로운 객체를 생성하는것과 달리 Spring을 사용하면 어노테이션을 이용해 객체를 생성 및 주입하여 사용한다.
1) Service 객체 등록
방법 1.
MemberService service = new MemberService();
방법 2.
<beans:bean id="service" class="com.bs.lec17.member.service.MemberService"></beans:bean>
@Autowired
MemberService service;
방법 3.
@Service
public class MemberService implements IMemberService { }
@Autowired
MemberService service;
보통은 3번 방법을 많이 사용한다.
2) Dao 객체 등록
@Component
혹은 @Repository
어노테이션을 이용하여 빈 등록을 한 후 생성자 주입 등을 사용해 service에서 객체를 주입해 사용한다.
@Repository
public class MemberDao implements IMemberDao { }
@Autowired
MemberDao dao;
예전에는 @RequestMapping
어노테이션을 사용했지만 요즘은 거의 @GetMappring
, @PostMapping
등의 RESTapi 기반의 어노테이션을 사용한다.
공통 url은 컨트롤러 클래스에 @RequestMapping
어노테이션을 이용해 지정해두면 중복작업을 생략할 수 있다.
보통은 커맨드 객체(entity, dto class)를 생성하여 프론트로부터 값을 받아오는 방법을 사용한다.
@Controller
@RequestMapping("/member")
public class MemberController {
// 생략
@PostMapping("/memJoin")
public String memJoin(Member member)
// 서비스 단 작업
return "memJoinOk";
}
ID : ${member.memId}
PW : ${member.memPw}
웹 서비스는 HTTP 프로토콜을 기반으로 한다.
HTTP 프로토콜은 클라이언트와 서버의 관계를 유지하지 않는 특징Connectionless
이 있다.
관계를 유지하지 않으면 고객이 앞선 요청에서 넘긴 데이터를 확인할 수 없으므로 이러한 단점을 해결하기 위해 세션과 쿠키를 사용한다.
세션과 쿠키 모두 클라이언트와 서버의 연결을 유지하기 위해 사용한다.
서버에서 연결정보를 관리한다.
public String memLogin(Member member, HttpServletRequest request) {
Member mem = service.memberSearch(member);
HttpSession session = request.getSession();
session.setAttribute("member", mem);
// 생략
}
public String memLogin(Member member, HttpSession session) {
Member mem = service.memberSearch(member);
session.setAttribute("member", mem);
// 생략
}
@RequestMapping("/logout")
public String memLogout(Member member, HttpServletRequest request)
// 생략
HttpSession session = request.getSession();
session.invalidate(); // 세션삭제
return "/member/logoutOk";
}
@RequestMapping("/logout")
public String memLogout(Member member, HttpSession session)
// 생략
session.invalidate(); // 세션삭제
return "/member/logoutOk";
}
HttpServletRequest
와 HttpSession
의 차이는 거의 없으며 세션객체를 얻는 방법에 약간의 차이가 있다.
HttpServletRequest
파라미터로 HttpServletRequest를 받은 후 getSession()으로 세션을 얻음.
HttpSession
파라미터로 HttpSession을 받아 세션 사용.
클라이언트에서 연결정보를 관리한다.
@RequestMapping("/main")
public String mallMain(Mall mall, HttpServletResponse response){
Cookie genderCookie= new Cookie("gender", mall.getGender());
if(mall.isCookieDel()) {
genderCookie.setMaxAge(0); // 쿠키 삭제(유지시간 0 처리)
mall.setGender(null);
} else {
genderCookie.setMaxAge(60*60*24*30); // 쿠키 유지시간 설정
}
response.addCookie(genderCookie);
return "/mall/main";
}
@RequestMapping("/index")
public String mallIndex(Mall mall, @CookieValue(value="gender", required=false) Cookie genderCookie, HttpServletRequest request) {
if(genderCookie != null)
mall.setGender(genderCookie.getValue());
return "/mall/index";
}
@CookieValue
의 value
에 명시한 쿠키가 없을 경우 예외가 발생한다.
required=false
설정 시(기본: true) 명시한 쿠키가 없어도 예외가 발생하지 않는다.
파라미터로 값을 받아올때와 같은 원리라고 생각하면 된다.
작성중...