열심히 끝까지
디바이스 융합 자바(Java) day65(2) - 스프링(@(어노테이션),컴포넌트(@Component),@Repository,@Service) 본문
디바이스 융합 자바(Java) day65(2) - 스프링(@(어노테이션),컴포넌트(@Component),@Repository,@Service)
노유림 2022. 9. 14. 18:16> xml에게는 치명적인 단점 존재
-> 너무 복잡함
>> 어떤 객체와 어떤 객체가 의존관계를 갖는다는 사실을 xml 보고는 쉽게 파악하기 힘듦
> 하나의 클래스 내부에 여러 개의 객체 멤버 변수 존재
: 이름 명확하게 존재하지 않을 수 있고 bean(등록된 객체)의 수가 엄청 많을 수도 있음
: xml 길이 늘어나고, 누가 누구랑 의존관계인지 파악하기 힘들어짐
>> 그래서 유명한 책, 혹은 괜찮은 강의에서는 "xml은 설정이 과도하다." 라고도 언급
>> 개발자들은, Java 코드와 함께 의존관계를 파악하는 것을 선호
: 그러니 "JAVA 코드에 xml 설정"을 추가해보자!!
하고 나온 것이 어노테이션(@)
※ 어노테이션 사용 방법
1 ) context를 namespace에 추가
[ xmlns:context="http://www.springframework.org/schema/context" ] 코드 상단에 달기
2 ) 컴포넌트 스캔 설정
어노테이션을 컨테이너가 사전에 스캔할 예정
>> 스캔 범위를 지정해주어야 함
@Component : 해당 클래스를 객체화해라!
3 ) <bean> 등록없이 자동으로 객체 생성 가능
new VO();
== <bean id="vo" class="xxx.VO" />
== @Component("vo")
: vo라는 이름을 등록해줌
// Component로 인해 new 하지 않아도 Galaxy Lookup 가능!
4 ) 의존성 주입(DI)
@Autowired 사용
: 멤버변수 뿐만 아니라 메서드, 생성자에서도 사용 가능
> 거의 멤버변수에서 사용
: 해당 멤버변수의 타입을 체크
: 메모리를 확인해서 같은 타입을 주입함
>> 이름이 없어도 사용이 가능하다??
: 멤버변수의 "타입"을 체크하기 때문에
>> 타입을 체크하기 때문에 들어갈 수 있음
@Qualifier("applewatch")
: 이름으로 지정(보조 @(어노테이션))
: 보조 역할
=> @Autowired의 대상이 @Component로 되어있는 것이
때로는 불리할 때도 있음...
===>> .xml 설정과 @(어노테이션) 설정을 함께 사용해보면 어떨까?
1. 아이폰 @으로 객체 생성
2. lookup
3. aw <-> gw
---------------디바이스 융합 자바(Java) day65(1) 참고 어노테이션만 썼을 경우-----------
---------applicationContext.xml
<?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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<!-- 필수 속성으로 base-package 존재
여기서 package지정 가능 -->
<context:component-scan base-package="test"></context:component-scan>
</beans>
---------IPhone.java
package test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component("ip")
public class IPhone implements Phone{
@Autowired
@Qualifier("aw")
private Watch watch;
// 애플워치로 소리를 업,다운 한다고 가정
private int battery;
public IPhone() {
System.out.println("아이폰 객체생성완료");
}
public Watch getWatch() {
return watch;
}
public void setWatch(Watch watch) {
System.out.println("아이폰setter호출 됨-watch");
this.watch=watch;
}
public int getBattery() {
return battery;
}
public void setBattery(int battery) {
System.out.println("아이폰setter호출 됨-battery");
this.battery=battery;
}
// DI : 생성자 인젝션
/*
public IPhone(Watch watch) {
// 미리 선언해주면 객체화 안해줘도 괜찮음
System.out.println("아이폰 객체 생성완료22");
this.watch=watch;
}
public IPhone(Watch watch, int battery) {
System.out.println("아이폰 객체 생성완료333");
this.battery=battery;
System.out.println("아이폰 전원 On : " + battery);
this.watch=watch;
}
*/
public void powerOn() {
System.out.println("아이폰 전원 ON");
}
public void powerOff() {
System.out.println("아이폰 전원 OFF");
}
public void volumeUp() {
// System.out.println("아이폰 소리++");
// watch = new AppleWatch();
// 객체화를 할 수 밖에 없음
// 이 것을 IoC 지원을 받아 처리해보기
watch.volumeUp();
}
public void volumeDown() {
// System.out.println("아이폰 소리--");
// watch = new AppleWatch();
// 객체화를 할 수 밖에 없음
watch.volumeDown();
}
}
---------AppleWatch.java
package test;
import org.springframework.stereotype.Component;
@Component("aw")
public class AppleWatch implements Watch {
public AppleWatch() {
System.out.println("애플워치 객체생성완료");
}
@Override
public void volumeUp() {
System.out.println("애플워치 ++");
}
@Override
public void volumeDown() {
System.out.println("애플워치 --");
}
}
---------Galaxy.java
package test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component("gp")
public class Galaxy implements Phone{
/*
public void initMethod() {
System.out.println("객체를 초기화하는 작업을 처리하는 메서드...");
// bean할 때 불러오는 것 가능
}
public void destroyMethod() {
System.out.println("객체 메모리를 해제할 때 호출하는 메서드...");
// bean할 때 불러오는 것 가능
}
*/
@Autowired
@Qualifier("gw") // 이름으로 찾을 수 있게 하는 보조 역할
private Watch watch;
private int battery;
public Galaxy(){
System.out.println("갤럭시 객체 On");
}
public Watch getWatch() {
return watch;
}
public void setWatch(Watch watch) {
System.out.println("갤럭시setter호출 됨-watch");
this.watch=watch;
}
public int getBattery() {
return battery;
}
public void setBattery(int battery) {
System.out.println("갤럭시setter호출 됨-battery");
this.battery=battery;
}
/*
public Galaxy(Watch watch, int battery) {
System.out.println("갤럭시 객체 + 배터리 생성");
this.battery=battery;
System.out.println("갤럭시 전원 On : " + battery);
this.watch = watch;
}
*/
// @Override 진행된 것
public void powerOn() {
System.out.println("갤럭시 전원 ON");
}
public void powerOff() {
System.out.println("갤럭시 전원 OFF");
}
public void volumeUp() {
// System.out.println("갤럭시 소리++");
watch.volumeUp();
}
public void volumeDown() {
// System.out.println("갤럭시 소리--");
watch.volumeDown();
}
}
---------GalaxyWatch.java
package test;
import org.springframework.stereotype.Component;
@Component("gw")
public class GalaxyWatch implements Watch {
public GalaxyWatch() {
System.out.println("갤럭시워치 객체생성완료");
}
@Override
public void volumeUp() {
System.out.println("갤럭시 워치 ++");
}
@Override
public void volumeDown() {
System.out.println("갤럭시 워치 --");
}
}
-----------------------------------어노테이션 및 .xml 설정을 같이 할 경우
---------applicationContext.xml
<?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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<!-- 필수 속성으로 base-package 존재
여기서 package지정 가능 -->
<context:component-scan base-package="test"></context:component-scan>
<bean id="gw" class="test.GalaxyWatch"/>
</beans>
---------IPhone.java
package test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component("ip")
public class IPhone implements Phone{
@Autowired
private Watch watch;
// 애플워치로 소리를 업,다운 한다고 가정
private int battery;
public IPhone() {
System.out.println("아이폰 객체생성완료");
}
public Watch getWatch() {
return watch;
}
public void setWatch(Watch watch) {
System.out.println("아이폰setter호출 됨-watch");
this.watch=watch;
}
public int getBattery() {
return battery;
}
public void setBattery(int battery) {
System.out.println("아이폰setter호출 됨-battery");
this.battery=battery;
}
// DI : 생성자 인젝션
/*
public IPhone(Watch watch) {
// 미리 선언해주면 객체화 안해줘도 괜찮음
System.out.println("아이폰 객체 생성완료22");
this.watch=watch;
}
public IPhone(Watch watch, int battery) {
System.out.println("아이폰 객체 생성완료333");
this.battery=battery;
System.out.println("아이폰 전원 On : " + battery);
this.watch=watch;
}
*/
public void powerOn() {
System.out.println("아이폰 전원 ON");
}
public void powerOff() {
System.out.println("아이폰 전원 OFF");
}
public void volumeUp() {
// System.out.println("아이폰 소리++");
// watch = new AppleWatch();
// 객체화를 할 수 밖에 없음
// 이 것을 IoC 지원을 받아 처리해보기
watch.volumeUp();
}
public void volumeDown() {
// System.out.println("아이폰 소리--");
// watch = new AppleWatch();
// 객체화를 할 수 밖에 없음
watch.volumeDown();
}
}
---------AppleWatch.java
package test;
public class AppleWatch implements Watch {
public AppleWatch() {
System.out.println("애플워치 객체생성완료");
}
@Override
public void volumeUp() {
System.out.println("애플워치 ++");
}
@Override
public void volumeDown() {
System.out.println("애플워치 --");
}
}
---------Galaxy.java
package test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component("gp")
public class Galaxy implements Phone{
/*
public void initMethod() {
System.out.println("객체를 초기화하는 작업을 처리하는 메서드...");
// bean할 때 불러오는 것 가능
}
public void destroyMethod() {
System.out.println("객체 메모리를 해제할 때 호출하는 메서드...");
// bean할 때 불러오는 것 가능
}
*/
@Autowired
private Watch watch;
private int battery;
public Galaxy(){
System.out.println("갤럭시 객체 On");
}
public Watch getWatch() {
return watch;
}
public void setWatch(Watch watch) {
System.out.println("갤럭시setter호출 됨-watch");
this.watch=watch;
}
public int getBattery() {
return battery;
}
public void setBattery(int battery) {
System.out.println("갤럭시setter호출 됨-battery");
this.battery=battery;
}
/*
public Galaxy(Watch watch, int battery) {
System.out.println("갤럭시 객체 + 배터리 생성");
this.battery=battery;
System.out.println("갤럭시 전원 On : " + battery);
this.watch = watch;
}
*/
// @Override 진행된 것
public void powerOn() {
System.out.println("갤럭시 전원 ON");
}
public void powerOff() {
System.out.println("갤럭시 전원 OFF");
}
public void volumeUp() {
// System.out.println("갤럭시 소리++");
watch.volumeUp();
}
public void volumeDown() {
// System.out.println("갤럭시 소리--");
watch.volumeDown();
}
}
---------GalaxyWatch.java
package test;
public class GalaxyWatch implements Watch {
public GalaxyWatch() {
System.out.println("갤럭시워치 객체생성완료");
}
@Override
public void volumeUp() {
System.out.println("갤럭시 워치 ++");
}
@Override
public void volumeDown() {
System.out.println("갤럭시 워치 --");
}
}
---------------Client.java
package test;
/*import java.util.List;
import java.util.Map;
import java.util.Set;*/
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
public class Client {
public static void main(String[] args) {
// Spring 컨테이너를 동작시킬 수 있도록 코드 작성
AbstractApplicationContext factory=new GenericXmlApplicationContext("applicationContext.xml");
System.out.println("로그 폰 호출 전");
Phone phone=(Phone)factory.getBean("gp");
// watch의 의존성 주입이 안되서 Galaxy의 watch는 돌아가지 않음
phone.powerOn();
phone.volumeUp();
phone.volumeDown();
phone.powerOff();
factory.close();
}
}
※ 컴포넌트(Component)
모듈화(하나의 로직을 한 공간에서 보고 싶어서 만들어진 개념)
ex ) JDBCUtil을 로직을 여러 곳에 사용
: 하나라도 바뀌면 나머지도 바꿔주어야함
> 유지보수 불리
- 메서드로 빼는 방법 : 일반적인 방법(모듈화 했어~ 라고 하면 메서드로 빼는 방법이 기본)
- Util(클래스)로 빼는 방법 : Util로 뺐어~ 라고 언급
ex ) Beans(JSP)
- beans, class, 컴포넌트 이 세가지는 같은 말이라고 해도 다름이 없음
: 클래스화된, 모듈화된 을 의미
>> @Component : 해당 클래스를 객체화해라. 라는 뜻
: 지정된 패키지 내부만 보게 되어있기 때문에
스캔 범위를 지정해주어야하는데
그것이 바로 위에 언급한 "컴포넌트 스캔 설정"
Impl > 실 구현체
@Component를 상속받은 어노테이션
↓
@Repository : DAO류에서 사용
>> 정신줄 놔도 DAO 라는 것이라고 인식 가능
@Service : DAO를 멤버변수로 가지는 서비스류
>> 저장 방법
com.ryo.biz.vo이름
>> 실무스타일 적용해볼 것
ex ) com.ryo.biz.board : BoardVO, BoardService
com.ryo.biz.board.impl : BoardDAO, BoardServiceImpl
com.ryo.biz.member : MemberVO, MemberService
com.ryo.biz.member.impl : MemberDAO, MemberServiceImpl
com.ryo.biz.common : JDBCUtil
test : Client
src/main/resource : applicationContext.xml
>> 이때, BoardServiceImpl는 BoardService를 상속하고
MemberServiceImpl는 MemberService를 상속
>> com.ryo.biz.board + com.ryo.biz.board.impl + com.ryo.biz.common 내용
-------------------------com.ryo.biz.board : BoardVO, BoardSerivice
package com.ryo.biz.board;
public class BoardVO {
private int bid;
private String title;
private String writer;
private String content;
private int cnt;
private String regdate;
public int getBid() {
return bid;
}
public void setBid(int bid) {
this.bid = bid;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getWriter() {
return writer;
}
public void setWriter(String writer) {
this.writer = writer;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public int getCnt() {
return cnt;
}
public void setCnt(int cnt) {
this.cnt = cnt;
}
public String getRegdate() {
return regdate;
}
public void setRegdate(String regdate) {
this.regdate = regdate;
}
@Override
public String toString() {
return "BoardVO [bid=" + bid + ", title=" + title + ", writer=" + writer + ", content=" + content + ", cnt="
+ cnt + ", regdate=" + regdate + "]";
}
}
package com.ryo.biz.board;
import java.util.List;
public interface BoardService {
void insertBoard(BoardVO vo);
void updateBoard(BoardVO vo);
void deleteBoard(BoardVO vo);
BoardVO selectOneBoard(BoardVO vo);
List<BoardVO> selectAllBoard(BoardVO vo);
}
-------------------------com.ryo.biz.board.impl : BoardDAO, BoardSeriviceImpl
package com.ryo.biz.board.impl;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Repository;
import com.ryo.biz.board.BoardVO;
import com.ryo.biz.common.JDBCUtil;
@Repository("boardDAO")
public class BoardDAO {
private Connection conn;
private PreparedStatement pstmt;
final String sql_selectOne="SELEC * FROM BOARD WHERE BID=?";
final String sql_selectAll="SELECT * FROM BOARD ORDER BY BID DESC";
final String sql_insert="INSERT INTO BOARD(BID,TITLE,WRITER,CONTENT) VALUES((SELECT NVL(MAX(BID),0)+1 FROM BOARD),?,?,?)";
final String sql_update="UPDATE BOARD SET TITLE=?, CONTENT=? WHERE BID=?";
final String sql_delete="DELETE BOARD WHERE BID=?";
BoardVO selectOneBoard(BoardVO vo) {
System.out.println("로그 : selectOne: " + vo);
conn=JDBCUtil.connect();
try {
pstmt=conn.prepareStatement(sql_selectOne);
pstmt.setInt(1, vo.getBid());
ResultSet rs=pstmt.executeQuery();
if(rs.next()) {
BoardVO data=new BoardVO();
data.setBid(rs.getInt("BID"));
data.setContent(rs.getString("CONTENT"));
data.setTitle(rs.getString("TITLE"));
data.setWriter(rs.getString("WRITER"));
data.setCnt(rs.getInt("CNT"));
data.setRegdate(rs.getString("REGDATE"));
return data;
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
JDBCUtil.disconnect(pstmt, conn);
}
return null;
}
List<BoardVO> selectAllBoard(BoardVO vo) {
System.out.println("로그 : selectAll : " + vo);
List<BoardVO> datas=new ArrayList<BoardVO>();
conn=JDBCUtil.connect();
try {
pstmt=conn.prepareStatement(sql_selectAll);
ResultSet rs=pstmt.executeQuery();
while(rs.next()) {
BoardVO data=new BoardVO();
data.setBid(rs.getInt("BID"));
data.setContent(rs.getString("CONTENT"));
data.setTitle(rs.getString("TITLE"));
data.setWriter(rs.getString("WRITER"));
data.setCnt(rs.getInt("CNT"));
data.setRegdate(rs.getString("REGDATE"));
datas.add(data);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
JDBCUtil.disconnect(pstmt, conn);
}
return datas;
}
void insertBoard(BoardVO vo) {
System.out.println("로그 >> insertBoard");
conn=JDBCUtil.connect();
try {
pstmt=conn.prepareStatement(sql_insert);
pstmt.setString(1, vo.getTitle());
pstmt.setString(3, vo.getContent());
pstmt.setString(2, vo.getWriter());
pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtil.disconnect(pstmt, conn);
}
}
void updateBoard(BoardVO vo) {
System.out.println("로그 >> updateBoard");
conn=JDBCUtil.connect();
try {
pstmt=conn.prepareStatement(sql_update);
pstmt.setString(1, vo.getTitle());
pstmt.setString(2, vo.getContent());
pstmt.setInt(3,vo.getBid());
pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtil.disconnect(pstmt, conn);
}
}
void deleteBoard(BoardVO vo) {
System.out.println("로그 >> deleteBoard");
conn=JDBCUtil.connect();
try {
pstmt=conn.prepareStatement(sql_delete);
pstmt.setInt(1,vo.getBid());
pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtil.disconnect(pstmt, conn);
}
}
}
package com.ryo.biz.board.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ryo.biz.board.BoardService;
import com.ryo.biz.board.BoardVO;
@Service("boardService")
public class BoardServiceImpl implements BoardService{
@Autowired
private BoardDAO boardDAO;
@Override
public void insertBoard(BoardVO vo) {
boardDAO.insertBoard(vo);
}
@Override
public void updateBoard(BoardVO vo) {
boardDAO.updateBoard(vo);
}
@Override
public void deleteBoard(BoardVO vo) {
boardDAO.deleteBoard(vo);
}
@Override
public BoardVO selectOneBoard(BoardVO vo) {
return boardDAO.selectOneBoard(vo);
}
@Override
public List<BoardVO> selectAllBoard(BoardVO vo) {
return boardDAO.selectAllBoard(vo);
}
}
-------------------------com.ryo.biz.common : JDBCUtil
package com.ryo.biz.common;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class JDBCUtil {
static final String driverName = "oracle.jdbc.driver.OracleDriver";
static final String url = "jdbc:oracle:thin:@localhost:포트번호:포트이름";
static final String user = "이름";
static final String passwd = "비번";
// conn 객체 반환
public static Connection connect() { // Connection 확보 로직
Connection conn = null;
try {
Class.forName(driverName);
conn = DriverManager.getConnection(url, user, passwd);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return conn;
}
// conn 객체 받아서 연결해제
public static void disconnect(PreparedStatement pstmt, Connection conn) {
try {
pstmt.close();
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
-------------------------test : Client
package test;
import java.util.List;
import java.util.Scanner;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import com.ryo.biz.board.BoardService;
import com.ryo.biz.board.BoardVO;
import com.ryo.biz.member.MemberService;
import com.ryo.biz.member.MemberVO;
public class Client {
public static void main(String[] args) {
AbstractApplicationContext factory=new GenericXmlApplicationContext("applicationContext.xml");
BoardService bs = (BoardService)factory.getBean("boardService");
Scanner sc = new Scanner(System.in);
// 글 등록
BoardVO vo = new BoardVO();
System.out.print("내용작성 >> ");
String msg=sc.nextLine();
vo.setContent(msg);
vo.setTitle("글 제목");
vo.setWriter("작은 티모");
bs.insertBoard(vo);
List<BoardVO> datas=bs.selectAllBoard(vo);
for(BoardVO v : datas) {
System.out.println(v);
}
sc.close();
factory.close();
}
}
-------------------------src/main/resource : applicationContext.xml
<?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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<!-- 필수 속성으로 base-package 존재
여기서 package지정 가능 -->
<context:component-scan base-package="com.ryo.biz"></context:component-scan>
</beans>
'디바이스 융합 자바(Java)기반 풀스택 개발자 양성과정(수업내용)' 카테고리의 다른 글
디바이스 융합 자바(Java) day66(2) - AOP 관련 용어정리 및 예시 (0) | 2022.09.15 |
---|---|
디바이스 융합 자바(Java) day66(1) - 9/14과제 설명, AOP(Advice) (0) | 2022.09.15 |
디바이스 융합 자바(Java) day65(1) - 스프링(생성자 인젝션(day64(2)참고), Setter 인젝션) (1) | 2022.09.14 |
디바이스 융합 자바(Java) day64(2) - Spring (IoC[제어의 역행], AOP[관점지향 프로그래밍]) (1) | 2022.09.13 |
디바이스 융합 자바(Java) day64(1) - Spring 설치 (0) | 2022.09.13 |