[하이버네이트 VS JPA] 객체 다루기

JPA를 언젠간 써야 할텐데 아직도 하이버네이트가 그냥 편해서… @_@;; 암튼 이 둘은 객체를 다루는 API가조금 다른데 그걸 정리해둡니다.

 하이버네이트(Session) JPA(EntityManager) 설명 
save() persist()  저장(정확하게는 Pesistent 상태로 변경) 
 get() find()  DB에서 가져오기 
 load()  getReference() 프록시 가져오기 
 delete() remove()  삭제(정확하게는 Deleted 상태로 변경) 
update()  없음  reattach 다시 부착하기(정확하게는 Detached 상태에서 Persistent 상태로 변경) 
 merge() merge()  merge 병합하기(get() 해온 다음에 Detached 객체의 상태를 복사해간다. 
왠지 CRUD가 다 있어 보이지만 사실 아래 두 줄은 Update 관련 API가 아니라 Detached 상태의 객체를 Persistent 상태로 만들기 용 메서드가 뭐 이것들을 이용해서 Detached 상태 객체를 DB에 반영해서 Update 쿼리를 발생시킬 수도 있지만.. 사실 진정한 Update는 API로 존재하지 않는다. 
즉.. Persistent 상태의 객체를 가지고 어떤 속성을 변경했다 치자.. 이때 굳이 어떤 API를 써서 Update 문을 발생시키지 않아도 된다는 것이다. 
Session session = getSession(); 
Transaction tx = session.beginTransaction(); 
Book book = (Book) session.get(Book.class, 12); 
book.setName(“토비의 스프링 3”); 
tx.commit(); 
session.close(); 
저렇게 변경하고 아무것도 실행하지 않는다. 왜일까? 퀴즈닷.

토비의 스프링 3

드디어 나왔네요. (사실 예판 시작한지는 꽤 됐는데 제가 블로깅을 깜빡하고 있었네요.ㅋㅋ 이미 한 줄 알았어요.) 제가 쿨하지 못해서 결국 제 추천사도 들어갔습니다. 온라인 서점에는 제 추천사를 볼 수 없지만 책을 사시면 제 추천사도 들어있을 겁니다. 캬캬캬.
날씨도 덥고 휴가철이라 공부하기 많이 힘드실 겁니다. 그런데 사실 이럴때가 더 공부하기 좋은 때 입니다. 남들이 덥다고 놀고 지쳐있을 때.. 그럴 때 꾸준하게 달리면.. 두배나 빠르게 달리는 거나 마찬가지 거든요. 마침 다음주부터 매주 토요일 4주 과정으로 한빛교육센터에서 이 책으로 강의를 시작합니다.
강의를 들으시는 분들께는 교재삼아 ‘토비의 스프링 3’이 지급될 겁니다. 교재비는 따로 내는 것 같진 않더군요. 무더운 스프링을 토비의 스프링 3으로 이겨내시죠. 이열치열삼아…

[Spring BlazaDS Integration 레퍼런스] 3장 스프링 빈을 플렉스 리모팅용으로 공개하기

참조: http://static.springsource.org/spring-flex/docs/1.5.x/reference/html/index.html#introduction


3.1. 도입

스프링이 관리하는 MessageBroker 는 플렉스 클라이언트가 스프링 빈을 리모팅 호출할 수 있는 형태로 손쉽게 공개할 수 있게 해준다. 이 방법은 스프링 프레임워크가 제공하는 다른 리모팅 기술과 매우 유사한 방법이다. 리모팅은 기존의 스프링 빈을 마치 외부 설정 용으로 만들어 준다. MessageBroker 는 플렉스 AMF 데이터 형식과 자바 사이의 직렬화 및 역직렬화를 투명하게 처리해준다.


3.2. 리모팅 서비스 설정

BlazeDS RemotingService 는 BlazeDS XML 설정에 있는 remoting-config.xml을 추가할 때동으로 설정된다. 스프링이 관리하는 리모팅 목적지 만을 사용할 때는 이 설정 파일 없이 스프링 설정 파일에 message-broker 태그를 추가하면 감각적인 기본값에 의해 RemotingService 가 설정된다. 그 결과 BlazeDS 설정에 remoting-config.xml에 다음과 같이 설정하는 것과 같은 것이다.

<?xml version=”1.0″ encoding=”UTF-8″?>

<service id=”remoting-service”

    class=”flex.messaging.services.RemotingService”>

    <adapters>

        <adapter-definition id=”java-object” 

            class=”flex.messaging.services.remoting.adapters.JavaAdapter” 

            default=”true”/>

    </adapters>

    <default-channels>

        <channel ref=”my-amf”/>

    </default-channels>

    

</service>    

    

이것은 애플리케이션 수준의 default-channels 설정이 있다고 가정한다는 것을 알아두자. 애플리케이션 수준 기본 설정에 의존하지 않는다면 원하는 서비스 관련 채널을 설정하는 것을 추천한다(아래 예제 처럼). 만약 애플리케이션 수준 기본값이 없다면, AMFEndpoint 를 사용하는 MessageBroker 에서 사용할 수 첫번째 가용 채널을 RemotingService의 기본값으로 설정한다.

만약 RemotingService에 설정되는 기본값을 더 명시적으로 제어하고 싶다면 message-broker 태그의 remoting-service remoyou하위 엘리먼트를 사용해서 설정할 수 있다. 

<flex:message-broker>

<flex:remoting-service default-adapter-id=”my-default-remoting-adapter” 

    default-channels=”my-amf, my-secure-amf” />

</flex:message-broker>

만약 레거시 BlazeDS 애플리케이션의 기존 remoting-config.xml이 있다면  RemotingDestinationExporter가 투명하게 모든 스프링이 관리하는 리모팅 목적지로 이전하게 해준다.

3.3. remoting-destination 태그 사용하기

remoting-destination 설정 태그는 기존에 스프링이 관리해주고 있는 서비스를 플렉스 클라이언트에서 직접 리모팅 할 수 있도록 해준다. 다음 스프링 빈 설정은 productService 빈을 설정하고 있다.

    

<bean id=”productService” class=”flex.samples.product.ProductServiceImpl” />

    

그리고 message-broker 태그를 설정하여 스프링이 관리하는 MessageBroker가 있다고 가정하겠다. 이때 다음의 최상위 remoting-destination 태그가 productService라는 서비스 목적지를 플렉스 클라이언트가 리모팅할 수 있게 공개해준다. 

<!– Expose the productService bean for BlazeDS remoting –>

<flex:remoting-destination ref=”productService” />

    

기본으로 플렉스 클라이언트에 공개되는 리모트 서비스 목적지는 목적지의 서비스 id로 빈 이름을 사용하는데 이 값을 remoting-destination 태그의 destination-id 애트리뷰트로 재정의할 수 있다. 

remoting-destination 태그를 사용하는 방법의 대안으로 bean 정의의 하위 엘리먼트를 사용하는 방법이 있다. 도메인 계층 빈 설정과 플렉스 리모팅 같은 기반 관련 설정을 분리할 필요가 없을 때 사용할 수 있다. (분리하는 것이 테스트를 더 편하게 할 수 있다는 것을 명심하자.) 다음과 같은 설정은 위와 동일한 결과를 가져다준다.

    

<bean id=”productService” class=”flex.samples.product.ProductServiceImpl” >

<flex:remoting-destination />

</bean>

    

플렉스 클라이언트가 호출할 수 있는 메서드를 remoting-destination 태그의 include-methods와 exclude-methods 애트리뷰트를 사용해서 보다 엄격하게 관리할 수 있다. 목적지를 공개할 BlazeDS 채널은 channels 애트리뷰트를 사용해서 제어할 수 있다. (최상위 엘리먼트로 사용하든 내부 엘리먼트로 사용하든 이 애트리뷰트를 사용할 수 있다.) 좀 더 커스터마이징한 예제는 다음과 같다.

<flex:remoting-destination ref=”productService” 

    include-methods=”read, update” 

    exclude-methods=”create, delete” 

    channels=”my-amf, my-secure-amf” />

    

remoting-destination 태그는 공개하는 빈 마다 투명하게 RemotingDestinationExporter 빈 인스턴스를 등록해 준다. 네임스페이스를 사용하지 않고 빈 설정을 하면 다음과 같다.

<!– Expose the productService bean for BlazeDS remoting –>

<bean id=”product” class=”org.springframework.flex.remoting.RemotingDestinationExporter”>

    <property name=”messageBroker” ref=”_messageBroker”/>

    <property name=”service” ref=”productService”/>

    <property name=”destinationId” value=”productService”/>

    <property name=”includeMethods” value=”read, update”/>

    <property name=”excludeMethods” value=”create, delete”/>

    <property name=”channels” value=”my-amf, my-secure-amf”/>

</bean>


3.4. @RemotingDestination 사용해서 리모팅 빈 공개하기

@RemotingDestination 애노테이션은 XML 리모팅-목적지 태그 대안으로 사용할 수 있다. @RemotingDestination 은 클래스의 타입에 사용하여 해당 빈을 공개할 수 있다. @RemotingInclude@RemotingExclude를 메서드에 사용하여 해당 메서드를 리모팅에 포함할지 제외할지 설정할 수 있다. 

다음 예제는 productService 빈을 애노테이션으로 리모팅 설정한 예에 해당한다.

package flex.samples.product;

import org.springframework.flex.remoting.RemotingDestination;

import org.springframework.flex.remoting.RemotingExclude;

import org.springframework.flex.remoting.RemotingInclude;

import org.springframework.stereotype.Service;

@Service(“productService”)

@RemotingDestination(channels={“my-amf”,”my-secure-amf”})

public class ProductServiceImpl implements ProductService {

@RemotingInclude

public Product read(String id) {

}

@RemotingExclude

public Product create(Product product){

}

@RemotingInclude

public Product update(Product product){

}

@RemotingExclude

public void delete(Product product) {

}

}

    


[Spring BlazaDS Integration 레퍼런스] 2장 스프링에서 BlazeDS MessageBroker 설정 및 사용

참조: http://static.springsource.org/spring-flex/docs/1.5.x/reference/html/index.html#introduction


2.1. 도입

스프링 BlazeDS Integration을 사용할 때 반드시 설정해야 하는 핵심 요소는 MessageBroker다. 플렉스 클라이언트에서 발생한 HTTP 메세지는 스프링 DispatcherServlet 을 통해 스프링이 관리하는 MessageBroker로 전달된다. 스프링이 관리하는  MessageBroker를 사용할 때는 BlazeDS MessageBrokerServlet 을 설정할 필요 없다.

2.2. 스프링 DispatcherServlet 설정

스프링 WebApplicationContext의 시작점(bootstrap)으로 보통 web.xml에 DispatcherServlet 을 다음과 같이 설정한다.

<!– The front controller of this Spring Web application, responsible for handling all application requests –>

<servlet>

    <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>

    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

    <init-param>

        <param-name>contextConfigLocation</param-name>

        <param-value>/WEB-INF/config/web-application-config.xml</param-value>

    </init-param>

    <load-on-startup>1</load-on-startup>

</servlet>

2.3. 스프링에 MessageBroker 설정하기

WebApplicationContext에 MessageBroker를 설정할 때 편리한 스프링 XML 설정 네임스페이스가 제공된다. 그 네임스페이스를 사용하려면 스프링 XML 설정 파일에 스키마 위치를 추가해야 한다. 보통 다음 설정과 같을 것이다.

<?xml version=”1.0″ encoding=”UTF-8″?>

<beans xmlns=”http://www.springframework.org/schema/beans”

  xmlns:flex=”http://www.springframework.org/schema/flex”

       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-2.5.xsd

           http://www.springframework.org/schema/flex 

           http://www.springframework.org/schema/flex/spring-flex-1.0.xsd”>

</beans>

    

    

이렇게 하면 설정 파일에서 flex 네임스페이스로 스프링 BlazeDS Integration 설정 태그를 사용할 수 있다. 다음 예제부터는 위와같이 설정했다고 가정을 하겠다. 이 네임스페이스에서 사용할 수 있는 모든 태그과 애트리뷰트는 spring-flex-1.0.xsd를 참조하기 바란다. 이클립스 같은 XSD를 인식하는 XML 편집기에서는 우리가 타이핑하는 것에 따라 문서를 자동으로 읽어줄 것이다.

스프링 WebApplicationContext에 최소한 MessageBrokerFactoryBean 을 설정하여 MessageBroker를 가동시켜야 하며 MessageBrokerHandlerAdapter 와 적절한  HandlerMapping (보통 SimpleUrlHandlerMapping) 을 사용하여 요청을 스프링이 관리하는  MessageBroker에 전달되게 해야한다. 

빈 설정 파일에 message-broker 태그를 등록하면 그러한 빈들을 자동으로 등록해 준다. 다음 예제가 가장 간단한 형태다.

<flex:message-broker/>    

    

이렇게 하면 MessageBroker 를 설정하고 필요한 기반 요소를 감각적인 기본값(sensible defaults)으로 설정해 준다. 그렇게 사용하는 기본값들은 message-broker 태그의 애트리뷰트 또는 하위 엘리먼트를 사용해서 재정의 할 수 있다. 예를 들어 BlazeDS XML 설정 파일의 기본 위치(/WEB-INF/flex/services-config.xml)를 services-config-path 애트리뷰트로 재정의할 수 있다. MessageBrokerFactoryBean 은 스프링의 ResourceLoader 추상화를 사용하기 때문에 스프링 리소스 패스를 사용할 수 있다. 그 예로, 애플리케이션 클래스패스에서 설정을 읽어오도록 다음과 같이 설정할 수 있다.

<flex:message-broker services-config-path=”classpath*:services-config.xml”    

    

이와 동일한 순수 스프링 설정을 사용한 MessageBrokerFactoryBean 정의는 다음과 같다. 

<!– Bootstraps and exposes the BlazeDS MessageBroker –>

<bean id=”_messageBroker” class=”org.springframework.flex.core.MessageBrokerFactoryBean” >

<property name=”servicesConfigPath” value=”classpath*:services-config.xml” />

</bean>    

    

message-broker 태그에서 특히 주목할 점은 MessageBroker에 커스텀 id를 설정할 필요가 없다는 것이다. 나중에 참조할 일도 없기 때문에 사실 그렇게 하는 것을 권장하지 않는다. 커스텀 id를 설정해야 하는 상황은 오직 WebApplicationContext에 MessageBroker를 두개 이상 가동할 경우이다.


2.4. 요청을 MessageBroker쪽으로 매핑하기

들어오는 요청을 스프링이 관리하는 MessageBroker로 전달하려면 세곳에 요청 매핑을 설정해야한다. 

  • web.xml에 DispatcherServlet 매핑
  • 스프링 WebApplicationContext에 HandlerMapping
  • BlazeDS services-config.xml에 채널 정의

가장 간단한 요청 매핑 시나리오는 앞단에 위치한 플렉스가 애플리케이션의 유일한 클라이언트인 경우이다. 이런 경우 /messagebroker를 요청 최상위 패스로 매핑할 수 있다. 그런 경우 web.xml에 다음과 매핑할 것이다.

<!– Map all /messagbroker requests to the DispatcherServlet for handling –>

<servlet-mapping>

    <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>

    <url-pattern>/messagebroker/*</url-pattern>

</servlet-mapping>    

message-broker 설정 태그를 사용하면  SimpleUrlHandlerMapping 이 설정되어 DispatcherServlet 으로 전달되는 모든 요청을 /* 경로 패턴을 따라 스프링이 관리하는 MessageBroker 에 매핑한다. 자신이 직접 작성한 HandlerMapping 빈을 설정할 때는   message-broker 태그의 disable-default-mapping 애트리뷰트를 사용해서 기본 매핑 사용을 제어할 수 있다. 기본으로 설정되는 SimpleUrlHandlerMapping 의 순서는 mapping-order 애트리뷰트로 설정할 수 있다. (동일한 컨텍스트에 여러 핸들러 매핑 타입이 존재하는 복잡한 경우에 사용할 수 있겠다.)

스프링 WebApplicationContext의 SimpleUrlHandlerMapping 은 모든 요청을 MessageBrokerHandlerAdapter를 통해 스프링이 관리하는 MessageBroker로 전달한다. 기본으로 설정되는 message-broker 태그는 다음과 같은 빈 정의와 동일하다.

<!-- Maps request paths at /* to the BlazeDS MessageBroker -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="mappings">
        <value>
            /*=_messageBroker
        </value>
    </property>
</bean>

<!-- Dispatches requests mapped to a MessageBroker -->
<bean class="org.springframework.flex.servlet.MessageBrokerHandlerAdapter"/>    
		

BlazeDS services-config.xml의 채널 정의가 반드시 선택한 매핑에 대응해야 한다. 예를 들어, 위 매핑 전략에 대응하는 AMF 채널을 BlazeDS에 다음과 같이 설정할 수 있다. 

 

<channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
    <endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf" 
    	class="flex.messaging.endpoints.AMFEndpoint"/>
    <properties>
        <polling-enabled>false</polling-enabled>
    </properties>
</channel-definition> 		
		

services-config.xml에 커뮤니테이션 채널을 설정하는 더 자세한 방법은  BlazeDS documentation 에서 참조하기 바란다.


2.5. 스프링 MVC 컨트롤러와 플렉스 클라이언트 같이 사용하기

플렉스 기반 클라이언트 뿐 아니라 더 다양한 클라이언트를 지원하는 애플리케이션이 더 흔할 것이다. 예를 들어 RESTful 아키텍처를 구성하여 여러 종류의 클라이언트를 지원할 수 있다. 잠재적으로 플렉스 HTTPService 컴포넌트를 사용하여 RESTful 종점(endpoint)를 구독할 수도 있다. 스프링 MVC의 컨트롤러 모델은 RESTful 종점 같은 것을 만들기 단순하며, 유연한 방법들을 제공한다. 이러한 하이브리드 웹 애플리케이션 시나리오에서는 다른 방식의 매핑 전략이 필요하다.

가장 간단한 방법은 여러 DispatcherServlet과 계층형 애플리케이션 컨텍스트를 사용하는 것이다. 이 방법에서는 주요 애플리케이션 계층(서비스, 보안, 기반시설 지원, 등)을 ContextLoaderListener가 로딩하는 상위 컨텍스트에 두고, 스프링 MVC 컨트롤러들을 그 하위 DispatcherServlet 컨텍스트에 두고, 플렉스 클라이언트와 관련된 모든 것들을 별도의 DispatcherServlet 컨텍스트에 두는 것이다. 이 방법을 적용한 web.xml은 다음과 같다.

<context-param>

    <param-name>contextConfigLocation</param-name>

    <param-value>

        /WEB-INF/spring/*-context.xml

    </param-value>

</context-param>

<listener>

    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

</listener>

<servlet>

    <servlet-name>flex</servlet-name>

    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

    <load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

    <servlet-name>flex</servlet-name>

    <url-pattern>/messagebroker/*</url-pattern>

</servlet-mapping>

<servlet>

    <servlet-name>spring-mvc</servlet-name>

    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

    <load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

    <servlet-name>spring-mvc</servlet-name>

    <url-pattern>/spring/*</url-pattern>

</servlet-mapping> 

 /WEB-INF/spring/ 디렉토리에  -context.xml 로 끝나는 파일 그룹을 묶어서 부모 애플리케이션 컨텍스트를 만든다. 플렉스 관련 하위 컨텍스트는  /WEB-INF/flex-servlet.xml을 사용하고 스프링 MVC 컨트롤러는 WEB-INF/spring-mvc-servlet.xml안에 설정할 것이다. 이 방법은 깔끔하게 관심사를 분리해주며 스프링 2.5+ 애노테이션 컨트롤러가 기본으로 동작하게 해준다.

이 대안이 될 수 있는 방법으로는 단일 DispatcherServlet 컨텍스트를 사용하는 것이다. 이 방법의 단점은 몇 가지 부가적인 설정을 필요로 한다. /spring/* 요처을 DispatcherSerlvet이 처리하고 mapping XML 네임스페이스 설정 태그를 사용해서 /messagebroker/*를 스프링이 관리하는 MessageBroker로 전달하는 것이다. 그런다음 BlazeDS 채널 정의를 적절하게 수정해야 한다. message-broker 태그로 기본 매핑 전략을 다음과 같이 수정할 수 있다.

<flex:message-broker>

    <flex:mapping pattern=”/messagebroker/*” />

</flex:message-broker> 

그런다음 BlazeDS의 채널 정의에서 /spring/*을 고려해서 다음과 같이 수정해야 한다. 

<channel-definition id=”my-amf” class=”mx.messaging.channels.AMFChannel”>

    <endpoint url=”http://{server.name}:{server.port}/{context.root}/spring/messagebroker/amf” 

    class=”flex.messaging.endpoints.AMFEndpoint”/>

    <properties>

        <polling-enabled>false</polling-enabled>

    </properties>

</channel-definition> 

단일 매핑 전략에서는 message-broker 태그가 자동으로 등록해주는 HandlerMapping과 HandlerAdapter가 있기 때문에 스프링 MVC 문서에 따라 스프링 MVC 컨트롤러를 위한 HandlerMapping와 HandlerAdapter을 직접 등록해 줘야 한다.

리눅스 시간 맞추기

맥이나 윈도우는 얼마나 편해 ㅠ.ㅠ 

시간 한번 맞추기가 이렇게 힘들어서야 원…

커맨드만 복사해 놔야지.. 링크가 고장날지도 모르니…
    [root@Zeus ~]# date 
    Fri Aug  3 08:05:03 UTC 2007 
    [root@Zeus ~]# hwclock –show 
    Fri 03 Aug 2007 05:39:07 PM UTC  -0.870183 seconds 
    [root@Zeus ~]# echo $TZ 

    [root@Zeus ~]# export env TZ=KST-09:00:00 
    [root@Zeus ~]# date 
    Fri Aug  3 17:05:45 KST 2007 


    [root@Zeus ~]# date 
    Fri Aug  3 18:05:21 KST 2007 
    [root@Zeus ~]# hwclock –show 
    Fri 03 Aug 2007 06:39:45 PM KST  -0.540050 seconds 
    [root@Zeus ~]# rdate -s time.bora.net 
    [root@Zeus ~]# hwclock –systohc 
    [root@Zeus ~]# date 
    Fri Aug  3 18:06:56 KST 2007 
    [root@Zeus ~]# hwclock –show 
    Fri 03 Aug 2007 06:07:01 PM KST  -0.211481 seconds 

    export env TZ=KST-09:00:00 
    rdate -s time.bora.net 
    hwclock –systohc