Whiteship's Note


Whiteship's 스프링 DM 레퍼런스 1.0 m2 배포

Spring DM/etc : 2008.07.03 23:59




Change Log
- confluence로 깔끔하게 옮겼습니다.
- confluence에서 pdf 로 뽑아냈습니다.(깔끔하고, 링크도 살았습니다.)
- 일부 제목을 번역했습니다.
- 내용을 약간 다듬었습니다.

Next Version
- 생략한 표들을 추가할 계획입니다.
- 원래 계획 대로라면, M3이 될 것 같네요.
- 뒷 부분에 생략한 부분도 추가할 계획입니다.


top

Write a comment.


PDFsam

Good Tools : 2008.07.03 23:35


찬욱군이 알려준 PDF 편집 툴인데, 정말 좋네요. PDF 파일을 쪼개고 합치는 용도로 사용할 수 있는 무료 툴입니다. 더군다가 자바로 만들어졌다는 사실...

사용자 삽입 이미지
따라서 맥용도 쉽게 제공해주는게죠. 멋지네요. 아이콘들이 좀;; 구리고. 화면도 맥 스럽지 않게 미려하지 못하지만 뭐 상관없습니다. PDF 만 잘 합쳐주면 그만입니다.ㅋㅋ

http://www.pdfsam.org/?page_id=32
<- 다운로드 페이지

top

TAG PDFsam

Write a comment.


OSGi 관리 툴이 떴네;; mToolkit

Spring DM/etc : 2008.07.03 22:48


우와;; 오늘 번들 관리하는 모듈을 만들고 있었는데.. 김빠지게 시리..GUI로 번들 관리할 수 있는 툴을 무료 배포해버리는군요. 하하핫. 괜찮아 괜찮아 기선아. 너도 열심히 해서 만들자꾸나...

사용자 삽입 이미지


http://dz.prosyst.com/oss/
top

  1. Favicon of http://yunsunghan.tistory.com BlogIcon Max 2008.07.04 10:01 PERM. MOD/DEL REPLY

    이제 관련 tool이 하나,둘씩 나오기 시작하는군요...
    (OSGi 학습해야 하는데...)

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2008.07.04 11:58 신고 PERM MOD/DEL

    네. 알게 모르게 많이 나와있더라구요. ㅋㅋ
    OSGi 전쟁 중인듯..

Write a comment.


자바의 volatile 키워드는 무슨 의미일까...

Java : 2008.07.03 18:52


사전적인 의미는 '휘발성의' 라는 뜻이다.

네이버에서 검색한 어떤 블로그를 보니까 "비동기적으로 바뀔 수 있는 변수"로 선언할 때 사용하는 키워드라고 설명되어 있다. ㄷㄷㄷ이다 도무지 감을 못 잡겠다. 구글링을 할 수 밖에 없다. 진작에 구글로 검색할 껄 혹시나 하는
기대감에 네이버로 검색해봤지만, 역시나였다.

건졌다.

나와 비슷한 의문을 가진 사람들이 2005년에도 많이 있었나보다. 3년이 지난 지금에서야 난 좀 이해할 수 있을 것 같다.

자바의 volatile은 멀티 쓰레드 환경에서 "완전히 공유 하겠다"라는 뜻이다.

일반 변수들은 멀티 쓰레드 환경에서 쓰레드 마다 각자 메인 메모리에 위치한 변수 값을 복사하여 그 값을 가지고 논다. 따라서 여러 쓰레드가 그 값들을 변경하면 쓰레드 마다 다른 값을 가지고 있는 경우가 발생할 수도 있다. 그로인한 문제들은 뭐 수도 없으니까 패스하자. 그런 문제들을 해결하는 방법으로 내가 여태까지 알고 있던건 "완전히 분리"하는 방법이었다. 쓰레드 로컬을 쓰던, 아예 로컬 변수로 만들어 버리던 해서 멤버 변수를 사용하지 않는 거였다. 그렇게 해야지 쓰레드 세이프 하라고 하는 건 줄 알고 있었다. 그런데... 완전 반전이다. 그 반대 방법도 있었던 것이다.

모든 쓰레드가 복사본을 가지고 노는게 아니라 메인 메모리에 있는 변수 값을 그대로 사용하고 그 값을 변경시키는 것이다. 이렇게 되면 모든 쓰레드는 동일한 값을 공유하게 된다. 물론 어떤 쓰레드가 변경 시켰는지는 몰겠지만, 중요한 모든 쓰레드가 같은 값(최근에 변경된 값)을 공유한다는 것이다.

그렇다면, 다음의 코드에 대해 잠깐 생각해볼까..

    private volatile BundleContext context;

BundleContext를 volatile로 선언했다. 사실 저 코드는 예제에 있던 코드를 무심코 베껴온것이고, 이제사 저 코드의 의미가 궁금해져서 찾아보았다.

        private void installNewBundles(File[] bundleFiles) throws BundleException {
            for (File file : bundleFiles) {
                String bundleLocation = "file:" + file.getAbsolutePath();
                if(findBundleByLocation(bundleLocation) == null){
                    context.installBundle(bundleLocation);
                    bundleLocations.add(bundleLocation);
                }
            }
        }

    protected Bundle findBundleByLocation(String location) {
        Bundle[] bundles = context.getBundles();
        for (int i = 0; i < bundles.length; i++) {
            if (bundles[i].getLocation().equals(location)) {
                return bundles[i];
            }
        }
        return null;
    }

위 코드들은 모두 쓰레드 안에서 실행하는 메소드들이다. context에 어떤 번들을 설치하고, 가져오는 일들을 하고 있다. 이 코드를 여러 개의 쓰레드가 실행한다고 가정했을 때, 그 여러 개의 쓰레드들이 동일한 BundleContext를 가지고 있지 않다면, 어떤 일이 벌어질까... 상상도 하기 싫을 정도로 끔찍하다. 설치한 걸 또 설치할려고 하거나, 이미 없앤 것을 또 없애려고 할 것이다. 전혀 내가 원한대로 동작하지 않게 된다. 그래서 volatile이 쓰인 것이었다.

나이스... volatile을 이제야 이해했다.

ps : 하지만 "비동기적으로 변경 될 수 있는 값"이라는 말은 아직도 이해가 되지 않는다. 한글이 영어보다 어려운건지. 저 위의 링크에서는 "비동기적으로 변경" 이라는 영어 단어는 볼 적이 없는 것 같은데... 신기할 따름이다.

top

  1. 없다캐라 2010.03.11 16:15 PERM. MOD/DEL REPLY

    잘 봤습니다. 난 이제사 궁금해졌으니 몇년에 걸쳐도 애매한건 자꾸 검색되어 읽히나 봅니다.

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2010.03.11 17:59 신고 PERM MOD/DEL

    사실 저게 정확한건지 어쩐지도 몰겠어요;;
    조만간 스펙을 뒤져봐야겠네요.

  2. Favicon of http://ielia.tistory.com BlogIcon 옐랴 2010.09.16 15:10 PERM. MOD/DEL REPLY

    으어 ㅠㅠ 아직도 모르겠어요 ㅠㅠ

  3. 박거북 2012.06.28 09:19 PERM. MOD/DEL REPLY

    저는 int 형은 스레드 세이프하고 long형은 그렇지 않다는 예제로 volatile 키워드를 검색하게 되었는데..

    감사합니다. 긴가 민가했는데 확실히 이해되었네요..

  4. Favicon of https://dream-snail.tistory.com BlogIcon 꿈꾸는 달팽이(꿈달) 2013.04.01 11:49 신고 PERM. MOD/DEL REPLY

    감사합니다

Write a comment.


BundleManager 0.2 번들 소스 코드

Spring DM/exercise : 2008.07.03 18:23


이전 버전과 달라진 건 클래스 하나.

BundleDirectoryManager.java
package whiteship;

import java.io.File;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;

public class BundleDirectoryManager implements BundleActivator {

    private static final long INTERBAL = 1000;
    private static String BUNDLE_DIRECTORY = "E:\\bundles";
    private volatile BundleContext context;

    private final Thread thread = new BundleManager(BUNDLE_DIRECTORY);

    public void start(BundleContext context) throws Exception {
        this.context = context;
        thread.start();
    }

    public void stop(BundleContext context) throws Exception {
        thread.interrupt();
    }

    protected Bundle findBundleByLocation(String location) {
        Bundle[] bundles = context.getBundles();
        for (int i = 0; i < bundles.length; i++) {
            if (bundles[i].getLocation().equals(location)) {
                return bundles[i];
            }
        }
        return null;
    }

    private class BundleManager extends Thread {

        private File bundleLocation;
        private List<String> bundleLocations = new CopyOnWriteArrayList<String>();

        public BundleManager(String location) {
            bundleLocation = new File(location);
        }

        public void run() {
            if (!bundleLocation.isDirectory())
                throw new RuntimeException(bundleLocation.getPath()
                        + " is not directory.");

            try {
                while (!Thread.currentThread().isInterrupted()) {
                    Thread.sleep(INTERBAL);
                    uninstallDeletedBundles();
                    installNewBundles(bundleLocation.listFiles(new JarFileFilter()));
                }
            } catch (InterruptedException e) {
                System.out.println("I'm going out");
            } catch (BundleException e) {
                throw new RuntimeException(e);
            }
        }

        private void uninstallDeletedBundles() throws BundleException {
            for(String bundleLocation : bundleLocations){
                File file = new File(bundleLocation.substring(5));
                if(file == null || !file.exists()){
                    findBundleByLocation(bundleLocation).uninstall();
                    bundleLocations.remove(bundleLocation);
                }
            }
        }

        private void installNewBundles(File[] bundleFiles) throws BundleException {
            for (File file : bundleFiles) {
                String bundleLocation = "file:" + file.getAbsolutePath();
                if(findBundleByLocation(bundleLocation) == null){
                    context.installBundle(bundleLocation);
                    bundleLocations.add(bundleLocation);
                }
                
            }
        }

    }
}

지정한 디렉터리에서 번들 파일을 삭제하면, 해당 번들은 OSGi 플랫폼에서 uninstall 하는 기능 추가. 짝짝짝 멋져부러~

이 멋진 모습을 동영상으로 찍어서 보여드리고 싶은데.. 일단 뭐 다 만든 다음에 보여드리도록 하죠.
top

Write a comment.


메이븐을 대체할 것인가~ Buildr

Build/Buildr : 2008.07.03 17:20


루비로 만들고 있다는 새로운 빌드 툴. 사부님 소개로 알게 되었는데 괜찮은 녀석 같아 보입니다. Maven 보다 빠르고 확장성 좋고 편하고 쉽게 같은 일들을 할 수 만 있다면 Maven에서 Buildr로 안 갈아탈 이유가 없겠죠.

메이븐은 좀더 편의성을 도모하지 않으면 앞으로 점차 JAR 저장소로만 그 이름을 이어가게 되지 않을런지...사실 메이븐 저장소라고 하기도 뭐하죠. 이미 Ivy에서는 Common Repository라고 호칭하지 Maven Repository라고 하진 않더군요.

http://incubator.apache.org/buildr/index.html

사용자 삽입 이미지
망치로 'r'을 표현하는 센스.

'Build > Buildr' 카테고리의 다른 글

메이븐을 대체할 것인가~ Buildr  (0) 2008.07.03
top

TAG buildr, maven

Write a comment.


BundleManager 0.1 번들 소스 코드

Spring DM/exercise : 2008.07.03 14:36


BundleManager가 할 일
- 특정 폴더에 jar 파일을 집어 넣으면 그 녀석을 설치해야 한다.
- 이미 해당 jar 파일이 설치되어 있다면 설치하지 않는다.

BundleDirectoryManager.java
package whiteship;

import java.io.File;

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;

public class BundleDirectoryManager implements BundleActivator {

    private static final long INTERBAL = 1000;
    private static String BUNDLE_DIRECTORY = "E:\\bundles";
    private volatile BundleContext context;

    private final Thread thread = new BundleManager(BUNDLE_DIRECTORY);

    public void start(BundleContext context) throws Exception {
        this.context = context;
        thread.start();
    }

    public void stop(BundleContext context) throws Exception {
        thread.interrupt();
    }

    protected Bundle findBundleByLocation(String location) {
        Bundle[] bundles = context.getBundles();
        for (int i = 0; i < bundles.length; i++) {
            if (bundles[i].getLocation().equals(location)) {
                return bundles[i];
            }
        }
        return null;
    }

    private class BundleManager extends Thread {

        private File bundleLocation;

        public BundleManager() {
            //TODO I need CoC
        }

        public BundleManager(String location) {
            bundleLocation = new File(location);
        }

        public void run() {
            if (!bundleLocation.isDirectory())
                throw new RuntimeException(bundleLocation.getPath()
                        + " is not directory.");

            try {
                while (!Thread.currentThread().isInterrupted()) {
                    Thread.sleep(INTERBAL);

                    for (File file : bundleLocation.listFiles(new JarFileFilter())) {
                        String bundleLocation = "file:" + file.getAbsolutePath();
                        if(findBundleByLocation(bundleLocation) == null)
                            context.installBundle(bundleLocation);
                    }
                }
            } catch (InterruptedException e) {
                System.out.println("I'm going out");
            } catch (BundleException e) {
                System.out.println("Error installing bundle");
                throw new RuntimeException(e);
            }
        }

    }
}

번들을 시작시키면 위의 클래스에 있는 start()가 실행되고, 주기적으로(현재 1초) 특정 폴더(현재 E:\bundles)를 확인해서 그 안에 들어있는 JAR 파일들을 찾아서 설치한다. 이 때 만약 이미 OSGi 플랫폼에 설치되어 있는 번들은 설치하지 않는다.

JarFileFilter.java
package whiteship;

import java.io.File;
import java.io.FileFilter;

public class JarFileFilter implements FileFilter {

    public boolean accept(File f) {
        if(f.isDirectory())
            return false;
       
        String extenstion = getExtension(f);
        if(extenstion != null && extenstion.equals("jar"))
            return true;
       
        return false;
    }

     public String getExtension(File f) {
            String ext = null;
            String s = f.getName();
            int i = s.lastIndexOf('.');

            if (i > 0 &&  i < s.length() - 1) {
                ext = s.substring(i+1).toLowerCase();
            }
            return ext;
        }

}

파일 필터로. 특정 폴더 안에 들어있는 파일들 중에 확장자가 jar 인 파일들만 가져오기 위해서 만들었음.

bnd파일
# bundleManager.bnd
Private-Package: whiteship
Bundle-Activator: whiteship.BundleDirectoryManager




개선하거나 생각해볼 것
- 스프링 DM 번들로 변경하자.
- 시간이랑 폴더는 DI가 가능하도록 변경하자.(기본 값 유지)
- jar 뿐만 아니라 war로 설치를 시도하게 하자. 스프링 DM 웹 번들일 수도 있으니까.
- getExtension() 메소드는 별도의 Util 클래스로 빼내기.
- 예외처리 RuntimeException으로 처리하기.

0.2
- 해당 폴더에서 jar 파일이 삭제되면, 해당 번들을 uninstall 시킨다.

0.3
- 만약 해당 폴더에 있는 jar 파일이 변경되면, 해당 번들을 update 시킨다.

참조: http://neilbartlett.name/blog/osgibook/
top

Write a comment.


HelloBundle 번들 소스 코드

Spring DM/exercise : 2008.07.03 14:23


HelloOsgi.java
package whiteship;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;

public class HelloOsgi implements BundleActivator {

    public void start(BundleContext arg0) throws Exception {
        System.out.println("하이");
    }

    public void stop(BundleContext arg0) throws Exception {
        System.out.println("바이바이");        
    }

}
설명이 필요 없는 매우 매우 간단한 번들.

bnd 파일
# helloBundle.bnd
Private-Package: whiteship
Bundle-Activator: whiteship.HelloOsgi

저 번들을 start 시키면 화면에 "하이" 라는 메시지를 찍고 stop 시키면 "바이바이"를 출력함.


테스트 용도로 사용하기 좋습니다.
top

TAG HelloOsgi

Write a comment.


20080703 GMP

모하니?/GMPing : 2008.07.03 09:48


News

Community 커뮤너리: 지역사회
Naomi Campbell 네오미 캠벌
Super Model 수퍼 마를
Community Service: 사회봉사
punishment: 벌
rage: 격노
air rage: 공항 난동
arrangement: 기소 사실 인부 절차
in-person: 혼자

200 hours of community service and 8700 dollors that's the punishment for Naomi Campbell's air rage. The super model showed up in-person for her rondon arrangment.

Screen English(Dan in love)

Who are you?
I'm Marti B~
Anyway I'd like to specially thank you for last friday's column. It really helped me to understand my parents.
Thank you. What else can I do for you?
I'd like to see your daughter, If I could.

Pop's English(I'm yours)

open up your mind and see like me.
open up your plans and damn you are free.
look into your heart and you will find
love love love love.

Talk Play Love(~하지 않는게 좋아)

You don't wanna know.
You don't wanna give up.
You don't wanna go back.
You don't wanna date her.
You don't wanna dump me.
You don't wanna order that.
You don't wanna live lijke that.
You don't wanna quit your job.

Sound Sound Play

[아우] 앞에 c가 오면 캬 발음

cow 캬우
coward 캬워드
council 캬운슬: 시의회
You are such a coward

Today Expression

질질 끌다 = drag ~'s feet.
The construction is going on. I think it should have been now.
I think they are dragging thier feet.

제대로 하라 = act right


'모하니? > GMPing' 카테고리의 다른 글

20080715 GMP  (0) 2008.07.15
20080710 GMP  (0) 2008.07.10
20080708 GMP  (0) 2008.07.08
20080707 GMP  (0) 2008.07.07
20080705 GMP  (0) 2008.07.05
20080704 GMP  (0) 2008.07.04
20080703 GMP  (0) 2008.07.03
20080702 GMP  (0) 2008.07.02
20080701 GMP  (0) 2008.07.01
20080627 GMP  (0) 2008.06.27
20080626 GMP  (0) 2008.06.26
top

TAG GMP

Write a comment.


Spring MVC에서 사용하는 ApplicationContext와 WebApplicationContext



보통 스프링 설정 파일이 최소한 두 개이상 있을 겁니다. xxx-servlet.xml 과 나머지로 나눌 수 있습니다. 그중에서 xxx-servlet.xml은 DispatcherServlet이 WebApplicationContext를 만들 때 사용하고, 나머지는  ContextLoaderListener 또는 ContextLoaderServlet이 일반적인 ApplicationContext를 만들 때 사용합니다.

이게 끝이 아닙니다. WebApplicationContext는 바로 이 ApplicationContext를 상속받아서 여러 서블릿들이 공통으로 사용하는 빈들을 사용할 수 있게 되는 겁니다. 따라서 만들어지는 순서도 중요한데, Listener가 아니라 ContextLoaderServlet을 사용했을 때는 load 머시기 설정 값에 1을 줘서 DispatcherServlet보다 먼저 만들게 해야 합니다. 그래서 WebApplicationContext를 만들 때 해당 ApplicationContext를 상속받아서 그 안에 있는 빈들을 사용할 수 있게 되겠죠.

이런 구조로 설계한 건, DispatcherServlet이 하나의 웹 애플리케이션에서 여러 개일 수 있기 때문입니다. 여러 개의 DispatcherServlet에서 공통으로 사용할 빈들을 상위에 있는 ApplicationContext에 선언해두고 공유할 수 있게 하는 거죠.

사용자 삽입 이미지

자. 그럼 여기서 문제

만약에 스프링 2.5 컨트롤러를 사용하고 있고 이 컨트롤러에 특정 @Aspect를 적용하고 싶을 때 해당 AOP 관련 설정(aop:autoproxy 머시기 엘리먼트 + @Aspect 빈 등록)은 xxx-servlet.xml과 applicationContext.xml 둘 중 어디에 둬야 할까요?

xxx-servlet.xml에는 컨트롤러 설정, 뷰 리졸버, 핸들러 맵퍼 등의 설정이 되어 있고, applicationContext.xml에는 서비스, DAO 등의 설정이 들어있습니다.
 
ㄱ. xxx-servlet.xml
ㄴ. applicationContext.xml
ㄷ. 어디에 두든지 상관없다.
ㄹ. 스프링 2.5 컨트롤러에는 Spring AOP를 사용할 수 없다.

정답은?? ㄱ 입니다. 왜냐면, applicationContext.xml을 사용해서 ApplicationContext를 만드는 순간에는 컨트롤러들이 미쳐 빈으로 등록되어 있지도 않기 때문에, 프록시를 만들 대상이 없습니다. 다시 말해, AOP 빈은 있지만, 이 AOP를 적용할 대상이 되는 빈이 없는겁니다. 따라서 컨트롤러들과 관련된 설정이 있는 xxx-servlet.xml에 해당 설정을 위치해야 합니다.

'Spring MVC > 3장 Spring MVC' 카테고리의 다른 글

Spring MVC에서 사용하는 ApplicationContext와 WebApplicationContext  (6) 2008.07.03
Service Layer  (2) 2006.12.13
Web Layer  (0) 2006.12.12
User Interface Layer  (0) 2006.10.09
Layers of Abstractions  (0) 2006.10.08
top

  1. 이철우 2009.12.16 07:17 PERM. MOD/DEL REPLY

    순전히 제 생각인데요, ㄷ 같은데요. 이유는 ㄹ은 아닌것 같고, 처음 스프링 MVC 이용해서 간단한 Web Application 만들적에 xxx-servlet.xml 만 사용해서도 만들었거든요.
    하지만 비즈니스 로직은 ApplicationContext.xml 에 주로 두므로 ㄴ?

    저 혹시 AOP 에 관한 포스팅도 있나요? 개념은 20% 정도 이해 한것 같구요. 어떻게 구현하는지는 영 모르겠네요.

    좋은 하루 되세요.

    Favicon of http://whiteship.me BlogIcon 기선 2009.12.16 10:57 PERM MOD/DEL

    하핫 오래전에 낸 문제라 저도 잊었는데 이제야 푸시는 분이 등장하셨네요!! 정말 감사합니다.

    하지만, 정답은 본문 아래 빈공간에 적어두었습니다. 마우스로 드래그 해보세요.

    AOP 구현 방법에 대해서는 이따 살짝 올릴꼐요.

  2. 이철우 2009.12.16 15:05 PERM. MOD/DEL REPLY

    답변 감사합니다. 많이 배웠습니다.

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.12.16 15:12 신고 PERM MOD/DEL

    아 맞다; AOP 구현 써야겠네요;

  3. 이철우 2009.12.18 02:41 PERM. MOD/DEL REPLY

    AOP 엄청 좋은 거였네요.

    어제, SpringSource University (http://www.springsource.com/training/freeonline) 에서 Developing Aspects with AOP (http://www.springsource.com/training/freeonline/download?sid=246444) by Jeff Brown 라는 강의를 봤는데요, AOP 기초 개념을 아주 쉽게 설명해 주는군요. 오늘 한번 써볼려고 합니다.

    또 다른 공짜 강의가 있는데요 OSGi, Spring-dm, Spring-dm Server 에 관한 거구요, 제 많은 의문점들을 풀어주더군요. OSGi Training: OSGi and Modular Applications ( http://s3.springsource.com/MRKT/training/online-screencast-final.mp4 ) by Joris Kuipers

    Spring source tool suite 에서 스프링 디엠 서버 쓰기가 참 쉽군요. 그냥 '드래그 인 드랍' 하면 디플로이가 되니깐 말이죠. 그런데 greenpages 샘플에서 웹사이트가 접근이 않되는군요. 리소스를 몾찾겠다고 그러네요, 뭐가 문젠가 시간좀 보내야 겠네요.

    좋은 하루 되세요.

    Favicon of http://whiteship.me BlogIcon 기선 2009.12.18 10:26 PERM MOD/DEL

    넹 좋아요!

    우와;; 그새 저 많은 걸 보시다니;; 멋지세요.

Write a comment.