개발자
[SPRING]bean/어노테이션 /의존객체/스프링 작동 순서 본문
Bean (빈)
스프링 컨테이너가 관리하는 자바 객체를 빈(Bean)이라 한다.
자바에서 객체를 생성할 때 주로 new를 통해 생성하는데, 이 객체를 의미하는 것이 아니라 컨테이너에서 스스로 생성하고 관리하는 객체를 의미한다.
컨테이너에서의 관리를 통해 객체를 여러번 생성할 필요가 없고, 공용으로 사용할 수 있다.
Annotation
Annotation은 Java 5부터 추가된 문법 요소로, 코드 사이에 주석처럼 쓰이며 특별한 의미, 기능을 수행하도록 하는 기술입니다. 실제 데이터가 아닌 데이터를 위한 데이터로 메타데이터 (meta data)로 불립니다.
@Bean :
@bean 어노테이션은 개발자가 직접 제어가 불가능한 외부 라이브러리등을 bean으로 만들때 사용된다
@ComponentScan:
@Component, @Service, @Repository, @Controller, @Configuration 어노테이션이 붙은 클래스 Bean 들을 찾아서 Context에 bean 등록을 해주는 어노테이션입니다.
bean 등록을 하는 방법에는 @어노테이션을 이용하는 방법과,
ApplicationContext.xml 파일에 <bean id = "example" class = "example" /> 처럼 직접 등록하는 방법이 있습니다.
@Component 란,
@Component는 개발자가 직접 작성한 Class를 Bean으로 등록하기 위한 Annotation 입니다.
* 위에서 설명한 스프링의 컴포넌트 스캔 (@ComponentScan) 기능에 의해 스캔될 때, 주어진 패키지 내에서 @Component 어노테이션이 적용된 클래스를 식별하고, 그러한 클래스의 빈을 생성하여 ApplicationContext에 등록합니다.
* (value = "") 옵션이 있고, 해당 옵션을 사용하지 않는다면 class의 이름을 camelCase로 변경한 것을 bean id로 사용합니다.
참고 사이트 :
https://wildeveloperetrain.tistory.com/26
@Component 와 @Bean, @Autowired 어노테이션 알아보기
자주 사용하면서도 정확하게 무슨 용도로 사용되는지, 어떤 동작 원리를 가지는지, 어떤 차이가 있는지 잘 몰랐던 부분에 대해서 공부합니다. 먼저 Annotation에 대해서 간단하게 알아보겠습니다.
wildeveloperetrain.tistory.com
스프링 bean을 컨테이너에 등록하기
1. 컴포넌트 스캔 원리
2. 자바 코드를 통해 직접 등록
1. 컴포넌트 스캔 원리
@Component 어노테이션이 있으면 스프링 빈으로 자동 등록된다.
주로 정형화된 컨트롤러 - 서비스 - 리포지토리 같은 코드는 컴포넌트 스캔 원리를 활용한다.
정형화된 코드는 @Component 대신 @Controller, @Service, @Repository를 사용할 수 있는데, 이 세 가지 어노테이션들이 @Component라는 어노테이션을 포함하기 때문이다.
1.1 작동순서
'
1
2
3
4
5
6
|
사용자 웹브라우저 요청(View) ==> DispatcherServlet ==> @Controller 클래스 <==>> Service단(핵심업무로직단, business logic단) <==>> Model단[Repository](DAO, DTO) <==>> myBatis <==>> DB(오라클)
(http://... *.action) |
↑ View Resolver
| ↓
| View단(.jsp 또는 Bean명)
-------------------------------------------------------|
|
cs |
사용자(클라이언트)가 웹브라우저에서 http://localhost:9090/board/test/test_insert.action 을 실행하면
배치서술자인 web.xml 에 기술된 대로 org.springframework.web.servlet.DispatcherServlet 이 작동된다.
DispatcherServlet 은 bean 으로 등록된 객체중 controller 빈을 찾아서 URL값이 "/test_insert.action" 으로
매핑된 메소드를 실행시키게 된다.
Service(서비스)단 객체를 업무 로직단(비지니스 로직단)이라고 부른다.
Service(서비스)단 객체가 하는 일은 Model단에서 작성된 데이터베이스 관련 여러 메소드들 중 관련있는것들만을 모아 모아서
하나의 트랜잭션 처리 작업이 이루어지도록 만들어주는 객체이다.
여기서 업무라는 것은 데이터베이스와 관련된 처리 업무를 말하는 것으로 Model 단에서 작성된 메소드를 말하는 것이다.
이 서비스 객체는 @Controller 단에서 넘겨받은 어떤 값을 가지고 Model 단에서 작성된 여러 메소드를 호출하여 실행되어지도록 해주는 것이다.
실행되어진 결과값을 @Controller 단으로 넘겨준다.
1.2 controller
1
2
3
4
5
6
7
8
9
10
|
package com.spring.board.controller;
//=== #30. 컨트롤러 선언 ===
@Component
@Controller
public class BoardController {
}
|
cs |
XML에서 빈을 만드는 대신에 클래스명 앞에 @Component 어노테이션을 적어주면
해당 클래스는 bean으로 자동 등록된다.
그리고 bean의 이름(첫글자는 소문자)은 해당 클래스명이 된다.
즉, 여기서 bean의 이름은 boardController 이 된다.
여기서는 @Controller 를 사용하므로 @Component 기능이 이미 있으므로 @Component를 명기하지 않아도 * BoardController 는 bean 으로 등록되어 스프링컨테이너가 자동적으로 관리해준다.
1.2 -1 의존객체 주입하기(DI: Dependency Injection)
스프링 프레임워크는 객체를 관리해주는 컨테이너를 제공해주고 있다.
스프링 컨테이너는 bean으로 등록되어진 BoardController 클래스 객체가 사용되어질때, BoardController 클래스의 인스턴스 객체변수(의존객체)인 BoardService service 에 자동적으로 bean 으로 등록되어 생성되어진 BoardService service 객체를 BoardController 클래스의 인스턴스 변수 객체로 사용되어지게끔 넣어주는 것을 의존객체주입(DI : Dependency Injection)이라고 부른다.
이것이 바로 IoC(Inversion of Control == 제어의 역전) 인 것이다.
즉, 개발자가 인스턴스 변수 객체를 필요에 의해 생성해주던 것에서 탈피하여 스프링은 컨테이너에 객체를 담아 두고, 필요할 때에 컨테이너로부터 객체를 가져와 사용할 수 있도록 하고 있다.
스프링은 객체의 생성 및 생명주기를 관리할 수 있는 기능을 제공하고 있으므로, 더이상 개발자에 의해 객체를 생성 및 소멸하도록 하지 않고 객체 생성 및 관리를 스프링 프레임워크가 가지고 있는 객체 관리기능을 사용하므로 Inversion of Control == 제어의 역전 이라고 부른다. 그래서 스프링 컨테이너를 IoC 컨테이너라고도 부른다.
1.2 -2 IOC(Inversion of Control) 란
스프링 프레임워크는 사용하고자 하는 객체를 빈형태로 이미 만들어 두고서 컨테이너(Container)에 넣어둔후
필요한 객체사용시 컨테이너(Container)에서 꺼내어 사용하도록 되어있다.
이와 같이 객체 생성 및 소멸에 대한 제어권을 개발자가 하는것이 아니라 스프링 Container 가 하게됨으로써
객체에 대한 제어역할이 개발자에게서 스프링 Container로 넘어가게 됨을 뜻하는 의미가 제어의 역전
즉, IOC(Inversion of Control) 이라고 부른다.
1.2 -2 느슨한 결합
스프링 컨테이너가 BoardController 클래스 객체에서 BoardService 클래스 객체를 사용할 수 있도록
만들어주는 것을 "느슨한 결합" 이라고 부른다.
느스한 결합은 BoardController 객체가 메모리에서 삭제되더라도 BoardService service 객체는 메모리에서 동시에 삭제되는 것이 아니라 남아 있다.
1.2- 3 단단한 결합
단단한 결합(개발자가 인스턴스 변수 객체를 필요에 의해서 생성해주던 것)
private InterBoardService service = new BoardService();
===> BoardController 객체가 메모리에서 삭제 되어지면 BoardService service 객체는 멤버변수(필드)이므로
메모리에서 자동적으로 삭제되어진다.
1.3 service 객체 연결하기 (의존객체 주입)
1
2
3
|
@Autowired
private InterBoardService service;
|
cs |
@Autowired : Type에 따라 알아서 주입해준다. @Resource 를 해주면 boardService로 해주어야한다
빈이름까지 똑같아야해서
1.4 BoardService
1
2
3
4
5
6
7
8
9
|
package com.spring.board.service;
//=== #31. Service 선언 ===
//트랜잭션 처리를 담당하는곳 , 업무를 처리하는 곳, 비지니스(Business)단
@Service //이클래스는 이제 스프링이알아서 트랜잭션처리 해준다
public class BoardService implements InterBoardService {
@Autowired
private InterBoardService service;
|
cs |
1
2
3
4
5
|
// === #34. 의존객체 주입하기(DI: Dependency Injection) ===
@Autowired // Type에 따라 알아서 Bean을 주입해준다.
private InterBoardDAO dao;
// Type 에 따라 Spring 컨테이너가 알아서 bean 으로 등록된 com.spring.board.model.BoardDAO 의 bean 을 dao 에 주입시켜준다.
// 그러므로 dao 는 null 이 아니다.
|
cs |
Service(서비스)단 객체 = 업무 로직단(비지니스 로직단)
Model단에서 작성된 데이터베이스 관련 여러 메소드들 중 관련있는것들만 모아서 하나의 트랜잭션 처리 작업이 이루어지도록 만들어주는 객체
업무 : 데이터베이스와 관련된 처리 업무를 말하는 것으로 Model 단에서 작성된 메소드
@Controller 단에서 넘겨받은 어떤 값을 가지고 Model 단에서 작성된 여러 메소드를 호출하여 실행 ⇒ 결과값을 @Controller 단으로 넘겨줌
1.5 DAO (@Repository) 선언
1
2
3
4
5
6
7
|
package com.spring.board.model;
//=== #32. DAO 선언 ===
@Repository
public class BoardDAO implements InterBoardDAO {
|
cs |
의존객체 주입하기(DI: Dependency Injection)
:의존 객체 자동 주입(Automatic Dependency Injection)은 /스프링 컨테이너가 자동적으로 의존 대상 객체를 찾아서 해당 객체에 필요한 의존객체를 주입하는 것을 말한다.
단, 의존객체는 스프링 컨테이너속에 bean 으로 등록되어 있어야 한다.
의존 객체 자동 주입(Automatic Dependency Injection)방법 3가지
1. @Autowired ==> Spring Framework에서 지원하는 어노테이션이다. 스프링 컨테이너에 담겨진 의존객체를 주입할때 타입을 찾아서 연결(의존객체주입)한다. (이름 알아서 abc)
2. @Resource ==> Java 에서 지원하는 어노테이션이다.
스프링 컨테이너에 담겨진 의존객체를 주입할때 필드명(이름)을 찾아서 연결(의존객체주입)한다.
@Resource 를 해주면 빈이름 동일해야한다 (sqlsession)
3. @Inject ==> Java 에서 지원하는 어노테이션이다. 스프링 컨테이너에 담겨진 의존객체를 주입할때 타입을 찾아서 연결(의존객체주입)한다.
db에 연결
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
/*
// root-context.xml에 이미 빈으로 올려놨었다
@Autowired
private SqlSessionTemplate abc; //스프링 컨테이너가 SqlSessionTemplate로 된 빈을찾아 abc에 넣어준다.
// Type 에 따라 Spring 컨테이너가 알아서 root-context.xml 에 생성된 org.mybatis.spring.SqlSessionTemplate 의 bean 을 abc 에 주입시켜준다.
// 그러므로 abc 는 null 이 아니다. private SqlSessionTemplate abc=null;이 아닌것임.
*/
@Resource
private SqlSessionTemplate sqlsession; // 로컬 DB mymvc_user 에 연결
// Type (클래스) 및 빈이름이 동일한 것을 찾아서 주입시켜준다
@Resource
private SqlSessionTemplate sqlsession_2; // 로컬DB hr에 연결
// Type (클래스) 및 빈이름이 동일한 것을 찾아서 주입시켜준다
|
cs |
root-context.xml에 bean으로 등록 해줬어야 했다.
1
2
3
4
5
6
7
8
|
<!-- ==== #15. myBatis(JDBC)설정 sqlSessionTemplate 의존 객체 설정 ==== -->
<bean id="sqlsession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
</bean>
<bean id="sqlsession_2" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory_2" />
</bean>
|
cs |
1.6 board.xml
1.6-1 root-context.xml : DB 지정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
<?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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<!-- ==== #15. myBatis(JDBC)설정 연결문자열 설정하기 ==== -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe" />
<!-- <property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:xe" /> -->
<property name="username" value="mymvc_user" />
<property name="password" value="aclass" />
</bean>
<!-- ==== #15. myBatis(JDBC)설정 mapper 파일 위치 지정하기 ==== -->
<!-- mapper 파일이란 sql 문을 가지고 있는 xml 파일을 말한다. -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="mapperLocations" value="classpath*:com/spring/board/mapper/*.xml" />
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- ==== #15. myBatis(JDBC)설정 sqlSessionTemplate 의존 객체 설정 ==== -->
<bean id="sqlsession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
</bean>
<!-- ==== 로컬 오라클 서버의 HR 연결 시작 ==== -->
<bean id="dataSource_2" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe" />
<!-- <property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:xe" /> -->
<property name="username" value="hr" />
<property name="password" value="aclass" />
</bean>
<!-- mapper 파일이란 sql 문을 가지고 있는 xml 파일을 말한다. -->
<bean id="sqlSessionFactory_2" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="mapperLocations" value="classpath*:com/spring/board/mapper/*.xml" />
<property name="dataSource" ref="dataSource_2"/>
</bean>
<bean id="sqlsession_2" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory_2" />
</bean>
<!-- ==== 로컬 오라클 서버의 HR 연결 끝 ==== -->
<!-- ==== #16. 트랜잭션 처리를 위해서 아래와 같이 트랜잭션매니저 객체를 bean 으로 등록해야 한다. ==== -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- ==== #17. jackson 과 관련된 기능을 사용하기 위해 빈을 등록한다. ==== -->
<bean id="jacksonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
</beans>
|
cs |
1.6 - 2 board.xml : mapper , sql작성하는 곳(개인별로 만들기)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
?xml version="1.0" encoding="UTF-8"?>
<!-- ==== #29. mapper 기본설정 ==== -->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- ==== #29. 루트 엘리먼트 & 네임스페이스 설정(프로젝트 전체내에서 유일해야 한다.) ==== -->
<mapper namespace="board">
<!--sql문에 세미콜론 쓰지말것 -->
<insert id="test_insert">
insert into spring_test(no,name, writeday)
values(102, '최땡땡', default)
</insert>
<!-- 타입에 패키지명 써주기 -->
<!-- !!!! 주의해야할 사항은 리턴타입이 List<E> 이더라도 resultType 은 E 으로 해야만 한다. !!!! 왜냐하면 dao에서 selectList했으니까 이미 안다-->
<select id="test_select" resultType="com.spring.board.model.TestVO">
select no, name, to_char(writeday, 'yyyy-mm-dd hh24:mi:ss') AS writeday
from spring_test
order by writeday desc
</select>
<!-- #### 중요 ####
HashMap 타입으로 매개변수를 받아온 것을 꺼내서 사용할때
1. 데이터로 사용할때는 #{key명} 이고,
2. 식별자(테이블명, 컬럼명)로 사용할때는 ${key명} 이고,
3. myBatis 에서 제공하는 if 엘리먼트나 choose 엘리먼트 안에서 사용할때는
그냥 <if test="key명"> <when test="key명"> 으로 사용한다.
-->
<!-- 우리가 만든 패키지아니면 패키지명은 안써줘도 된다. java.util.HashMap-->
<insert id="test_insert_map" parameterType="HashMap">
insert into spring_test(no, name, writeday)
values(#{no}, #{name}, default)
</insert>
<!-- === 파라미터로 VO가 들어오면 입력해줄때 값은 #{get다음에나오는 메소드명인데 첫글자는 반드시 소문자} 으로 해준다. -->
<insert id="test_insert_vo" parameterType="com.spring.board.model.TestVO">
insert into spring_test(no, name, writeday)
values( #{no}, #{name}, default)
</insert>
|
cs |
'개발자 > SPRING' 카테고리의 다른 글
[SPRING] 환경설정 (0) | 2022.11.11 |
---|