@RequestMapping 
 핸들러 매핑과 핸들러 어댑터의 대상이 오브젝트가 아니라 메소드이다. 
 Controller와 같이 하나의 메소드를 가진 인터페이스로 정의되는 컨트롤러는 기본적으로 URL 당 하나의 컨트롤러 오브젝트가 매핑되고 컨트로러당 하나의 메소드만 DIspatcherServlet의 호출을 받을수 있다.
 >>어노테이션은 부여되는 대상의 타입이나 코드에는 영향을 주지 않는 메타정보이다. 

@MVC의 핸들러 매핑을 위해서는 DefaultAnnotationHandlerMapping이 필요하다. 매핑정보로 @RequestMapping 어노테이션을 사용한다.  메소드, 타입 레벨에 다 붙으며 이 정보를 결합하여 최종 매핑 정보를 생성한다. 한 클래스에 같이 사용하면 타입레벨속에 메소드 레벨이 포함된다. 

1.@RequestMappping 
-String[ ] value() : URL 패턴
-RequestMethod[ ] method() : http 요청메서드 , ex) @RequestMapping(  "/hello/add", method=RequestMethod.GET ) @RequestMapping(  "/hello/add", method=RequestMethod.POST) 
폼 처리할'대 동일한 URL에 대해 GET과 POST 처리시 용이 
-Stringp[] : 같은 URL을 사용하더라도 HTTP 요청 파라미터에 따라 별도의 작업을 해주고 싶을떄, ex) @RequestMapping(  value= "/hello/edit", params="type=admin" ) 
-String[ ] headers(): HTTP해더, 저장방식이 params와 비슷하게 해더이름=값의 형식을 사용한 경우
ex) @RequestMapping(  value="/hello", headers="content-type=text/*" ) 

메소드 레벨의 매핑조건이 공통점이 없는 경우라면 타입레벨에서 주지 않고 메소드 레벨에 독립적으로 매핑정보를 지정할수있다. 이때 타입레벨에서는 @ReqeustMapping을 꼭 부여해주어야 한다.  이떄 @Controller 어노테이션을 붙여 빈 자동스캔방식으로 등록되게 했다면 생략 가능하다. 

>>핸들러 매핑은 원래 핸들러 오브젝트를 결정하는 전략이다. 어노테이션이 영향으로 매핑 방법이 메소드 레벨까지 세분화 되기는 했지만 타입 컨트롤러와의 일관성을 위해 어노테이션 방식의 핸들러 매핑에서도 일단 오브젝트까지만 매핑을 하고 최종 실행할 메소드는 핸들러 어댑터가 결정한다. 

@RequestMapping( "/user/*")
public class UserController{
    @RequestMapping publid void add() {
    }
}
클래스 레벨에서는 /*로 끝나게 하고 메소드 레벨에서는 @RequestMapping만 부여해주면 매소드이름이 URL이 된다. 

상속도 가능하다.
super클래스에서 클래스 레벨로 @RequestMapping( "/user") 해놓았다면 sub클래스의 메소드 레벨의 
@RequesMapping("/list") public String list() {...} 로 호출가능하다. 


@Controller
DefaultAnnotationHandlerMapping은 사용자 요청을 @RequestMapping정보를 활용해서 컨트롤러 빈의 메소드에 매핑해준다. 그리고 AnnotationMethodHandlerAdpter는 매핑된 메소드를 실제로 호출하는 역활을 담당한다. 

 메소드 파라미터의 종류 
-httpServletRequest , httpServletResponse
-패스변수 
url: /user/view/10 
@RequestMapping( "/user/view/{id}" )
public String view( @PathVariable("id") int id ) {

}
@RequestParam
http 요청 파라미터를 메소드 파라미터에 넣어준다. 
Map<String, String>타입으로 선언하면 모든 요청파라미터를 담을 맵으로 받을 수 있다. 

@RequestHeader

@ModelAttribute 
파라미터타입으로 오브젝트를 만들고 프로퍼티를 토해 요청파라미터를 넣어준다. 
생략가능하며 @RequestParam,@ModelAttribute 생략되었을 경우 string, int는 전자로 보고 그 외 복잡한 오브젝트는 후자로 알아서 본다.

@RequestBody 
http 요청의 본문이 그대로 전달된다. 
xml이나 json기반의 메세지를 사용하는 요청의 경우 매우 유용하다. 
AnnotationMethodHandlerAdapter에는 HttpMessageConverter 타입의 메세지 변환기가 여러개 등록되어있다. 이 어노테이션이 있으면 http요청의 미디어 타입과 파라미터 타입을 먼저 확이한다. 메시지 변환기 중에서 해당 미디어 타입과 파라미터 타입을 처리할수있는것이 있으면 http 요청이 본문부분을 통째로 변환해서 지정된 메소드 파라미터로 전달해준다. 

>>AnnotationMethodHandlerAdapter가 호출하는 컨트롤러 메소드의 사용 가능한 파라미터타입과 어노테이션이다. 


리턴타입의 종류
컨트롤러가 DIspatchServlet에 돌려줘야하는 정보는 모델과 뷰다. 핸들러 어댑터를 거쳐서 최종적으로 DIspatcherServlet에 돌아갈때는 ModelAndView 타입으로 리턴값이 전달된다. httpServletRsponse에 직접 결과를 넣어 리턴한는 경우도 있다. 
-@ModelAttribute  모델  오브젝트 또는 커맨드 오브젝트 : 모델 오브젝트의 이름은 파라미터 타입 이름을 따른다. 
-Map. Model ModelMap 파라미터 : 뷰에 전달되는 모델에 자동으로 추가
-@ModelAttribute 메소드

모델의 바인딩과 검증
 컨트로러 메소드에 @modelAttribute가 지정된 파라미터를 @controller 메소드에 추가하면 크게 세 가지 작업이 자동으로 진행된다. '
 -파라미터 타입의 오브젝트를 만든다. 
 -준비된 모델 오브젝트의 프로퍼티에 웹 파라미터를 바인딩해준다.  http를 통해 전달되는 파라미터는 기본적으로 문자열인데 프로퍼티가 스트링이 아니라면 적절한 타입으로 변환해준다. 
 
 -모델의 값을 검증한다. 

 ing 1200p


출저 : 토비의 스프링







 



'STUDY > SPRING' 카테고리의 다른 글

Java EE 디자인패턴(ing)  (0) 2018.11.12
DATA Access  (0) 2018.11.08
Aspect Oriented Programming  (0) 2018.11.06
TRANSACTION  (0) 2018.11.06
MVC  (0) 2018.11.02

 
개념정리용 도서로 2018.11.12 - 2018.11.15

자바 EE

자바 EE 어플리케이션
-메타 데이터를 어노테이션을 달아놓은 POJO만 있으면 EJB(상태성/무상태성), servlet, jsf기반 빈(backig bean), 퍼시스턴스 개체, 싱글톤, REST 웹 서비스를 만들 수 있다. 

-다중 티어 아키텍쳐이다
클라이언트 티어, 미들 티어( 웹 레이어 + 비즈니스 레이어 ), 엔터프라이즈 정보 시스템 티어로 나뉜다. 
클라이언트 티어(프리젠테이션 티어):  클라이언트 - 서버 구저에서 클라이언트에 해당하는 애플리케이션 전부를 일컫는다. 
미들티어: 웹 컨테이너와 EJB컨테이너를 제공한다. 웹 레이어 기술은자바 서버 페이지(JSP), 표현식 언어(EL), 자바 서버페이지(JSTL)가 클라이언트로 보낼 응답을 포장하는 동안 서블릿은 웹 흐름을 제어하고 교통정리를 한다.  비즈니스 레이어는 업무 요건을 처리하거나 도메인 내부의 특정 비즈니스 로직을 실행한다. 비즈니스 레이어는 자바 퍼시스턴스(JPA), 자바 트랜잭션(JTA), 자바 데이터베이스 연결(JDBC) 기술이있다. 
EIS티어 :  DB형태의 데이터 저장 단위로 구성하지만 데이터를 공급하는 리소스면 어느것이든 가능



패턴은 세가지 유형으로 나눈다. 

생성패턴( Createional pattern ) - 객체의 생성, 초기화, 클래스 선택에 관한 패턴 ( 싱글턴 , 팩토리 )
행동패턴( Behavioral pattern ) - 객체간 소통, 메시징, 상호작용에 관한 패턴 ( 옵져버 )
구조패턴( structural pattern ) - 클래스와 객체 관계를 조직하는 패턴 ( 데코레이션 )

1.퍼사드 패턴
 복잡한 비즈니스 로직을 상위 레벨의 인터페이스로 캡슐화해서 하위 시스템에 더 쉽게 접근하능하도록 할수있게 한다. 

2.싱글톤 패턴
3.의존체 주입과 CDI
4.팩토리 패턴
5.장식자 패턴
6.AOP
7.비동기
8.타이머 서비스
9.옵저버
10.데이터 접근 패턴
11.REST형 웹서비스
12.mvc
13.나머지 자바 EE패턴











'STUDY > SPRING' 카테고리의 다른 글

@MVC (ing)  (0) 2018.11.12
DATA Access  (0) 2018.11.08
Aspect Oriented Programming  (0) 2018.11.06
TRANSACTION  (0) 2018.11.06
MVC  (0) 2018.11.02

스프링은 주요 데어터 엑서스기술인 자체적인 dataSource 생성 방식 대신 스프링 빈으로 등록돤 DataSource를 사용하여 필요한 방법을 제공해준다. 


스프링의 JDBC 기술과 동작원리
JDBC : 자바의 데이터 엑서스 기술이 기본이 되는 로우레벨의 API이다. 
기술
1.Connection 열기와 닫기
2.Statement 준비와 닫기 및 실행
sql 정보가 담긴 statement 또는 preparedStatment를 생성하고 필요한 준비작업을 한다. 
3.ResultSet 루프
ResultSet에 담기 쿼리 실행 결과가 한건 이상이라면 루프를 돌면서 각자 로우를 처리해줘야하는데 루프름 만들어 반복해주는것도 스프링 JDBC가 해주는 작업이다. 
4.예외처리의 반환
5.트랜잭션 처리 

SimleJdbcTemplate
 jdbcTemplate과 NameParameterJdbcTemplate에서 가장 많이 사용되는 기능을 통합하고 자바 5이상의 장점을 최대한 활용할 수 있게 만든것이다. 
멀티 스레드 환경에서도 안전하게 공유해서 사용가능하다. 

SimpleJdbcInsert, SimpleJdbcCall
DB가 제공해주는 메타정보를 활용해서 최소한의 코드만으로 단순한 JDBC코드를 작성하게 해준다.

sql파라미터
작업시 문자열로 된 sql을 제공해줘야하는데 파라미터 바인딩 방법을 사용한다. 
map / mapSQLParameterSource 사용
 -실행메소드 INSERT, UPDATE, DELETE와 같은 SQL을 사용할때 simpleJdbcTemplete의 update()를사용
 -조회메소드 
 -배치메소드 update()로 실행하는 sql들을 배치모드로 실행하게 해준다 JDBC statement를 사용하여 addBatch(), executeBatch() 메소드르 이용해 여러개의 sql을 처리한다. 

스프링의 DAO
 보통 DAO는 도메인 오브젝트 또는 DB 데이틀 단위로 만든다 . 스프링은 JdbcDaoSupport라는 JDBC를 이용한 DAO작서에 사용할수있는 추상클래스를 제공하고 있다. 

MYbatis 

 자바 오브젝트와 sql문 사이의 자동매핑 기능을 지원하는 ORM 프레임워크이다. 
sql을 자바 코드에서 분리하여 별도의 xml 파일 안에 작성하고 관리할 수 있어 sql 변경시 자바코드를 수정하고 컴파일 하지 않아도 된다.

 ORM(Object Relation Mapping) : 오브젝트와 RDB 사이에 존재하는 개념과 접근방법, 성격차이 때문에 요구되는 불편한 작업을 제거해줘서 개발자가 오브젝트를 가지고 정보를 다루면 ORM 프레임워크가 이를 RDB에 적절한 형태롸 변환해주거나 그 반대로 RDB에 저장되어있는 정보를 자바 오브젝트가 다루기 쉬운 형태로 변환해주는 기술이다. 
 따라서 ORM을 사용하는 개발자는 모든 데이터를 오브젝트 관점으로 본다. 

iBatis -> MyBatis
 -Apache project 팀에서 google code팀으로 이동하면서 명칭수정
 -용어변경
 SqlMapConfig -> Configration
 sqlMap => Mapper
 resultClass -> resultType
-자바 1.4까지만 iBatis 사용
-lib제공
<dependency>
    <groupId>org.mybatis</groupId>
   <artifactId>mybatis</artifactId>
   <version>3.2.2</version>
</dependency>
 
<dependency>
   <groupId>org.mybatis</groupId>
   <artifactId>mybatis-spring</artifactId>
    <version>1.2.0</version>
</dependency>
-sqlMapClient DI 설정불필요 , sqlsessionFactory, sqlSessionTemplate만 bean id 지정하면 됨 ...


등록, 수정 , 삭제
 insert()  
 sql아이디(statementName)와 파라미터 오브젝트를 넣어주면 해당 insert 문을 실행한다. 
내부적으로 ibatis의 SqlMapExecutor의 insert() 메소드가 사용된다. 파라미터 유무에 따라 다음 두가지중 하나가 사용된다.
  Object insert( String statementName )
  Object insert( String statementName, Object parameterObject )

 update()
 실행후 영향받은 로우개수를 리턴해주는 메서드 2개와 로우 개수를 체크해주는 메소드 1개가 있다. 기대했던 로우수와 다른 경우 예외가 발생한다. 

 delete() 
  실행후 영향받은 로우개수를 리턴해주는 메서드 2개와 로우 개수를 체크해주는 메소드 1개가 있다. 기대했던 로우수와 다른 경우 예외가 발생한다. 

 조회
 단일 로우 오브젝트: 실행 결과가 한건
 다중 로우: 실행결과가 한건 이상인 경우 각 로우를 오브젝트에 담아 이를 다시 리스트로 돌려준다.
 다중 로우 조회( queryForMap() ): 맵이 앤드리마다 로우 하나의 내용이 들어간다. 맵의 키는 지정된 컬럼값이 사용된다. 
 핸들러 방식 ( queryWithRowHandler() ): sql의 결과를 루프를 돌면서 각 로우마다 콜벡 오브젝트를 호출하는 방식이다. 

mybatis 사용예시
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
        p:dataSource-ref="dataSource"
        p:configLocation="classpath:sqls/mybatis-config.xml"
        p:mapperLocations="classpath*:sqls/**/sql-*.xml">
    </bean>
    mybatis-config.xml
    <configuration>
        <typeAliases>
             <typeAlias alias="MemberVO"                type="com.bo.common.vo.MemberVO"/>
             <typeAlias alias="BoardVO"                 type="com.bo.common.vo.BoardVO"/>
        </typeAliases>
    <configuration>


    @VO( "MemberVO" )
    public class MemberVO{
       
       @Name( "순번" )
       private Object      seq;
       @Name( "순번필드명" )
       private String      seqName;
       @Name( "대상테이블명" )
       private String      tblName.... 
    member.xml
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="memberInfo">
       <resultMap type="MemberVO" id="result" />
       <select id="listMember" resultMap="result" parameterType="java.util.HashMap">
            SELECT * FROM tbl_member WHERE memberTeam=#{where.memberTeam}
        </select>.....
   
   MemberDaoImpl
      @Repository( "MemberDaoImpl" )
   public class MemberDaoImpl implements MemberDao{
       @Autowired
       @Resource ( name = "commonDB" )
       private SqlSession  sqlSession;
       @Override
       public List<MemverVO> list( Object object ) throws Exception{
             return sqlSession.selectList( "memberInfo.listMember", object );
       } ....
그밖의  mybatis 동적 SQL

    1.<trim>, <if>
    <select id="CommonFileInfo" resultType="Integer" parameterType="java.util.HashMap" useCache="false">
             SELECT
                    COUNT(*)
             FROM
                    BOARD
             <trim prefix="WHERE" prefixOverrides="AND | OR ">
                    <if test="where.fileType != null and where.fileType != ''">
                           AND FILE_TYPE = #{where.fileType}
                    </if>
                    <if test="where.regUser != null and where.regUser != ''">
                           AND REG_USER = #{where.regUser}
                    </if>
             </trim>
       </select>
            <where>태그의 오류를 대신한 것으로  where 엘리먼트는 태그에 의해 컨텐츠가 리턴되면 단순히 “WHERE”만을 추가한다. 
           게다가 컨텐츠가 “AND”나 “OR”로 시작한다면 그 “AND”나 “OR”를 지워버린다.
            
            2.<foreach>
        <update id="update">
             <foreach collection="list" item="item" index="index" open="INSERT ALL " separator=" " close="SELECT * FROM DUAL">
                     INTO BOARD(
                           SEQ
                           , NAME
                           , WRITER
                           <if test='item.modifyCause != null and item.modifyCause != "" and item.modifyCause != "-"'>
                           , MODIFY_CAUSE
                           </if>
                    ) VALUES
                    (
                           #{item.seq}
                           , #{item.name}
                           , #{item.writer}
                           <if test='item.modifyCause != null and item.modifyCause != "" and item.modifyCause != "-"'>
                           , #{item.modifyCause}
                           </if>
                    )
             </foreach>
       </update>
  1.  <choose>  
       SELCT *
       FROM
             <choose>
                    <when test="where.type eq 'tblboard1'.toString()">TBL_BOARD_1 TB_1</when>
                    <when test="where.type eq 'tblboard12'.toString()">TBL_BOARD_2 TB_2</when>
             </choose>
    4.bind
        <select id="selectBlogsLike" resultType="Blog">
        <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
        SELECT * FROM BLOG
        WHERE title LIKE #{pattern}
        </select>
mybatis의 plug-in
mybatis-config.xml
       <plugins>
           <plugin interceptor="com.util.MybatisInterceptor"/>
       </plugins>

mybatis에서는 plug-in을 이용하여 mybatis쿼리가 실행하는 시점에 간섭하여 사용자가 정의한 별도의 작업을 진행할수있다.

MybatisInterceptor.java
@Intercepts( {
    @Signature( type = Executor.class, method = "update", args = { MappedStatement.class, Object.class } ),
    @Signature( type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class } ),
    @Signature( type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class } ) } )
public class MybatisInterceptor implements Interceptor {
       @Override
       public Object intercept( Invocation invocation ) throws Throwable {
             Object args[] = invocation.getArgs();
             MappedStatement ms = (MappedStatement) args[0];
             String id = ms.getId();
             //로그 찍고 싶지않은 쿼리들 예외처리
             if ( "memberInfo.listMember".equals( id ) )
                    return invocation.proceed();
            
             //바인딩 변수 사용했을 경우 ?로 표시되므로 ?를 바인딩된 값으로 치환해준다. 
             BoundSql boundSql = ms.getBoundSql( args[1] );
             StringBuilder sql = new StringBuilder( boundSql.getSql() );
             if ( boundSql.getParameterMappings().size() > 0 ) {
                    ArrayList<ParameterMapping> parameterMappingsList = (ArrayList<ParameterMapping>) boundSql.getParameterMappings();
                    for ( int i = 0; i < parameterMappingsList.size(); i++ ) {
                        ParameterMapping parameterMapping = parameterMappingsList.get( i );
                        Object result = null;
                        String fieldName = parameterMapping.getProperty();
                        result = Ognl.getValue( fieldName, boundSql.getParameterObject() );
                        int index = sql.indexOf( "?" );
                        ....
                        sql.replace( index, index + 1, result );
                    }
             }

                            return sql;
       }

-prepared statement
쿼리가 실행되는 순서는 
구분분석(parse) >> 치환(bind) >> 실행(execute) >> 인출(patch) 과정을 거치는데  일반적인 statement를 사용하면 select쿼리를 입력했을때 매번 전과정을 수행한다. 하지만 prepared STatement를 사용하는 경우에는 효율을 높이기 위해 최초1번만 parse를 한다. 
 그리고 변경되는 값은 변수로 선언해주고 매번 값을 대입하여 사용하여아한다.  바인드 데이터는 sql문법이 아닌 내부의 인터프리터나 컴파일 언어로 처리하기 때문에 문법적인 의미를 가지지 않아 인젝션 공격에 안전하다. 













'STUDY > SPRING' 카테고리의 다른 글

@MVC (ing)  (0) 2018.11.12
Java EE 디자인패턴(ing)  (0) 2018.11.12
Aspect Oriented Programming  (0) 2018.11.06
TRANSACTION  (0) 2018.11.06
MVC  (0) 2018.11.02


어플리케이션의 공통기능들을 핵심로직과 분리하여 공통관심(로깅, 트랜잭션 등등)으로 두고 관리한다. 
이떄 기본적이 개념은 공통 관심 사항을 구현한 코드를 핵심 로직을 구현한 코드 안에 삽입하는 것이다. 

 트랜잭션 같은 부가기능은 핵심기능과 같은 방식으로 모듈화하기 매우 힘들다. 이름 그대로 부가기능이기때문에 스스로 독립적인 방식으로 존재해서는 적용되기 어렵기 떄문이다. 그래서 데코레이션 패턴, 다이내믹 프록시, 오브젝트 생성 후처리, 자동 프록시 생성, 포인트 컷과 같은 기법이 생겨났다.
  그리고 이런 독립적으로 모듈화가 불가능한 것들의 모듈화를 연구해온 사람들이 기존의 객체지향 설계 페러다임과 구분되는 새로운 특성이 있다고 생각했고 그것을 애스팩트라고 불렀다. 
 
 애스팩트 : 그 자체로 애플리케이션의 핵심 기능을 담고 있진 않지만 애플리케이션을 구성하는 한가지 요소이고 핵심기능에 부가되어 의미를 갖는 특별한 모듈 
 그리고 이 모듈을 만들어 설계하고 개발하는 방법을 애스팩트 지향 프로그래밍(AOP)이라고 한다.

target : 부가기능을 부여할 대상
advice : 타깃에게 제공할 부가기능을 담은 모듈 , 오브젝트, 메소드 레벨 모두 정의가능하다.
weaving : advice를 핵심기능에 적용하는 것
aspect : 여러 객체에 공통으로 적용되는 기능
joinpoint : advice를 적용 될수있는 위치, 타깃 오브젝트가 구현한 인터페이스는 모두이다. 
pointcut: joinpoint의 부분집합으로서 실제로 advice가 적용되는 joinpoint를 나타낸다. 
proxy :  클라이언트와 타킷 사이에 투명하게 존재하면서 부가기능을 제공하는 오브젝트 DI를 통해 타깃대신 클라이언트에 주입된다.
advisor : 포인트컷과 어드바이스를 하나씩 갖고 있는 오브젝트. 부가기능(어드바이스)를 어디에(포인트컷) 전달할것인가 아는 기본모듈
            스프링만의 용어임

세가지 weaving방식 
-컴파일시 : aspectJ에서 사용 컴파일 결과 aop가 적용된 클래스 파일이 생성된다. 
-클래스 로딩시 : 원본 클래스 파일을 변경하지 않고 클래스를 로딩할때 jvm이 변경된 바이트 코드를 사용하도록 함으로써 aop를 적용한다. aspectJ도 지원함
-런타임시 : 소스 코드나 클래스 정보 자체를 변경하지 않는다 대신 프록시를 사용한다. 

1.스프링의 AOP( 프록시를 이용한 AOP )
모듈화가 된 부가기능(advice)과 적용대상(pointcut)의 조합을 통해 여러 오브젝트에 산재해서 나타는 공통적인 기능을 손쉽게 개발하고 관리할수 있는 기술이다. 
 스프링은 다이내믹 프록시 기술을 이용해 AOP개발 기능을 제공한다. 
프록시 기술 방식의 AOP는 데코레이션 패턴 또는 프록시 패턴을 응용해 기존 코드에 영향을 주지 않은 채로 부가기능을 타깃오브젝트에 제공할수있는 객체지향 프로그래밍 모델로부터 출발한다. 여기에 포인트 컷이라는 적용 대상 기법과 자동 프록시 생성이라는 적용 기법까지 적목하면 비로소  AOP라고 부를수있는 효과적인 부가기능 모듈화가 가능해진다. 

client가 target을 직접적으로 알고 있으면 안된다. client가 사용할 오브젝트를 DI컨테이너 설정을 통해 바꿀수없기 때문이다. 따라서 DI원리에 의존하고 있는 데코레이션 패턴이 적용된 프록시 방식이 적용되지 못한다. 
 따라서 Client가 target이 구현하고있는 인터페이스를 이용해 의존하도록 만들어야 한다.  aop는 하나의 모듈을 많은 오브젝트의 메소드 실행시점에 일괄 적용할 수 있어야 한다.  그래서 스프링은 자동 프록시 생성기를 이용해서 컨테이너 초기화중에 만들어진 빈을 바꿔치기해 프록시 빈을 자동으로 등록해준다. 빈을 등록하는 로직은 포인트컷을 이용하면되고 어노테이션,xml을 통해 이미 정의된 빈의 의존관계를 바꿔치기하는것은 빈 후처리가 사용한다.  이 자동 프록시 생성기가 바로 스프링의 프록시 기반 AOP의 핵심동작원리이다. 

 최소한 네가지 빈을 등록해야한다.
 -자동 프록시 생성기
스프링의 DefaultAdvisorAutoProxyCreator 클래스를 빈으로 등록한다. 다른 빈을 DI하지 않고 자신도 DI되지 않으며 독립적으로 존재한다. 애플리케이션 컨텍스트가 빈 오브젝르를 생성하는 과정에 빈 후처리기로 참여한다. 빈으로 등록된 어드바이저를 이용해서 프록시를 자동으로 생성하는 기능을 한다.

 -어드바이스 
 부가기능을 구현한 클래스를 빈으로 등록한다. 

 -포인트컷 
 스프링의 AspectJExpressionPointcut을 빈으로 등록하고 expression프로퍼티에 포인트컷 표현식을 넣어주며 된다 
 
 -어드바이져
 자동프록시 생성기에 의해 자동 검색되어 사용된다. 

<aop:config>
    <aop:pointcut id="mybatis_operations"   expression="execution( *com. *Dao.)"/>
    <aop:advisor advice-ref="mybatis_txAdvice" pointcut-ref="mybatis_operations"/>
</aop:config>

<aop:config> : AspectJAdvisorAutoProxyCreator 을 빈으로 등록한다.
<aop:pointcut> : AspectJExpressionPointcut을 빈으로 등록한다.
<aop:advisor> :  advice와 pointcut의 ref를 프로퍼티로 갖는 DefaultBeanFactoryPointcutAdvisor를 등록한다.

1.AOP 인터페이스 구현과 <bean> 등록을 이용하는 방법
2.AOP 인터페이스 구현과 aop 네임스페이스의 <aop:advisor>를 이용 하는 방법
3.임의의 자바 클래스와 aop 네임스페이스의 <aop:aspect>를 이용하는 방법
2번과 마찬가지로 aop네임페이스를 사용하나 어드바이저 대신 에스펙트라는 개념을 이용한다. 
스프링 aop를 사용한다면 어떤 개발 방식이든 모두 프록시 방식의 AOP다. 

스프링의 aop는 기본적으로 다이내믹 프록시를 기법을 사용한다. 이 기법을 사용하려면 기본적으로 인터페이스가 있어야 하는데 특별히 레거시 클래스코드를 써야하는 경우 어떻게 해야할까
이때는 클래스 프록시 모드를 사용한다. 인터페이스가 아닌 레거시 클래스 코드일경우 JDK 다이내믹 믹 프록시가 아닌 CGLIB 라이브러리가 제공된다. 
 <tx: config proxy-target-class="true">
클래스 프록시는 타깃클래스를 상속해서 프록시를 만드므로 final클래스는 적용할수없으며 생성자가 두번호출되는 문제로 생성자에서 중요한 작업은 피하도록 해야한다. 그리고 클래스의 public 메소드 전체가 트랜잭션의 대상이 된다. 

4.@AspectJ 애노테이션을 이용한 애스펙트 개발 방법
<aop:config> 대신 <aop:aspectj-autoproxy /> 사용하여 @AspectJ가 붙은 것을 모두 에스펙트로 등록해줘야 한다. 어드바이스와 포인트컷은 자바 클래스내에 정의한 어노테이션을 이용해 정의된다.
 -@PointCut 
 -어드바이스: @Before, @AfterReturning,@AfterThrowing,@After,@Around
 

2.AspectJ AOP ( 바이트코드 새성과 조작을 통한 AOP )
 자바 언어 자체를 확장해서 만든 aspect문법을 이용해 에스펙트를 작성해야한다.  스프링의 AOP는 단지 DI의 도움을 받아 프록시 오브젝트를 추가함으로써 애스펙트를 적용할수있다. 하지만 AspectJ는 이와 달리 아예 타깃오브젝트 자체의 코드를 바꿈으로서 애스펙트를 적용한다.  따라서 프록시를 사용하지 않는다. 대신 타깃 오버젝트와 자바 코드에 처음부터 애스펙트가 적용되어 있던것처럼 클래스 바이트코드를 변경하는 작업이 필요하다. 
 자바의 프록시 기법으로는 특정 오브젝트가 생성된 시점이나 특정 필드를 읽을 지점에 어드바이스를 추가할 방법이 없다. 하지만 AspectJ는 private 메소다의 호출, 스태틱 메소드 호출, 오브젝트의 생성순간 까지 다 참여가능하다. 
 
스프링 빈에서 작업의 실행을 어드바이즈하는것이 전부라면 스프링 AOP가 좋은 선택이나 컨테이너가 관리하지않는 객체(도메인 등)를 어드바이즈하거나 간단한 메서드들 외에 조인포인트를 어드바이즈해야된다면 AspectJ 를 사용하는것이 좋다. 

출처 :토비,  4.0 최범균저

'STUDY > SPRING' 카테고리의 다른 글

Java EE 디자인패턴(ing)  (0) 2018.11.12
DATA Access  (0) 2018.11.08
TRANSACTION  (0) 2018.11.06
MVC  (0) 2018.11.02
[코드로 배우는 스프링 웹프로젝트]  (0) 2018.10.31

트랜잭션 : 더 이상 쪼갤 수 없는 최소 단위의 작업 

DAO메소드에서 DB커넥션을 매번 만든다. connection 오브젝트를 하나로 사용하려면 호출시마다 파라미터로 전달해주어야 한다. 
히지만 이렇게 될 경우 개발자가 connection까지 연결을 고려해야한다.
그래서 스프링은 트랜잭션 동기화를 설정해준다.
DAO가 사용하는JDBCTemplete이 트랜잭션 동기화 방식을 이용하도록 하는 것이다. 
실제 스프링을 사용하지 않는 자바에서는 직접 connection연결 관리부터 커밋,롤백을 제어해주어야 한다. 
     manager.getConnection( getConnectionHandler -> {
            if( getConnectionHandler.failed() ) {
                return;
            }
            SQLConnection conn = connectionHandler.getConnection();
            conn.setAutoCommit( false, commitHandler -> {
                if(commitHandler.failed() ) {
                    conn.close();
                    return;
                }
                ......
                //트랜잭션 작업 실행
                          //실패시
                if ( completeHandler.failed() ) {
                        conn.rollback( rollbackHandler -> {
                            if( rollbackHandler.failed() ) {
                                                                 logger.info( "rollbackHandler.failed()" );
                            }
                            conn.close();
                        } );
                        return;
                }
                //성공시
                conn.commit( commitHandler -> {
                        conn.close();
                })  
......   
})

내부적으로는 setAutoComit(false)를 호출해 트랜잭션을 시작시킨 후에  본격적으로 DAO기능을 이용하기 시작한다.  동작 메소드 내부에서
이용하는 JDBCTemplete메소드에서는 가장 먼저 트랜잭션 동기화 저장소에 현재 시작된 트랜잭션을 가진 connection object가 존재하는지 확인한다. 
이미 저장해둔 connection이 있다면 이를 가져와 PreparedStatment를 만들고 수정 SQL을 실행한다.  실행이 끝난후 connection을 닫지 않은 채로 작업
을 마친다. 
  여전히 connection은 열려있고 트랜잭션은 진행중 인채로 동기화 저장소에 저장되어있다. 모든 작업이 완료되면 commit을 호출해서 트랜잭션을 완료시킨다. 그리고 close()를 호출한다.  

 이떄 한개의 트랜젝션안에 여러개의 DB에 데이터를 넣는 작업은 해야할때는 어떻게 해야 할까?
로컬 트랜잭션은 하나의 DB Connection에 종속된다. 따라서 별도의 트랜잭션 관리자를 통해 트랜잭션을 관리하는 글로벌 트랜젝션방식을 사용해야한다
자바는 하나이상의 DB가 참여하는 트랜잭션을 만들면 JTA를 사용해야한다. 그외 하버네이트를 이용해 트랜잭션을 관리 할수있다.
하지만 특정 트랜잭션 방법에 의존적이지 않고 독립적이게 만들 수 없을까?
 DB에서 제공하는 DB클라이언트 라이브러리와 API는 서로 호환되지 않는 독자적인 방식이다.  SQL을 이용하는 방식이라는 공통점으로 만
들어낸것이 JDBC이며 이 추상화된 기술로 DB의 종류에 상관없이 일관적으로 데이터에 엑서스 할수있다. 이것처럼 트랜잭션 처리코드에서 추상화가 도입될수있다. 

스프링은 데이터 엑서스 기술과 트랜잭션 서비스 사이의 종속성을 제거하고 스프링이 제공하는 트랜잭셔 추상 계층을 이용해서 서비스의 종류나 환경이 바뀌어도 트랜잭션을 사용하는 코드는 그대로 유지할 수 있는 유연성을 갖추고 있다.

 스프링의 트랜잭션 추상 인터페이스 : PlatformTransactionManager
 PlatformTransactionManager를 구현한 transactionManger를 주입하는 방식으로 사용한다. 

단일 책임 원칙 : 하나의 모듈은 한가지 책임을 가진다. 

PlatformTransactionManager은 트랜잭션의 경계를 지정(시작,종료, 종료시 정상, 비정상 판단)한다.
PlatformTransactionManager의 구현 클래스
-DataSourceTransactionManager 
  Connection의 트랜잭션 API를 이용해서 트랜잭션을 관리한다. 그리고 이 매니저를 사용하려면 빈에 등록되어있어야한다.
이 빈의 ref는 datasource id를 지정한다 
            -root-context.xml
       <bean id="dataSource" class="org.apache.tomcat.dbcp.dbcp.BasicDataSource" destroy-method="close">
             <property name="driverClassName"                                   value="#{contextProperties.driver}"/>
             <property name="url"                                               value="#{contextProperties.url}"/>
             <property name="username"                                          value="#{contextProperties.username}"/>
             <property name="password"                                          value="#{contextProperties.password}">
       </bean>
       <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
             <property name="dataSource" ref="dataSource"/>
       </bean>
        
       -contextProperties
        driver=oracle.jdbc.driver.OracleDriver
        url=jdbc:oracle:thin:@127.0.0.1:1521:XE
        username=user
        password=1234
        -service
        @Resource(name="transactionManager")
        private DataSourceTransactionManager transactionManager;

        DefaultTransactionDefinition defaultTransactionDefinition= new DefaultTransactionDefinition();
       /**
        * Set the name of this transaction. Default is none.
        * <p>This will be used as transaction name to be shown in a
        * transaction monitor, if applicable (for example, WebLogic's).
        */
       defaultTransactionDefinition.setName("insert tx");
       status = transactionManager.getTransaction(defaultTransactionDefinition);
       try{
           dao의 작업 
           transactionManager.commit( status );
       }catch{
           transactionManager.rollback( status );
       }

선언적 트랜잭션 
코드에서 실행하지않고 설정파일이나 어노테이션을 이용하여 트랜잭션의 범위, 롤백규칙을 정의한다.
트랜잭션은 전파방식, 격리수준, 읽기 전용, 타임아웃, 롤백규칙으로 정의된다. 

1.aop와 tx스카마 태그사용
트랙잰션 설정마다 변경이 필요없다. 
count 같은 쿼리를 만들때 읽기전용 속성을 메소드마다 추가해줘야하지만 tx 스키마 태그를 이용하면 한번에 처리가능하다.
       <tx:annotation-driven transaction-manager="transactionManager" />
       <tx:advice id="mybatis_txAdvice" transaction-manager="transactionManager">
             <tx:attributes>
                    <tx:method name="list*"                 read-only="true"  propagation="NOT_SUPPORTED"/>
                    <tx:method name="count*"                read-only="true"  propagation="NOT_SUPPORTED"/>
                    <tx:method name="insert*"               timeout="3" rollback-for="Exception"   propagation="REQUIRED"/>
                    <tx:method name="add*"                  timeout="3" rollback-for="Exception"   propagation="REQUIRED"/>
                    <tx:method name="update*"               timeout="3" rollback-for="Exception"   propagation="REQUIRED"/>
                    <tx:method name="delete*"               timeout="3" rollback-for="Exception"   propagation="REQUIRED"/>
             </tx:attributes>
       </tx:advice>

<aop:config>
<aop:pointcut id="mybatis_operations"  expression="execution( *com. *Dao.)"/>
<aop:advisor advice-ref="mybatis_txAdvice" pointcut-ref="mybatis_operations"/>
</aop:config>

2.@Transactional
1번과 같이 일괄적으로 적용하는 방식은 대부부 상황에 잘 들어맞는다. 하지만 클래스나 메소드마다 제각각 속성일 경우 이름 패턴을
통해 적용하는건 적합하지 않다. 이때 직접 타깃에 어노테이션을 사용한다.
<tx:annotation-driven> : @Transactional이 붙은클래스나 인터페이스 또는 메소드를 찾아 트랜잭션 advice를 적용한다
@Target( ElementType.METHOD, ElementType,TYPE}) : 사용할 대상지정, 메소드와 타입처럼 한개이상 지정가능
@Retention( RetentionPolicy.RUNTIME ) 애노테이션 정보가 언제까지 유지되는 지를 지정한다. 런타임때도 정보 얻을수 있다.
@Inherited 상속을 통해서도 애노테이션 정보 얻을 수 있다. 
public @interface Transactional {
Isolation isolation() default Isolation.DEFAULT;
boolean readOnly() default false;
}

@Transactional은 동시에 포인트컷의 자동등록에서 사용된다. 

DefaultTransaction이 구현하고 있는 TransactionDefinition 인터페이스는 트랜잭션의 동작방식에 영향을 줄수있는 네가지 속성을 정의하고 있다.

전파방식( PROPAGATION )
 -트랜잭션의 경계에서 이미 진행중인 트랜잭션이 있을때 또는 없을때 어떻게 동작할 것인가를 결정하는 방식 
 예를 들면 A의 트랜잭션이 시작돼서 진행중이라면 B의 코드는 어떤 트랜잭션에서 동작해야할까.. 그리고 어딘가에 참여하여 예외발생시 두 트랜잭션은
 어떻게 되는 것인가.
 getTransaction() 메소드는 항상 트랜잭션을 시작하는 것이 아니라 전파속성과 현재 진행중인 트랙잭션의 존재여부로 반환값을 정한다.

 -REQUIRED : default 이미시작된 트랜잭션이 있으면 없으면 새로 시작한다. 하나의 트랜잭션이 시작된 후에 다른 트랜잭션 경계가 설정된 메소드를 호출하면 자연스럽게 하나가 된다. (가장 많이 사용 default) A, B , A>B B>A 모두 가능하다. 
 -SUPPORTS : 이미 시작된 트랜잭션이 있으면 참여하고 없으면 없이 진행한다. connection, 하이버네이트는 공유가능하다.
 -MANDATORY : 이미시작된 트랜잭션이 있으면 없으면 예외발생, 
 -REQUIRES_NEW : 항상 새로운 트랙잭션 시작한다. 항상 독자적인 트랜잭션이다.
 -NOT_SUPPORTED : 사용하지않는다.( aop를 통해 한번에 적용하고 특정메소드가 적용되지않게 예외처리 )
 -NEVER : 트랜잭션을 사용하지 않도록 강제한다. 이미 진행중인 트랜잭션이 있다면 예외발생
 -NESTED : 이미 진행중인 트랜잭션이 있다면 중첩 트랜잭션을 사용한다. 독립된트랜잭션이 아닌 트랜잭션 안에 다시 트랜잭션을 만드는 것이다. 로그 트랜잭션과 메인 트랜잭션중 부모 자식관계를 만들어 로그는 실패해도 메인트랜잭션은 커밋될수있도록 함

격리수준( IOSLATION )
동시에 여러 트랜잭션이 진행될때 트랜잭션이 작업결과를 다른 트랜잭션에게 어떻게 노출할 것인지 결정
 -DEFAULT : 사용하는 데이터엑서스 기술에 따름 
 -READ_UNCOMMITTED : 하나의 트랜잭션이 커밋되기전에 그 변화가 다른 트랜잭션에 노출 , 빠르나 데이터 일관성이 떨어짐
 -READ_COMMITTED :  많이 사용되는 격리수준,  커밋하지 않으면 정보를 읽어올수없다.  하지만 읽는 로우는 다른 트랜잭션이 수정가능하다.  SELECT이후 변경된 ROW 가능
 -REPEATABLE_READ : 읽은 로우를 다른 트랙잭션이 수정할수없다 하지만 추가는 가능하다. SELECT이후 추가된 ROW가능
 -SERIALIZABLE : 동시에 같은 테이블 접근 불가능. 격리수준은 높으나 성능이 가장 떨어지므로 극단적인 안정작업만 추천

제한시간( TIME OUT )
-제한시간을 지정하여 예외 발생가능, 기본설정은 없다. 

읽기전용( READ-ONLY )
-읽기전용으로 쓰기 방지

트랜잭션 정의를 수정하려면 TransactionDefinition 오브잭트를 생성하고 사용하는 코드는 트랜잭션 경계설정 기능을 가진 TransactionAdvice다.
하지만 이 속성을 변경하면 모든 트랜잭선이 변경된다. 
원하는 메소드만 선택하여 정의를 변경할수있다. 어드바이스의 기능을 확장하면 된다. 
메소드 이름 패턴에 따라 다른 트랜잭션 정의가 적용되도록 만들면 되는데 TransactionInterceptor를 사용한다.

<tx:advice> : TransactionInterceptor 빈이 등록된다. 
<tx:attributes> :  개별 어트리뷰트를 등록하여 지정할수있다. 
롤백 예외
-런타임 예외시 롤백한다. 
-런타임 예외시 말고 롤백이 필요하다면 rollback-for, rollbackForClassName을 사용한다. 


참고: 토비의 스프링














'STUDY > SPRING' 카테고리의 다른 글

DATA Access  (0) 2018.11.08
Aspect Oriented Programming  (0) 2018.11.06
MVC  (0) 2018.11.02
[코드로 배우는 스프링 웹프로젝트]  (0) 2018.10.31
Annotation  (0) 2018.10.30


실행순서 
    0.Filter 모든 요청에 걸러져서 dispatcherServlet으로 들어간다. 
    1.웹 브라우저를 통해 클라이언트 요청이 dispatcherServlet에게 들어온다. 
    2.dispatcherServlet은 HandlerMappging에게 어떤 컨트롤러가 처리할지 결과를 받아온다.
    3.HandlerAdapter는 DispatcherServlet의 처리 요청을 변환해서 컨트롤러에게 전달하고 컨트롤러의 응답 결과를 DispatcherServlet 요구하는 결과 방식으로 변환한다. 
      웹 브라우저, 캐시들도 설정한다.
    4.Controllers는 클라이언트 요청을 처리한 뒤 결과를 DispatcherServlet에게 리턴한다. 
    5.HandlerAdapter는 controller의 실행결과를 ModelAndView로 변환해서 DispatcherServlet에게 리턴한다. 
    6.DispatcherServlet은 viewResolver에게 컨트롤러의 처리결과를 보여줄 view를 결정한다. 
    7.해당 view에게 처리결과 화면을 생성한다. jsp나 velocity 탬플리 파일을 이용해 응답 결과를 전송한다. 

1.Filter
- 공통적인 업무(로그인, 로그, 권한체크...)를 할때 공통관심으로 분리하는데 이떄 사용할 수 있는 것이 서블릿 필터,스프링 프레임워크를 사용하면 interceptor, AOP가 있다.  
이 세가지의 실행시점은 서버실행시 서블릿이 올라오는 동안 init이 실행되고 filter가 실행,  컨트롤러가 실행되기전에 intercepter의 preHandler, 그리고
AOP의 작업 후에 역으로 postHandler, atfer Completion, filter로 진행되고  destory 된다. 
 init(), doFilter(), destory()
필터는 스프링과 무관하게 지정된 자원에 대해 동작한다.  즉 스프링 외부에 존재한다. 
그래서 servlet에서 처리하기 전후에 사용되기 편하며 servletRequest 혹은 response를 교체하는것이 가능하다. 
web.xml에 설정한다. 
*interceptor의 차이점
실행시점에 속하는 영역(Context)이다. intercepter는 스프링내부에 존재하며 dispatcherServlet이 컨트롤 호출 전후로 작동한다.
preHandler(), postHandler(), afterCompletion()
예외처리가 spring annotation으로 작동하므로 관리의 편의성이 있다. 
     <mvc:interceptors>
             <mvc:interceptor>
                    <mvc:mapping path="/**"/>
                    <bean class="className"/>
             </mvc:interceptor>
     </mvc:interceptors>

*AOP와 interceptor의 차이점
spring의 AOP은 joinPoint등을 활용해서 호출대상이 되는 메소드의 파라미터를 받는 구조이나 intercepter는 filter와 유사하게 HttpServletRequest, httpServletRequest로 파라미터를 받는 구조이다. 
포인트 컷으로 @after, @Before.... 
예외처리가 spring annotation으로 작동하므로 관리의 편의성이 있다. 
    <filter>
             <filter-name>encodingFilter</filter-name>
              <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
             <init-param>
                    <param-name>encoding</param-name>
                    <param-value>UTF-8</param-value>
             </init-param>
    </filter>
    <filter-mapping>
            <filter-name>encodingFilter</filter-name>
            <url-pattern>/*</url-pattern>
    </filter-mapping>

2.dispatcherServlet 
컨테이너를 생성한다.
web.xml을 먼저 읽어와  [서블리이름]-servlet.xml 파일의 정보로 설정한다. 이떄 servlet.xml 형식이 아닌 다른 파일을 사용했다면 contextConfigLocation 태그로 설정을 변경하며
xml이 아닌 annotation(@Configuration)으로 설정했다면 contextClass를 AnnotationConfigWebApplicationtext를 xml에 추가해주고 contextConfigLocation에 해당 시작 클래스를 등록해야한다. 
   <servlet>
             <servlet-name>dispatcher</servlet-name>
              <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
             <init-param>
                    <param-name>contextConfigLocation</param-name>
                    <param-value>classpath:spring/context-*.xml</param-value>
             </init-param>
             <load-on-startup>1</load-on-startup>
   </servlet>
3.handlerMapping & handlerAdapter
스프링은 Url이 들어오면 어떤 컨트롤러 오브젝트가 이를 처리하게 할지 매핑해주는 전략을 만들어 DI로 제공한다.
 오브젝트 어댑터 패턴을 사용해서 특정 컨트롤러를 호출해야 할때는 해당 컨트롤러 타입을 지원하는 어댑터를 중간에 껴서 호출하는것이다.  DIspatcherServlet은 컨트롤러가 어떤 메소드를 가졌고 어떤 인터페이스를 구현했는지 전혀 알지못한다. 대신 컨트롤러의 종류에 따라 적절한 어뎁터를 사용한다. 이렇게 하면 하나의 dispatcherServlet이 동시에 여러가지 타입이 컨트롤러를 사용할수있다. 

dispathcherServlet은 컨트롤러를 직접 실행하지 않고 HandlerAdapterf를 사용하여 간접적으로 컨트롤러을 실행하는데 실제 반환하는 핸들러의 객체 타입이 무엇인지 신경쓰지않는다. ModelAndVIew가 아닌 string 타입이 될수도 있다. 이때 중간에서 string을 modelAndview로 변경해주어야 하는데 그때 사용되는 것이 HandlerAdapter이다 
<mvc:annotatinon-driven>설정이나 @EnaleWebMvc 애노테이션을 사용하면 handlerMapping과 HandlerAdapter를 등록한다.
 RequestMappingHandlerMapping  : @controller 적용 빈객체를 핸들러로 사용하는 HandlerMapping구현, 적용 우선순위가 높다.
 SimpleUrlHandlerMapping :  <mvc:default-servlet-handler> <mvc:view-controller> <mvc:resources> 태그 사용 
 RequestMappingHandlerAdapter:  RequestMappingHandlerMapping 에 대한 어뎁터
 HttpRequestHandlerAdaper: HttpRequestHandler에 대한 어뎁터
 SimpleControllerHandlerAdapter: Controller 인터페이스를 구현한 객체에 대한 어뎁터 

4.viewResolver
컨트롤러가 지정한 뷰이름으로부터 응답 결과 화면을 생성하는 view객체를 구현할때 사용 
주요 구현클래스
  internalResourceViewResolver  / velocityViewResolver / velocityLayoutViewResolver / BeanNameViewResolver 
  servlet-context.xml 의 internalResourceViewResolver 
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
     <beans:property name="prefix" value="/WEB-INF/views/" />
     <beans:property name="suffix" value=".jsp" />
</beans:bean>
 servlet-context.xml 의 BeanNameViewResolver 
 bean에서 BeanNameViewResolver 등록하고 bean의 id가 download인 클래스를 등록하면 
 return new ModelAndVIew( "download", "downloadFile", downloadFile )이 실행가능하다. 
 이름이 download인 DownloadVIew객체를 뷰로 검색하며 DIspatcherServlet은 downloadView를 이용해 DownLoadController의 처리결과를 출력하게 된다. 
 다수의 viewResolver는 우선순위 설정할것
      <bean id="internalResource" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
             <property name="prefix" value="/application/" />
             <property name="suffix" value=".jsp" />
             <property name="order" value="2"/>
      </bean>
      <bean id="multipartResolver"  class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
 <property name="order" value="1"/>
      </bean>
order이 작을수록 우선순위가 높으며 우선순위가 높은 viewResolver가 null을 리턴하면 다음 우선순위를 찾는다. 이떄 internalResoureceviewResolver는 항상 뷰 이름에 매핑되는 뷰 객체를 리턴하기때문에 null을 리턴할수없다. internalResoureceviewResolver후에 지정된 viewResolver는 탐색하지않고 없을경우 404에러를 출력한다. 따라서 internalResoureceviewResolver는 마지막 우선순위를 지정하도록 해야한다. 

뷰 생성까지 모든 작업을 마쳤으면 dispatchServlet은 HttpServletResponse에 담긴 최종 결과를 서블릿 컨테이너에게  돌려준다.
그리고 이 컨테이너는 httpServletResponse에 담긴 정보를 Http응답으로 만들어 사용자의 브라우저나 클라이언트에게 전송하고 작업을 종료한다. 












'STUDY > SPRING' 카테고리의 다른 글

Aspect Oriented Programming  (0) 2018.11.06
TRANSACTION  (0) 2018.11.06
[코드로 배우는 스프링 웹프로젝트]  (0) 2018.10.31
Annotation  (0) 2018.10.30
스프링 컨테이너와 빈  (0) 2018.10.30
목적: spring 프로젝트를 정리하기 위한 글로 포인트 개념만 정리 
기간: 학습기간 2주 ( 2018.10.28 - 2018.11.11 )
 1주: 책을 위주로 정리 및 프로젝트 완성
 1주: 실제 서비스중인 프로젝트를 바탕으로 업그레이드 기술 분석 및 비교   
* 코드로 배우는 스프링 웹 프로젝트( 저자 구멍가게코딩단 ) 도서는 코드 위주의 진행이라 개념이 부족하므로 
   보충 도서로 spring 4.0 프로그래밍( 저자 최범균 ) 도서로 개념을 추가 설명


'STUDY > SPRING' 카테고리의 다른 글

TRANSACTION  (0) 2018.11.06
MVC  (0) 2018.11.02
Annotation  (0) 2018.10.30
스프링 컨테이너와 빈  (0) 2018.10.30
[코드로 배우는 스프링 웹프로젝트] PART 1. 프로젝트의 기본구조 구성  (0) 2018.10.29


1. <context:componet-scan>

context: componet-scan base-package="com.controller"
특정 패키지안의 클래들을 스캔하고 빈 인스턴스를 생성한다. 
base-package 패키지의 내의 클래스들을 스캔하며 아래 어노테이션을 찾는다.
스캔을 통해 빈이 등록될 경우 자동 의존 설정이 필요하다. 
@Component
@Repository( ddd에서의 Repository )
@Service ( ddd에서의 Service )
@Controller 
@required
@configuration : 여러 클래스에 빈 정보를 나누어 설정 할 수 있다. 

 context:component-scan은 암시적으로  context:component-config를 호출하여 Bean에 대한 주석을 활성화한다. 


 


2.<mvc: annotation-driven>
스프링  mvc컴포넌트들은 그것을 디폴트 설정을 가지고 활성화 하기 위해 사용된다. 
context:component-scan을 사용하면 빈을 생성하기 위해 mvc:annotation-driven을포함시키지 않아도 mvc어플리케이션은 잘 동작한다. 
하지만 이 태그를 사용함으로써 @Controller에게 요청을 전파하기위해 요구되는 HandlerMapping와 HandlerAdapter를 등록한다.  게다가 클래스 패스상에 존재하는 디폴트작업들을 한다. 
  • Using the Spring 3 Type ConversionService as a simpler and more robust alternative to JavaBeans PropertyEditors
  • Support for formatting Number fields with @NumberFormat
  • Support for formatting Date, Calendar, and Joda Time fields with @DateTimeFormat, if Joda Time is on the classpath
  • Support for validating @Controller inputs with @Valid, if a JSR-303 Provider is on the classpath
  • Support for reading and writing XML, if JAXB is on the classpath
  • Support for reading and writing JSON, if Jackson is on the classpath
이 태그를 사용하지않으면 xml에서 bean으로 RequestMappingHandlerMaggping , RequestMappingHandlerAdapter를 등록해주어야한다. 
 
-<mvc:default-servlet-handler>
  jsp와 특정확장자를 가진 URL말고는 모두 dispatchServlet이 다 받는다. 등록된 핸들러 매핑 전략을 이용해 컨트롤러 매핑에서 찾는다.  담당하는 URL은 컨트롤러로 넘어가나 /js/jquery.js 처럼 매핑안되는 url은 DefaultServletHttpRequestHandler이 담당한다. 이 컨트롤러는 /**로 매핑되어있다. 그리고 default라 우선순위가 제일 낮다. 사실 DefaultServletHttpRequestHandler는 서버가 제공하는 디폴트 서블릿으로 넘기는 작업을 하는데 이떄 스프링이 처리못하는 URl을 담당한다 
디폴트 서블릿은 서버마다 이름이 다르다.톰캣, 제티는 이름이 default, Resin은 resin-file, WebLogic은 FileServlet, WebSphere는 SimpleFileServlet이다
annotation-driven 태그가 등록하는 RequestMappingHandlerMapping의 우선순위가 default-servlet-handler 태그가 등록하는 simpleUrlHandlerMappging의 우선순위보다 높다. 
RequestMappingHandlerMapping 다음 SimpleUrlHandlerMappging 확인한다. 

3.<context : annotation-config>
= bean class : Autowire , Common , Qualifier + AnnotationBeanPostProcecssor

어플리케이션 컨텍스트안에 이미 등록된 빈의 어노테이션의 활성화를 위해 사용된다. 

@Autowired : 의존개체를 자동설정할때 타입을 이용하여 의존하는 객체를 주입한다. 설정위치는 생성자, 필드, 메소드이며 null값 유지시 required = false
@Qualifier :  @Autowired과 함께 사용된다. 동일타입 빈객체에 value 부여로 구별할수있다.
@Resource : @Autowired과 같은역할이지만 @Autowired는 타입으로 @Resource는 이름으로 연결한다. 설정위치는 프로퍼티, setter메소드이다.
 속성의 name은 빈객체의 이름이며 name 지정없을경우 필드이름이나 프로퍼티 이름을 사용한다. 
@postConstruct  의존하는 객체의 초기화  CommonAnnotationBeanPostProcessor 클래스를 빈으로 등록시켜줘야 한다
@PreConstruct  컨테이너에서 객체를 제거하기 전에 해야할작업을 수행하기 위해 사용된다. 
@inject  +  @named:  @Autowired은 required속성을 이용해서 필수 여부를 지정할 수 있는 것과 달리 inject 애노테이션은 반드시 사용할 빈이 존재해야한다. 












'STUDY > SPRING' 카테고리의 다른 글

TRANSACTION  (0) 2018.11.06
MVC  (0) 2018.11.02
[코드로 배우는 스프링 웹프로젝트]  (0) 2018.10.31
스프링 컨테이너와 빈  (0) 2018.10.30
[코드로 배우는 스프링 웹프로젝트] PART 1. 프로젝트의 기본구조 구성  (0) 2018.10.29

container

1.스프링 컨테이너(Bean Factory)
빈객체를 관리하고 각 객체가 의존관계를 설정해주는 컨테이너 
대표적 구현클래스 : XmlBeanFactory
외부 자원으로부터 설정정보를 읽어와 빈 객체를 생성함 

2.스프링 컨테이너(ApplicationContext)
BeanFatory 인터페이스를 상속받은 하위 인터페이스
메세지의 국제화 , 리소스의 관리 및 로딩, 이벤트 처리 
대표적 구현클래스 : GenericXmlApplicationContext
이객체들은 context.getBean()로 가져올수있다. 
Beanfatory는 단순히 컨테이너 객체를 생성하고 DI를 처리해주는 기능을 제공한다. 하지만 스프링을 사용하는 이유는 다양한 부가기능(편리한 트랜잭션, 자바 코드기반 스프링 설정, 애노테이션을 사용한 빈설정, 메시지 처등 ) 때문이다. 그리고 이런 기능을 사용하기 위해선 beanfatory만 사용하는 것은 매우 드물며 applicationContext계열을 사용한다. 

applicationContext 인터페이스와  관련된 클래스 계층 구조에서 제일 하단의 것으로 실제 사용되는 클래스 목록이다.
-GenericXMLApplicationContext : XML파일을 설정 정보로 사용하는 스프링 컨테이너 구현 클래스이다. 독립형 어플리케이션을 만들때 사용한다. 3.0부터 추가되었으며 그전에는 classPathXmlApplication(클래스패스에서 설정파일을 읽어온다) + FileSystemXmlApplicatio(로컬파일에서 설정파일을 읽어온다 )이 대신함 
-AnntationConfigApplicationContext: 자바코드를 설정 정보로 사용하는 스프링컨테이너 
-GenericGroovyApplicationContext: 그루비 언어로 작성될 설정정보를 사용하는 스프링컨테이너
-XmlWebApplicationContext: 웹 어플리케이션을 개발할때 스프링 컨테이너로써 xml파일을 설정 정보로 사용한다.
-AnnotationConfigWebApplicationContext: 웹 어플리케이션을 개발할때 사용하는 스프링 컨테이너 

3.스프링 컨테이너(WebApplicationContext)
모든 클래스 파일이 이 부분에 올라가는 것이 아닌 context-scan 관련 어노테이션 클래스파일만 업로드되어 객체가 생성된다. 
이 객체들을  getBeanDefinitionNames();로 가져올수있다.
dispatcherServlet이 xx-servlet.xml을 읽어와 webApplicationContext를 만든다. 나머지 설정 xml파일은 contextLoadListener또는 
ContextLoaderServlet이 webapplication을context를 만들때 사용한다.
이 webapplicaionContext는 applicationContext를 상속받아 여러 서블릿이 공통으로 사용하는 빈들을 사용할수 있게 된다. 
그렇기 때문에 만들어지는 순서가 중요하다. 
ContextLoaderServlet을 사용했을 때는 load의 설정 값을 1을 주어 ApplicationContext를 DispatcherServlet보다 먼저 만드다. 
이 설정을 하는 이유는 DispatcherServlet이 하나의 Web Application에 여러개일 수 있기 때문이다.
여러 개의 DispatcherServlet에서 공통으로 사용할 빈들을 상위 ApplicationContext에 선언해두어 공유할 수 있게 하는 것이다.

컨테이너의 생성과 종료 
-컨테이너 생성
-빈 메타정보(xml이나 자바기반설정)를 이용해서 빈 객체 생성
xml 
GenericXmlApplication ctx = new GenericXmlApplication();
ctx.load( "classpath:config.xml" ); // 메타 정보 제공 및
ctx.refresh(); //읽어온 메타정보로 빈 객체 재생성
java
GenericXmlApplication ctx = new GenericXmlApplication();
ctx.register( config.class )
ctx.refresh(); 
refresh는 초기화 과정이기도 하므로 반드시 실행되어야한다. 
-컨테이너 사용
-컨테이너 종료 
일반적으로 close()를 호출하지만 강제종료일때 registerShutdownHook()을 사용한다. 

bean

스프링 컨테이너는 빈객체를 생성하고 초기화하고 소멸한다. 
그리고 그 단계마다 빈  객체의 매서드를 실행한다. 
1.빈객체 생성
2.빈 프로퍼티 설정
3.BeanNameAware.setBeanName() //빈생성시 컨테이너에서 빈이름을 전달받는다. 
4.ApplicationContextAware.setApplicationContext() //빈생성시 컨테이너를 전달 받는다. >> 컨테이너 기능 사용가능 
5.BeanPostProcessor의 초기화 전처리
6.초기화 
6-1.@postConstruct
6-2.InitializingBean.atferPropertiesSet()
6-3. 커스텀 init 메서드
7.BeanPostProcessor의 초기화 후 처리 
8.빈객체의 사용
9.소멸
9-1.@preDestory 메서드 
9-2.DisposableBean.destory()
9-3.커스텀 destory 메서드 
*<context:annotation-config>를 사용하면 CommonAnnotationBeanProcessor가 빈으로 등록되면서 초기화,소멸 ( 6-1, 9-1 )사용가능

*커스텀 메소드는 bean태그에서 init-method , destory-method를 사용하면 된다. 




'STUDY > SPRING' 카테고리의 다른 글

TRANSACTION  (0) 2018.11.06
MVC  (0) 2018.11.02
[코드로 배우는 스프링 웹프로젝트]  (0) 2018.10.31
Annotation  (0) 2018.10.30
[코드로 배우는 스프링 웹프로젝트] PART 1. 프로젝트의 기본구조 구성  (0) 2018.10.29

[part. 1 프로젝트의 기본 구조 구성]

1.개발 환경 설정 <page 26>
-sts 설치 / 이클립스( 메이븐 프로젝트 )
-스프링 프로젝트
 Spring Starter Project(Spring Boot) :
 별도의 설정이 없으며 was없이 실행가능하다. / jsp설정은 별도로 해야한다.
 Spring Project :
 현재 실무에서 많이 사용하고 있으며 모든 버전이 스프링에서 사용할수 있으나 초반 테스트 환경 구현이 어렵고  was와 연동하는 경우 리소스 추가요구된다.
이책은  Spring Project 로 Spring Legacy project 를 사용한다.
sts >> file > new project > Spring Legacy project > spring MVC project
-maven : poem.xml의 dependency 부분 확인할것 (.m2)
-tomcat 9.0 / java 1.8 / mysql 6.3.9 / mybatis 

2.스프링의 간단한 소개 <page 49>
-프레임워크
   뼈대가 완성, 조립식 가능 
-POJO기반구성
   엔터프라이즈급 프로젝트 시스템의 복잡성으로 인한 실패 >> 이로 인해 만들어진 경량 프레임워크로 관계시  apI를 사용하지 않는 POJO의 구성으로 가능하도록 제작되었음 >> 유연성, 확장성, 디커플링
-의존을 통한 객체 간의 관계 구성
   DI(Dependency injection ) 의존
      외부에서 필요한 객체를 직접 결정하기 때문에 의존 관계를 직접 처리할 필요없고 인터페이스를 통해 유연
      한 구조 개발 가능(생성자, set메소드)
      객체를 생성하면 각 객체를 연결해주는 조립기 역할을 한다.: GenericXmlApplicationContext클래스가 xml 파일의 설정정보를
      읽어와 객체를 생성하고 연결한뒤 내부적으로 보관한다. 이렇게 생성한 객체를 보관하기 때문에 컨테이너라고 부른다. 그리고 이 
      생성된 객체들을 빈이라고 부른다. 
   IoC( Inversion of Control )  제어의 역행
      메소드나 객체의 호출작업을 외부에서 결정 >> 프레임워크에  필요한 부품을 만들고 조립가능 >> 구조를       설계할수있도록 만들어짐 
-AOP(Aspect oriented Programming)
  비즈니스 로직(core-concern)에만 집중할수있도록 횡단 관심사(cross-concern  ex 로깅, 트랜잭션)를 분리

3.예제를 위한 MySQL의 설정과 스프링테스트

4.스피링 + MyBatis + Mysql 설정

5.모델 2방식의 스프링 MVC
<목요일 진행예정>

controller  <page 105>

리다이렉트 경우 파라미터 RedirectAttributes 로 받아 속성 addFlashAttribute를 사용한후 

리턴을 return "redirect: /@RequestMapping사용

JSON 데이터를 생성하는 경우 리턴타입 @ResponseBody 클래스 반환 


6.스프링 + Mybatis <page 126>

-mysql : book_ex스키마에 tbl_member 생성

create table tbl_member (
    userid varchar(50) not null,
    userpw varchar(50) not null,
    username varchar(50) not null,
    email varchar(100),

    regdate timestamp default now(),
    updatedate timestamp default now(),
    primary key(userid)
)

timestamp 사용시 서버시간 UTC 기준이므로 timezone 유의

 -도메인 객체를 위한 클래스 설계 

도메인 :  분리가 가능한 단위 

-DAO인터페이스 작성

-XML Mapper작성

참고사이트 http://www.mybatis.org/mybatis-3

-mybatis-spring에서 xmlMapper인식 

-DAO인터페이스 구현

  sqlSessionTemplete : mybatis의 데이터베이스의 연결을 맺고 작업이 완료된 후 작업을 close 하는 클래스

SqlSessionTemlate은 sqlSessionFactory를 생성자로 주입해서 설정한다. 


첨부파일은 <page 138>까지 실행한 프로젝트 

ex_0.zip


트러블슈팅

에러 : Access denied for user 'zerock'@'localhost'

이유 : mysql 외부 접속 권한 없어 root-context.xml의 dataSource bean을 생성하지못함

해결 : 사용자계정에 권한부여  참고 사이트 : http://withcoding.com/36 




'STUDY > SPRING' 카테고리의 다른 글

TRANSACTION  (0) 2018.11.06
MVC  (0) 2018.11.02
[코드로 배우는 스프링 웹프로젝트]  (0) 2018.10.31
Annotation  (0) 2018.10.30
스프링 컨테이너와 빈  (0) 2018.10.30

+ Recent posts