oracle db..接続の件、
C:\oraclexe\app\oracle\product\11.2.0\server\odp.net\bin\2.x
のOracle.DataAccess.dllを使うこと。
---> ターゲットCPU --> x64
宛先フォルダ:C:\oraclexe\
Oracleホーム: C:\oraclexe\app\oracle\product\11.2.0\server\
Oracleベース:C:\oraclexe\
'Oracle Databaseリスナー'のポート: 1521
'Oracle Services for Microsoft Transaction Server'のポート: 2030
'Oracle HTTPリスナー'のポート: 8080
ODAC for Visual Studio 2017 Downloads
https://www.oracle.com/technetwork/topics/dotnet/downloads/odacmsidownloadvs2017-3806459.html
.NETへの快適なドライブ
https://www.oracle.com/technetwork/jp/articles/dotnet/o24odp-2147205-ja.html
【.NET】Oracleクライアント不要なODP.NET Managed Driverの接続方法
2018년 11월 14일 수요일
2018년 9월 2일 일요일
spring 설정 xml과 소스코드에서 properties 사용하기
spring 설정 xml과 소스코드에서 properties 사용하기
포르테시모 2013.07.18 13:52
spring 설정 xml에 다음과 같은 구문을 추가한다.
(첫번째)
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<context:component-scan base-package="com.tutorialspoint" />
<!-- context:property-placeholder location="classpath:database.properties" /!-->
<context:property-placeholder location="/WEB-INF/*.properties" />
굵은 표시를 한 부분을 추가한다.
classpath:database.properties의 의미는 classpath로 지정된 경로들에 있는 database.properties를 읽어오라는 뜻이라한다.
classpath:properties/*.properties의 의미는 classpath로 지정된 경로들에 있는 확장자가 properties인 파일들을 모두 읽어 오라는 뜻이라한다.
난 /WEB-/INF/database.properties,/WEB-/INF/file.properties 2개의 properties를 넣어서
<context:property-placeholder location="/WEB-INF/*.properties" /> 이렇게 사용하였다.
주의할 점은 properties들에 같은 key 값이 있다면 원하지 않는 데이터가 읽힐수 있다고 한다. 그럴 경우 다른 방법을 사용해야한다고 한다.
spring 설정 xml에 추가로 다음과 같이 db연결 정보를 변경한다.
(두번째)
기존코드
|
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="cubrid.jdbc.driver.CUBRIDDriver" /> <property name="url" value="jdbc:cubrid:localhost:30000:springdemo:::?charset=UTF-8" /> <property name="username" value="dba" /> <property name="password" value="admin" /> </bean> <!-- Definition for studentJDBCTemplate bean --> |
신규코드
|
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> |
(세번째)
database.properties
jdbc.driver=cubrid.jdbc.driver.CUBRIDDriver
jdbc.url=jdbc:cubrid:localhost:30000:springdemo:::?charset=UTF-8
jdbc.username=dba
jdbc.password=admin
jdbc.url=jdbc:cubrid:localhost:30000:springdemo:::?charset=UTF-8
jdbc.username=dba
jdbc.password=admin
file.properties
file_dir.url=/static/file_upload_data/
file_dir.thumbnail.url=/static/file_upload_data/thumbnail/
file_dir.english_word_audio_file.url=/static/english_word_audio_file/
file_dir.thumbnail.url=/static/file_upload_data/thumbnail/
file_dir.english_word_audio_file.url=/static/english_word_audio_file/
(네번째)
자바 코드에서 해당 properties 값을 가져다 쓸때는 아래와 같이 했다.
@Value("${file_dir.url}")
private String fileUploadLoc;
private String fileUploadLoc;
속성으로 지정해야했다. 지역변수로는 annotation을 이용해서는 받아올수 없었다.
properites에 해당 키값이 없다면 컴파일시에 오류를 낸다.
위에 내용은 내가 메인으로 사용할 properties의 내용을 가져올때 사용할 방법이다.
나혼자 만들때는 문제가 안되겠지만 혹시나 나중에 다른사람들과 협업을 할때를 고려하여 다른 방법도 적는다.
SpEL이용
(첫번째)
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<util:properties id="db" location="/WEB-INF/database.properties" />
<util:properties id="file" location="/WEB-INF/file.properties" />
위에 굵게 표시한 부분을 넣어줘야한다.
주의 할점은 첫번째와는 다르게 <util:properties id="db" location="/WEB-INF/*.properties" /> 이렇게
사용할수가 없다. 에러가 발생한다. 파일명을 온전히 써주어야한다.
(두번째)
이전코드
|
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> |
신규코드
|
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="#{db['jdbc.driver']}" /> <property name="url" value="#{db['jdbc.url']}" /> <property name="username" value="#{db['jdbc.username']}" /> <property name="password" value="#{db['jdbc.password']}" /> </bean> <!-- Definition for studentJDBCTemplate bean --> |
(세번째 properties 설정은 동일하다.)
(네번째) 소스코드에서 사용할때
@Value("#{file['file_dir.url']}")
private String fileUploadLoc;
private String fileUploadLoc;
소스코드에서 사용할때 첫번째 것은 동일한 key가 두개이상 존재할때 내가 원하는 값을 선택할수 없는 문제가 있고.
두번째것은 값이 실제로 존재하지 않아도 오류를 내지않고 null로 들어가게 된다.
두방법을 모두 한꺼번에 사용해도 에러가 발생되지 않는다.
단 두번째 방법을 사용하고 spring 설정 xml에 첫번째 방법의 태그를 지우고
첫번째 방법과 같이
@Value("${file_dir.url}")
private String fileUploadLoc;
private String fileUploadLoc;
쓰게 되면 fileUploadLoc에는 "${file_dir.url}" 라는 문자열이 들어가게 된다. 조심해야한다.
JSP에서 properties 읽기(펌 : http://nkjava.blogspot.in/2013/07/springmvc-read-property-in-jsp.html)
Spring config
<util:properties id="db" location="/WEB-INF/database.properties" />
jsp
<spring:eval expression="@db.getProperty('jdbc.password')" />
<util:properties id="db" location="/WEB-INF/database.properties" />
jsp
<spring:eval expression="@db.getProperty('jdbc.password')" />
테스트 해보니까 SpEL만 되는 것 같다. 참고 자료에는 context:property-placeholder 태그도 사용했지만
없어도 정상동작 하는 것을 확인하였다.
출처: http://jijs.tistory.com/entry/spring-설정-xml과-소스코드에서-properties-사용하기 [나살고싶어~]
2018년 8월 23일 목요일
Apache POIで実現が手間、困難な事
■Apache POIで実現が手間、困難な事
0件のコメント
今回の開発でApache POI(以下POI)を使用する機会があったので
POIで実現が手間、困難な事を紹介したいと思います。
ライブラリを選定する参考になれば幸いです。
今回使用した開発言語、POIとExcelのバージョンは下記の通りです。
・Java 1.7.0_45 64bit
・poi 3.8 20120326
・Excel 2010 xlsx形式
POIで実現が手間、困難な事を紹介したいと思います。
ライブラリを選定する参考になれば幸いです。
今回使用した開発言語、POIとExcelのバージョンは下記の通りです。
・Java 1.7.0_45 64bit
・poi 3.8 20120326
・Excel 2010 xlsx形式
1.シートのコピーでオブジェクトのコピーが行えない
図形やグラフ、フォーム部品などオブジェクトを含む
シートのコピーを行った場合、ファイルが破損します。
予めオブジェクトが置かれているシートを操作する、
コピーしたシートにオブジェクトの追加などは
問題ありません。
シートのコピーを行った場合、ファイルが破損します。
予めオブジェクトが置かれているシートを操作する、
コピーしたシートにオブジェクトの追加などは
問題ありません。
2.列単位の操作が行えない
処理単位が行やセルしか無く、列単位での挿入は
行をループさせながらセルを増やすという処理を
実装しなければなりません。
行をループさせながらセルを増やすという処理を
実装しなければなりません。
3.基本的にセル範囲は行、セルの追加とは非同期
結合セル、参照、印刷範囲などのセル範囲は行の追加削除、
セルの追加削除を行っても自動的には更新されません。
場合によってはファイルが破損するので注意が必要です。
全て範囲を確認しながら範囲を広げたり、狭めたりを
行わなければなりません。
セルの追加削除を行っても自動的には更新されません。
場合によってはファイルが破損するので注意が必要です。
全て範囲を確認しながら範囲を広げたり、狭めたりを
行わなければなりません。
4.行の自動高さ調整はされない
多くのExcelライブラリがそうであるようにセルに
折り返すようなテキストを挿入しても行の自動高さ調整は
されません。
折り返すようなテキストを挿入しても行の自動高さ調整は
されません。
5.画像の細かい調整できない
配置した画像の位置や大きさなどをピクセル指定などで
調整する事ができないようです。
配置自体はセル範囲に対して行うのですが、
セルに対してフィットするように配置されて縦横比は
無視されます。
セル範囲からオフセットを行う引数もあるのですが、
残念ながら今回は上手く機能させる事ができませんでした。
調整する事ができないようです。
配置自体はセル範囲に対して行うのですが、
セルに対してフィットするように配置されて縦横比は
無視されます。
セル範囲からオフセットを行う引数もあるのですが、
残念ながら今回は上手く機能させる事ができませんでした。
6.配置しているグラフを操作する方法がない
3.8バージョンでは配置済みのグラフを取得できる処理があると
思うのですが、上手く取得する事ができませんでした。
結果、配置しているグラフのデータ範囲などを更新する
事はできませんでした。
名前定義は更新が可能なので上手くテンプレートを作成すれば
データ範囲は調整が可能かも知れません。
また、グラフの新規作成についてもドキュメントが非常に
少なく、あまり現実的ではありません。
グラフ自体は予め配置してデータ範囲を決めておけば、
出力した値での集計は問題なく可能です。
思うのですが、上手く取得する事ができませんでした。
結果、配置しているグラフのデータ範囲などを更新する
事はできませんでした。
名前定義は更新が可能なので上手くテンプレートを作成すれば
データ範囲は調整が可能かも知れません。
また、グラフの新規作成についてもドキュメントが非常に
少なく、あまり現実的ではありません。
グラフ自体は予め配置してデータ範囲を決めておけば、
出力した値での集計は問題なく可能です。
7.非常に多くのメモリを使用する
3.8時点でのPOIは全てのデータをメモリ上に展開する為、
かなりのメモリを消費します。
保存された実ファイルの10倍以上は使用するようです。
クライアント側で動作させるプログラムなら大きな問題には
ならないかも知れませんが、WEBサーバで動作させる場合には
出力するデータに制限をかける事をオススメします。
以上が今回の開発で悩まされたPOIで実現が手間、困難な事です。
デメリットは大きいですが、オープンソースというメリットは
非常に大きいものです。
いくつかの問題点はラッピングクラスなどを実装すれば
使いやすいようにカスタマイズできると思います。
問題が多いオブジェクトに関してもある程度はテンプレートの
工夫などで切り抜ける事ができますので、
簡単な帳票や表などには十分使用できると思います。
今後はオブジェクトやメモリの問題なども改善していく
予定があるようなので、期待したい所です。
システム構築のご依頼でしたらお気軽にご相談下さい。
弊社お問い合わせ
かなりのメモリを消費します。
保存された実ファイルの10倍以上は使用するようです。
クライアント側で動作させるプログラムなら大きな問題には
ならないかも知れませんが、WEBサーバで動作させる場合には
出力するデータに制限をかける事をオススメします。
以上が今回の開発で悩まされたPOIで実現が手間、困難な事です。
デメリットは大きいですが、オープンソースというメリットは
非常に大きいものです。
いくつかの問題点はラッピングクラスなどを実装すれば
使いやすいようにカスタマイズできると思います。
問題が多いオブジェクトに関してもある程度はテンプレートの
工夫などで切り抜ける事ができますので、
簡単な帳票や表などには十分使用できると思います。
今後はオブジェクトやメモリの問題なども改善していく
予定があるようなので、期待したい所です。
システム構築のご依頼でしたらお気軽にご相談下さい。
弊社お問い合わせ
POIで、読み込んだExcelファイルから図形を取得して値をセットする
POIで、読み込んだExcelファイルから図形を取得して値をセットする
Excelファイル(※2007以降の.xlsx形式)から目的の図形を取得し、値をセットする。
今回はテキストボックスを取得してセットするサンプル。
既に対象のWorkbookとSheetを取得している状態から。
今回はテキストボックスを取得してセットするサンプル。
既に対象のWorkbookとSheetを取得している状態から。
// 図形描画の為のXSSFDrawingから図形のListを取得 XSSFDrawing drawing = sheet.createDrawingPatriarch(); ListshapeList = drawing.getShapes(); // Listから目的の図形を探索 for (XSSFShape sh : shapeList) { // (1)実際の型を確認 if (sh instanceof XSSFSimpleShape) { XSSFSimpleShape ss = (XSSFSimpleShape) sh; // (2)テキストの値をkeyに対象かどうか判断 if (ss.getText().equals("key")) { ss.setText("value you want to set"); } } }
(1)Listで取得されるオブジェクトはXSSFShapeのサブクラス(※)であり、検査せずにSimpleShapeとして扱おうとするとClassCastExceptionが発生する。
※こいつら。↓
XSSFConnector, XSSFGraphicFrame, XSSFPicture, XSSFShapeGroup, XSSFSimpleShape。
(2)APIDocなんかを読み漁ったけれども、定義した名前から図形を取得する方法がわからず。とりあえずテキストから判断するやり方で記述。
【環境】
POI 3.10
Java SE7
Java SE7
【参考】
XSSFSimpleShape (POI API Documentation)
もともと設定されていたフォントなどを維持したままテキストのみを置き換える場合は下記のようにテキストを分解し、テキストの最小単位(TextRun)に対して操作を行わなければいけないらしい。
[追記 2014/5/7]
上記のやり方で値をセットすると、図形にもともと設定されていたフォントや揃方がクリアされてデフォルト値になってしまうことがわかった。もともと設定されていたフォントなどを維持したままテキストのみを置き換える場合は下記のようにテキストを分解し、テキストの最小単位(TextRun)に対して操作を行わなければいけないらしい。
// 上記の11行目から if (ss.getText().equals("key")) { for (XSSFTextParagraph p : ss.getTextParagraphs()) { for (XSSFTextRun r : p.getTextRuns()) { r.setText("value you want to set"); // ※1 } } }
2018년 5월 27일 일요일
JavaScriptまとめ ➤ 正規表現 サンプル
http://cya.sakura.ne.jp/js/regexp.htm#s005
http://www.kanaya440.com/contents/tips/
http://www.kanaya440.com/contents/tips/
$(document).ready(function(){
// HOME > JavaScript > 数値の文字数(桁数)を調べるときにlengthは使えない
var no = 10000;
var figure = String(no).length;
$('#testDiv').text(figure);
// 숫자 3자리 단위마다 콤마(comma) 찍기
var no2 = 33333;
var aaa = no2.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
$('#testDiv').text(aaa);
});
2018년 3월 23일 금요일
Take my breath away
Take my breath away
Berlin
Berlin
Watching every motion
In my foolish lover's game
On this endless ocean
Finally lovers know no shame
Turning and returning
To some secret place inside
Watching in slow motion
As you turn around and say
Take my breath away
Take my breath away
In my foolish lover's game
On this endless ocean
Finally lovers know no shame
Turning and returning
To some secret place inside
Watching in slow motion
As you turn around and say
Take my breath away
Take my breath away
Watching I keep waiting
Still anticipating love
Never hesitating
To become the fated ones
Turning and returning
To some secret place to hide
Watching in slow motion
As you turn to me and say
Take my breath away
Still anticipating love
Never hesitating
To become the fated ones
Turning and returning
To some secret place to hide
Watching in slow motion
As you turn to me and say
Take my breath away
Through the hourglass I saw you
In time you slipped away
When the mirror crashed I called you
And turned to hear you say
If only for today
I am unafraid
Take my breath away
Take my breath away
In time you slipped away
When the mirror crashed I called you
And turned to hear you say
If only for today
I am unafraid
Take my breath away
Take my breath away
Watching every motion
In this foolish lover's game
Haunted by the notion
Somewhere there's a love in flames
Turning and returning
To some secret place inside
Watching in slow motion
As you turn my way and say
Take my breath away
Take my breath away
Take my breath away
Take my breath away
In this foolish lover's game
Haunted by the notion
Somewhere there's a love in flames
Turning and returning
To some secret place inside
Watching in slow motion
As you turn my way and say
Take my breath away
Take my breath away
Take my breath away
Take my breath away
Watching every motion in my foolish lover"s game
당신의 동작 하나하나를 지켜보죠. 바보 같은 사랑의 게임 속에서
당신의 동작 하나하나를 지켜보죠. 바보 같은 사랑의 게임 속에서
On this endless ocean finally lovers know no shame
이렇게 끝없는 바다위에 결국 연인들은 아무런 부끄럼도 모르게 되죠.
이렇게 끝없는 바다위에 결국 연인들은 아무런 부끄럼도 모르게 되죠.
Turning and returning to some secret place inside
마음속깊이 은밀한 곳을 향해 계속 돌고 돕니다.
마음속깊이 은밀한 곳을 향해 계속 돌고 돕니다.
Watching in slow motion as you turn around and say
난 가만히 지켜보고 있어요. 당신이 돌아서며 말하는 모습을
난 가만히 지켜보고 있어요. 당신이 돌아서며 말하는 모습을
Take my breath away, Take my breath away
내 마음을 가져가세요. 내 마음을 가져가세요.
내 마음을 가져가세요. 내 마음을 가져가세요.
Watching I keep waiting still anticipating love
당신을 지켜보며 당신의 사랑을 기다리고 있어요.
당신을 지켜보며 당신의 사랑을 기다리고 있어요.
Never hesitating to become the fated ones
운명적인 사랑을 이루는데 조금도 주저하지 않아요.
운명적인 사랑을 이루는데 조금도 주저하지 않아요.
Turning and returning to some secret place to hide
마음속 깊은 곳을 향해 끝없이 돌고 돕니다.
마음속 깊은 곳을 향해 끝없이 돌고 돕니다.
Watching in slow motion as you turn to me and say
가만히 지켜보고 있어요. 그대가 내 쪽으로 돌아서며 말하는 걸...
가만히 지켜보고 있어요. 그대가 내 쪽으로 돌아서며 말하는 걸...
Take my breath away
내 마음을 가져가세요.
내 마음을 가져가세요.
Through the hourglass I saw you, in time you slipped away
모래시계를 통하여 나는 당신을 보았어요. 세월 속에 당신은 슬쩍 가버렸죠.
모래시계를 통하여 나는 당신을 보았어요. 세월 속에 당신은 슬쩍 가버렸죠.
When the mirror crashed I called you, and turned to hear you say
거울이 깨졌을 때 나는 당신을 소리쳐 부르고 몸을 돌려 당신이 말하는 것을 들었죠.
거울이 깨졌을 때 나는 당신을 소리쳐 부르고 몸을 돌려 당신이 말하는 것을 들었죠.
If only for today I am unafraid
오직 오늘만을 위해서라면 나는 두렵지 않아요.
오직 오늘만을 위해서라면 나는 두렵지 않아요.
Take my breath away, Take my breath away
내 마음을 가져가세요. 내 마음을 가져가세요.
내 마음을 가져가세요. 내 마음을 가져가세요.
Watching every motion in this foolish lover"s game
이 바보 같은 사랑게임을 하면서 당신의 모든 움직임을 지켜보고 있어요.
이 바보 같은 사랑게임을 하면서 당신의 모든 움직임을 지켜보고 있어요.
Haunted by the notion somewhere there"s a love in flames
어딘가에 불타는 사랑이 있을 거라는 생각에 사로잡히지요.
어딘가에 불타는 사랑이 있을 거라는 생각에 사로잡히지요.
Turning and returning to some secret place inside
깊이 감추어진 내 마음속의 사랑을 향해 끝없이 돌고 돕니다.
깊이 감추어진 내 마음속의 사랑을 향해 끝없이 돌고 돕니다.
Watching in slow motion as you turn to me and say
난 가만히 지켜보고 있어요. 당신이 내 쪽으로 돌아서며 이렇게 말하는 모습을..
난 가만히 지켜보고 있어요. 당신이 내 쪽으로 돌아서며 이렇게 말하는 모습을..
Take my breath away, My love, take my breath away
내 마음을 가져가세요. 내 사랑, 내 마음을 가져가세요.
내 마음을 가져가세요. 내 사랑, 내 마음을 가져가세요.
2018년 3월 13일 화요일
terasoluna error
<t:messagesPanel />
<div>
<form:errors path="*" />
</div>
YearMonthUpdateUpdateBLogicOutput output = null;
try {
output = yearMonthUpdateUpdateBLogic.execute(input);
if (!result.hasErrors()) {
ResultMessages messages = ResultMessages.info().add("i.ne.fw.0002");
model.addAttribute(messages);
}
} catch (BusinessException e) {
model.addAttribute(e.getResultMessages());
} catch (Exception e) {
ResultMessages messages = ResultMessages.error().add("e.ne.fw.8002")
.add(ResultMessage.fromText(e.getMessage()));
model.addAttribute(messages);
}
BindingResult result = input.getResult();
if (result.hasErrors()) {
return null;
}
if (!mYearMonth.getSysYearMonth().equals(form.getSysYearMonth())) {
ResultMessages messages = ResultMessages.error().add("e.ne.fw.9001");
throw new BusinessException(messages);
}
2018/03/14 일본어
ふよ[付与·附与] 부여; (내려) 줌.(↔剝奪)
単項目チェックはBean Validation、
相関チェックはSpring Validator又はBean Validationでチェックを行う。
いじょう[委譲·依譲·移譲]
위양·이양.
せんい[遷移]
천이.(=転移)
てっする[徹する]
철저하다; 투철하다; 꿰뚫다.사무치다.
사무치다, 철저하다;투철하다, 밤을 새우다
すいしょう[推奨]추장.
てったい[撤退]철퇴.
こな[粉]
가루; 분말; 특히, 밀가루.(=粉)
単項目チェックはBean Validation、
相関チェックはSpring Validator又はBean Validationでチェックを行う。
いじょう[委譲·依譲·移譲]
위양·이양.
せんい[遷移]
천이.(=転移)
てっする[徹する]
철저하다; 투철하다; 꿰뚫다.사무치다.
사무치다, 철저하다;투철하다, 밤을 새우다
すいしょう[推奨]추장.
てったい[撤退]철퇴.
こな[粉]
가루; 분말; 특히, 밀가루.(=粉)
@Autowired、@Inject、@Resourceの違いについての検証
@Autowired、@Inject、@Resourceの違いについての検証
Java
spring
この記事は最終更新日から1年以上が経過しています。
@Autowired、@Inject、@Resourceについて、共通的な動きとしては、何れも自動でフィールドにbeanをインジェクションすることです。今回はそれらの違いについて、検証してみます。
@Resource⇨javax.annotation
@Inject⇨javax.inject
@Autowired⇨org.springframework.bean.factory
事前準備
以下のクラスを用意する。
・インタフェースクラスPrint
・インタフェースクラスPrintの実装クラスHelloWorldPrintImp
・インタフェースクラスPrintの実装クラスHelloMoonPrintImp
public interface Print {
public void print();
}
@Component
public class HelloWorldPrintImp implements Print {
@Override
public void print() {
System.out.println("Hello World");
}
}
@Component
public class HelloMoonPrintImp implements Print {
@Override
public void print() {
System.out.println("Hello Moon");
}
}
検証1
@Autowired
private Print print;
@Inject
private Print print;
@Resource
private Print print;
上記のケースは、何れも例外NoUniqueBeanDefinitionExceptionが発生した。
インタフェースクラスPrintの実装クラスのbeanがユニックでないのが原因である。
検証2
@Autowired
private Print helloWorldPrintImp;
@Inject
private Print helloWorldPrintImp;
@Resource
private Print helloWorldPrintImp;
インジェクション対象のフィルド名を@Componentのクラス名と一致すればに、検証1の例外を回避し、上記何れも正常にインジェクションできる。
実行結果は以下の通りです。
@Autowired:Hello World
@Inject:Hello World
@Resource:Hello World
検証3
@Autowired
@Qualifier("helloWorldPrintImp")
private Print print;
@Inject
@Qualifier("helloWorldPrintImp")
private Print print;
@Resource
@Qualifier("helloWorldPrintImp")
private Print print;
@Qualifier("name")を上記のアノテーションと併用することで、インジェクション対象bean名を指定でき、検証1の例外も同様に回避する。
実行結果は以下の通りです。
@Autowired:Hello World
@Inject:Hello World
@Resource:Hello World
検証4
@Autowired
@Qualifier("helloMoonPrintImp")
private Print helloWorldPrintImp;
@Inject
@Qualifier("helloMoonPrintImp")
private Print helloWorldPrintImp;
@Resource
@Qualifier("helloMoonPrintImp")
private Print helloWorldPrintImp;
フィルド名=コンポーネントクラス名、且つ@Qualifierで別のコンポーネントを指定する場合、@Autowiredと@Injectの動きは一緒であり、@Qualifierで指定するコンポーネントがインジェクションされている。
@Resourceは@Qualifierで指定のコンポーネントを無視し、フィルド名と一致のコンポーネントがインジェクションされている。
実行結果は以下の通りです。
@Autowired:Hello Moon
@Inject:Hello Moon
@Resource:Hello World
また、@Resource(name="name")でコンポーネント名を指定できる。
@Resource(name="helloMoonPrintImp")
private Print helloWorldPrintImp;
その場合に、nameで指定されるコンポーネントがインジェクションされる。
実行結果は以下の通りです。
@Resource:Hello Moon
結論
タイプ一致の場合に、インジェクションの優先順位:
@Autowiredと@Inject
1.Qualifier指定のコンポーネント
2.フィルド名と一致のコンポーネント
@Resource
1.@Resource(name="name")で指定のコンポーネント
2.フィルド名と一致のコンポーネント
3.Qualifier指定のコンポーネント
Java
spring
この記事は最終更新日から1年以上が経過しています。
@Autowired、@Inject、@Resourceについて、共通的な動きとしては、何れも自動でフィールドにbeanをインジェクションすることです。今回はそれらの違いについて、検証してみます。
@Resource⇨javax.annotation
@Inject⇨javax.inject
@Autowired⇨org.springframework.bean.factory
事前準備
以下のクラスを用意する。
・インタフェースクラスPrint
・インタフェースクラスPrintの実装クラスHelloWorldPrintImp
・インタフェースクラスPrintの実装クラスHelloMoonPrintImp
public interface Print {
public void print();
}
@Component
public class HelloWorldPrintImp implements Print {
@Override
public void print() {
System.out.println("Hello World");
}
}
@Component
public class HelloMoonPrintImp implements Print {
@Override
public void print() {
System.out.println("Hello Moon");
}
}
検証1
@Autowired
private Print print;
@Inject
private Print print;
@Resource
private Print print;
上記のケースは、何れも例外NoUniqueBeanDefinitionExceptionが発生した。
インタフェースクラスPrintの実装クラスのbeanがユニックでないのが原因である。
検証2
@Autowired
private Print helloWorldPrintImp;
@Inject
private Print helloWorldPrintImp;
@Resource
private Print helloWorldPrintImp;
インジェクション対象のフィルド名を@Componentのクラス名と一致すればに、検証1の例外を回避し、上記何れも正常にインジェクションできる。
実行結果は以下の通りです。
@Autowired:Hello World
@Inject:Hello World
@Resource:Hello World
検証3
@Autowired
@Qualifier("helloWorldPrintImp")
private Print print;
@Inject
@Qualifier("helloWorldPrintImp")
private Print print;
@Resource
@Qualifier("helloWorldPrintImp")
private Print print;
@Qualifier("name")を上記のアノテーションと併用することで、インジェクション対象bean名を指定でき、検証1の例外も同様に回避する。
実行結果は以下の通りです。
@Autowired:Hello World
@Inject:Hello World
@Resource:Hello World
検証4
@Autowired
@Qualifier("helloMoonPrintImp")
private Print helloWorldPrintImp;
@Inject
@Qualifier("helloMoonPrintImp")
private Print helloWorldPrintImp;
@Resource
@Qualifier("helloMoonPrintImp")
private Print helloWorldPrintImp;
フィルド名=コンポーネントクラス名、且つ@Qualifierで別のコンポーネントを指定する場合、@Autowiredと@Injectの動きは一緒であり、@Qualifierで指定するコンポーネントがインジェクションされている。
@Resourceは@Qualifierで指定のコンポーネントを無視し、フィルド名と一致のコンポーネントがインジェクションされている。
実行結果は以下の通りです。
@Autowired:Hello Moon
@Inject:Hello Moon
@Resource:Hello World
また、@Resource(name="name")でコンポーネント名を指定できる。
@Resource(name="helloMoonPrintImp")
private Print helloWorldPrintImp;
その場合に、nameで指定されるコンポーネントがインジェクションされる。
実行結果は以下の通りです。
@Resource:Hello Moon
結論
タイプ一致の場合に、インジェクションの優先順位:
@Autowiredと@Inject
1.Qualifier指定のコンポーネント
2.フィルド名と一致のコンポーネント
@Resource
1.@Resource(name="name")で指定のコンポーネント
2.フィルド名と一致のコンポーネント
3.Qualifier指定のコンポーネント
@Component、@Service、@Repository、@Controllerの違いについて
@Component、@Service、@Repository、@Controllerの違いについて
Java
spring
この記事は最終更新日から1年以上が経過しています。
Springアノテーション「@Component、@Service、@Repository、@Controller」について、
動きとして基本的同じであり、何れもアノテーションが付与されたクラスをSpringのDIコンテナにbeanとして登録します。
使い分けとしては、Spring MVCにおいてコントローラー層のクラスには@Contoroller、
サービス層のクラスには@Serivice、データ層のクラスには@Repository、
どれにも当てはまらない場合は@Componentを付けます。
@Controller
Spring MVCでコントローラー層のクラスに付与する。
Controller は、主に以下の役割を担う。
・画面遷移の制御
・ドメイン層の Service の呼出 (主処理を実行する)
@Controller
@RequestMapping("findProduct")
public class FindProductController {
@Inject
FindProductService findProductService;
@RequestMapping(value="list")
public String list(Model model) {
Collection<Product> products = findProductService.findAll();
model.addAttribute("products", products);
return "product/list";
}
}
@Service
Sping MVCでサービス層のクラス(ビジネスロジック等)に付与する。
Service は業務処理を提供する。
@Service
public class FindProductServiceImp implements FindProductService {
@Inject
FindProductRepository findProductRepository;
public Todo findAll() {
Collection<Product> products = findProductRepository.findAll();
if (products == null) {
// エラー処理
...
}
return products;
}
}
@Repository
Spring MVCでデータ層のクラス(DAO等のDBアクセスを行うクラス)に付与する。
@Repository
public class FindProductRepositoryImpl implements FindProductRepository {
private Collection<Product> products;
@Override
public Collection<Product> findAll() {
return products;
}
}
@Component
Spring MVCに限らず、SpringのDIコンテナにbeanとして登録したいクラスへ付与する。
@Component
public class checkComponentImp implements checkComponent{
@Override
public boolean check(BLogicParam param) {
...
}
}
Java
spring
この記事は最終更新日から1年以上が経過しています。
Springアノテーション「@Component、@Service、@Repository、@Controller」について、
動きとして基本的同じであり、何れもアノテーションが付与されたクラスをSpringのDIコンテナにbeanとして登録します。
使い分けとしては、Spring MVCにおいてコントローラー層のクラスには@Contoroller、
サービス層のクラスには@Serivice、データ層のクラスには@Repository、
どれにも当てはまらない場合は@Componentを付けます。
@Controller
Spring MVCでコントローラー層のクラスに付与する。
Controller は、主に以下の役割を担う。
・画面遷移の制御
・ドメイン層の Service の呼出 (主処理を実行する)
@Controller
@RequestMapping("findProduct")
public class FindProductController {
@Inject
FindProductService findProductService;
@RequestMapping(value="list")
public String list(Model model) {
Collection<Product> products = findProductService.findAll();
model.addAttribute("products", products);
return "product/list";
}
}
@Service
Sping MVCでサービス層のクラス(ビジネスロジック等)に付与する。
Service は業務処理を提供する。
@Service
public class FindProductServiceImp implements FindProductService {
@Inject
FindProductRepository findProductRepository;
public Todo findAll() {
Collection<Product> products = findProductRepository.findAll();
if (products == null) {
// エラー処理
...
}
return products;
}
}
@Repository
Spring MVCでデータ層のクラス(DAO等のDBアクセスを行うクラス)に付与する。
@Repository
public class FindProductRepositoryImpl implements FindProductRepository {
private Collection<Product> products;
@Override
public Collection<Product> findAll() {
return products;
}
}
@Component
Spring MVCに限らず、SpringのDIコンテナにbeanとして登録したいクラスへ付与する。
@Component
public class checkComponentImp implements checkComponent{
@Override
public boolean check(BLogicParam param) {
...
}
}
[Spring] @Autowired, @Resource, @Inject의 차이 Spring
[Spring] @Autowired, @Resource, @Inject의 차이 Spring
2014. 7. 7. 18:01
https://blog.naver.com/platinasnow/220053030295
이번에 소개하는 세가지 어노테이션 @Autowired, @Resource,@Inject은 모두 의존관계를 자동으로 연결해주는 기능을 가진 어노테이션입니다. 다만 조금씩의 차이가 있습니다.
@Autowired
@Inject
@Resource
범용
스프링 전용
자바에서 지원
자바에서 지원
연결방식
타입에 맞춰서 연결
타입에 맞춰서 연결
이름으로 연결
자세한 설명을 하자면, @Inject와 @Resource는 JSR에 실려있는 자바 기존의 어노테이션입니다. 반면 @Autowired의 경우에는 스프링에서 등장한 어노테이션입니다. 따라서 스프링 이외에서는 사용 할 수 없습니다. 만약에 프로젝트를 스프링에서 다른 프레임워크로 바꿀 생각이 있으시다면 @Autowired보단 @Inject나 @Resource를 쓰시면 됩니다. 다만 이런 경우는 거의 없다고 봅니다.
또한 연결 방식은 @Autowired와 @Inject는 타입에 맞춰서 하는 반면, @Resource는 이름에 맞춰서 연결하게 됩니다. 예를 들어보겠습니다.
Bird 인터페이스를 상속하는 Chicken과 Penguin 이라는 클래스가 있다고 합시다.
Chicken과 Penguin 클래스를 연결할 것이므로 @Component로 빈에 등록해주었습니다.
public class Bird{}
@Component
public class Chicken implements Bird{}
@Component
public class Penguin implements Bird{}
그리고 다음과 같이 연결해봅시다.
@Autowired
private Chicken penguin; //Chicken 타입으로 연결됩니다.
@Inject
private Penguin chicken; //Penguin 타입으로 연결됩니다.
@Resource
private Chicken penguin; //penguin 타입으로 연결됩니다만, Chicken 클래스를 자료형으로 두었기에 캐스팅이 되지 않아 에러가 납니다
@Resource
private Bird penguin; //penguin 타입으로 연결되어 호출해보면 penguin 클래스의 값을 호출하는 것을 볼 수 있습니다.
@Autowired와 @Inject의 경우에도 @Qualifier 어노테이션을 사용하면, 타입 이외의 방법으로도 연결 할 수 있습니다.
@Autowired
@Qualifier("chicken")
pirvate Brid penguin;
위와 같이 쓰면 이름에 상관없이 Chicken 타입으로 연결되는 것을 알 수 있습니다. 이렇게 @Qualifer와 함께 쓰면 더욱 강력한 기능을 쓸 수 있는 장점이 있습니다.
[출처] [Spring] @Autowired, @Resource, @Inject의 차이|작성자 심해펭귄
2014. 7. 7. 18:01
https://blog.naver.com/platinasnow/220053030295
이번에 소개하는 세가지 어노테이션 @Autowired, @Resource,@Inject은 모두 의존관계를 자동으로 연결해주는 기능을 가진 어노테이션입니다. 다만 조금씩의 차이가 있습니다.
@Autowired
@Inject
@Resource
범용
스프링 전용
자바에서 지원
자바에서 지원
연결방식
타입에 맞춰서 연결
타입에 맞춰서 연결
이름으로 연결
자세한 설명을 하자면, @Inject와 @Resource는 JSR에 실려있는 자바 기존의 어노테이션입니다. 반면 @Autowired의 경우에는 스프링에서 등장한 어노테이션입니다. 따라서 스프링 이외에서는 사용 할 수 없습니다. 만약에 프로젝트를 스프링에서 다른 프레임워크로 바꿀 생각이 있으시다면 @Autowired보단 @Inject나 @Resource를 쓰시면 됩니다. 다만 이런 경우는 거의 없다고 봅니다.
또한 연결 방식은 @Autowired와 @Inject는 타입에 맞춰서 하는 반면, @Resource는 이름에 맞춰서 연결하게 됩니다. 예를 들어보겠습니다.
Bird 인터페이스를 상속하는 Chicken과 Penguin 이라는 클래스가 있다고 합시다.
Chicken과 Penguin 클래스를 연결할 것이므로 @Component로 빈에 등록해주었습니다.
public class Bird{}
@Component
public class Chicken implements Bird{}
@Component
public class Penguin implements Bird{}
그리고 다음과 같이 연결해봅시다.
@Autowired
private Chicken penguin; //Chicken 타입으로 연결됩니다.
@Inject
private Penguin chicken; //Penguin 타입으로 연결됩니다.
@Resource
private Chicken penguin; //penguin 타입으로 연결됩니다만, Chicken 클래스를 자료형으로 두었기에 캐스팅이 되지 않아 에러가 납니다
@Resource
private Bird penguin; //penguin 타입으로 연결되어 호출해보면 penguin 클래스의 값을 호출하는 것을 볼 수 있습니다.
@Autowired와 @Inject의 경우에도 @Qualifier 어노테이션을 사용하면, 타입 이외의 방법으로도 연결 할 수 있습니다.
@Autowired
@Qualifier("chicken")
pirvate Brid penguin;
위와 같이 쓰면 이름에 상관없이 Chicken 타입으로 연결되는 것을 알 수 있습니다. 이렇게 @Qualifer와 함께 쓰면 더욱 강력한 기능을 쓸 수 있는 장점이 있습니다.
[출처] [Spring] @Autowired, @Resource, @Inject의 차이|작성자 심해펭귄
[Spring] ViewResolver 설정
[Spring] ViewResolver 설정
2014.12.18 23:51
Posted in Programing/Spring by devbox
ViewResolver 설정
뷰 영역 구현
컨트롤러는 최종적으로 결과를 출력할 뷰와 뷰에 전달할 객체를 담고 있는 ModelAndView 객체를 리턴한다.
DispatherServlet은 ViewResolver를 사용하여 결과를 출력할 View 객체를 구하고, 구한 View 객체를 이용하여 내용을 생성한다.
1. 컨트롤러 구현 및 설정 추가
컨트롤러를 구현하려면 먼저 @Contoller 어노테이션을 클래스에 적용한다. 그리고, @RequestMapping 어노테이션을 이용해서 클라이언트의 요청을 처리할 메서드를 지정한다.
package madvirus.spring.chap06.controller;
import java.util.Calendar;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
// @Controller 어노테이션은 해당 클래스가 스프링 MVC의 컨트롤러를 구현한 클래스라는 것을 지정한다.
@Controller
public class HelloController {
// @RequestMapping 어노테이션은 값으로 지정한 요청 경로를 처리한 메서드를 설정한다.
// 이 경우 http://host:port[/컨텍스트 경로]/hello.do 요청을 HelloController 클래스의 hello() 메서드가 처리하게 된다.
@RequestMapping("/hello.do")
public ModelAndView hello() {
//ModelAndView는 컨트롤러의 처리 결과를 보여줄 뷰와 뷰에서 출력할 모델을 지정할 때 사용된다.
ModelAndView mav = new ModelAndView();
// 컨트롤러의 처리 결과를 보여줄 뷰의 이름을 'hello'를 지정한다.
mav.setViewName("hello");
// 모델에 'greeting'이라는 이름으로 String 타입의 값을 추가하였다.
mav.addObject("greeting", getGreeting());
return mav;
}
// 스프링은 ModelAndView 뿐만 아니라 String이나 modelMap, 또는 Map과 같은 타입을 이용해서 뷰 이름과 모델 정보를 설정할 수 있도록 하고 있다.
private String getGreeting() {
int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
if (hour >= 6 && hour <= 10) {
return "좋은 아침입니다.";
} else if (hour >= 12 && hour <= 15) {
return "점심 식사는 하셨나요?";
} else if (hour >= 18 && hour <= 22) {
return "좋은 밤 되세요";
}
return "안녕하세요";
}
}
DispatherServlet은 스프링 컨테이너에서 컨트롤러 객체를 검색하기 때문에 스프링 설정 파일에 컨트롤러를 빈으로 등록해 주어야 한다.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="helloController" class="madvirus.spring.chap06.controller.HelloController" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
스프링 2.5 버전까지는 @Controller 어노테이션이 적용된 클래스를 컨트롤러로 사용하려면 별도의 DefaultAnnoationHandlerMapping과 AnnotationHandlerAdapter를 스프링 설정 파일에 등록해 주어야 한다. 하지만 스프링 3.0부터는 이 두 빈 객체를 기본 구현체로 사용하기 때문에 별도의 설정을 하지 않을 경우 @Controller 어노테이션이 적용된 클래스를 컨트롤러 구현체로 사용할 수 있게 된다.
2. 설정 파일에 ViewResolver 설정 추가
컨트롤러 클래스는 직접 또는 간접적으로 ModelAndView 객체를 생성하게 된다.
예를 들어 앞서 작성한 HelloController 클래스는 다음과 같이 ModelAndView 객체를 생성해서 리턴하였다.
public ModelAndView hello() {
ModelAndView mav = new ModelAndView();
// 뷰이름
mav.setViewName("hello");// setViewName() 메서드를 이용하여 뷰 이름을 지정한 모습
mav.addObject("greeting", getGreeting());
return mav;
}
컨트롤러의 처리 결과를 보여줄 뷰의 이름을 'hello'를 지정하였는데, DispatherServlet은 이 뷰 이름과 매칭되는 뷰 구현체를 찾기 위해 ViewResolver를 사용한다.
JSP를 뷰 기술로 사용할 경우 다음과 같이 InternalResourceViewResolver 구현체를 빈으로 등록해주면 된다.
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="WEB-INF/view"/>
<property name="suffix" value=".jsp/>
// 이는 ViewResolver가 "WEB-INF/view/뷰이름.jsp"를 뷰 JSP로 사용한다는 것을 의미한다.
// 즉, 앞의 예에서 HelloController는 뷰 이름으로 "hello"를 리턴하므로, 실제로 사용되는 뷰 파일은 "WEB-INF/view/hello.jsp"파일이 된다.
</bean>
InternalResourceViewResolver는 컨트롤러가 지정한 뷰 이름으로부터 실제로 사용될 뷰를 선택하는데, 이 때 컨트롤러가 지정한 뷰 이름 앞뒤로 prefix 프로퍼티와 suffix 프로퍼티를 추가한 값이 실제로 사용될 자원의 경로가 된다.
※ ViewResolver 구현 클래스
스프링 컨트롤러는 뷰에 의존적이지 않다. 컨트롤러는 아래 코드와 같이 결과를 생성할 뷰의 이름만 지정할 뿐이다.
컨트롤러가 지정한 뷰 이름으로부터 응답 결과 화면을 생성하는 View 객체는 ViewResolver가 구한다.
스프링은 몇 가지 ViewResolver 구현 클래스를 제공하고 있는데, 이중 주료 ViewResolver 구현 클래스는 다음과 같다.
3. ViewResolver 인터페이스
package org.springframework.web.servlet;
import java.util.Locale;
public interface ViewResolver{
View resolveViewName(String viewName, Locale locale) throws Exception;
}
ViewResolver는 뷰 이름과 지역화를 위한 Locale을 파라미터로 전달받으며, 매핑되는 View 객체를 리턴한다. 만약, 매핑되는 View 객체가 존재하지 않으면 null을 리턴한다.
4. View 객체
ViewResolver는 응답 결과를 생성할 뷰 객체를 리턴한다. 모든 뷰 클래스는 View 인터페이스를 구현하고 있으며, View 인터페이스는 다음과 같이 정의되어 있다.
public interface View {
String RESPONSE_STATUS_ATTRIBUTE = View.class.getName() + ".responseStatus";
String getContentType();
void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception;
}
getContentType() 메서드는 "text/html"과 같은 응답 결과의 컨텐츠 타입을 리턴한다. render() 메서드는 실제로 응답 결과를 생성한다. render() 메서드의 첫 번째 파라미터인 model에는
컨트롤러가 리턴한 ModelAndView 객체의 모델 데이터가 전달된다. 각각의 View 객체는 이 모델 데이터로부터 응답 결과를 생성하는데 필요한 정보를 구한다.
출처: http://devbox.tistory.com/entry/Spring-ViewResolver-설정 [장인개발자를 꿈꾸는 :: 기록하는 공간]
2014.12.18 23:51
Posted in Programing/Spring by devbox
ViewResolver 설정
뷰 영역 구현
컨트롤러는 최종적으로 결과를 출력할 뷰와 뷰에 전달할 객체를 담고 있는 ModelAndView 객체를 리턴한다.
DispatherServlet은 ViewResolver를 사용하여 결과를 출력할 View 객체를 구하고, 구한 View 객체를 이용하여 내용을 생성한다.
1. 컨트롤러 구현 및 설정 추가
컨트롤러를 구현하려면 먼저 @Contoller 어노테이션을 클래스에 적용한다. 그리고, @RequestMapping 어노테이션을 이용해서 클라이언트의 요청을 처리할 메서드를 지정한다.
package madvirus.spring.chap06.controller;
import java.util.Calendar;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
// @Controller 어노테이션은 해당 클래스가 스프링 MVC의 컨트롤러를 구현한 클래스라는 것을 지정한다.
@Controller
public class HelloController {
// @RequestMapping 어노테이션은 값으로 지정한 요청 경로를 처리한 메서드를 설정한다.
// 이 경우 http://host:port[/컨텍스트 경로]/hello.do 요청을 HelloController 클래스의 hello() 메서드가 처리하게 된다.
@RequestMapping("/hello.do")
public ModelAndView hello() {
//ModelAndView는 컨트롤러의 처리 결과를 보여줄 뷰와 뷰에서 출력할 모델을 지정할 때 사용된다.
ModelAndView mav = new ModelAndView();
// 컨트롤러의 처리 결과를 보여줄 뷰의 이름을 'hello'를 지정한다.
mav.setViewName("hello");
// 모델에 'greeting'이라는 이름으로 String 타입의 값을 추가하였다.
mav.addObject("greeting", getGreeting());
return mav;
}
// 스프링은 ModelAndView 뿐만 아니라 String이나 modelMap, 또는 Map과 같은 타입을 이용해서 뷰 이름과 모델 정보를 설정할 수 있도록 하고 있다.
private String getGreeting() {
int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
if (hour >= 6 && hour <= 10) {
return "좋은 아침입니다.";
} else if (hour >= 12 && hour <= 15) {
return "점심 식사는 하셨나요?";
} else if (hour >= 18 && hour <= 22) {
return "좋은 밤 되세요";
}
return "안녕하세요";
}
}
DispatherServlet은 스프링 컨테이너에서 컨트롤러 객체를 검색하기 때문에 스프링 설정 파일에 컨트롤러를 빈으로 등록해 주어야 한다.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="helloController" class="madvirus.spring.chap06.controller.HelloController" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
스프링 2.5 버전까지는 @Controller 어노테이션이 적용된 클래스를 컨트롤러로 사용하려면 별도의 DefaultAnnoationHandlerMapping과 AnnotationHandlerAdapter를 스프링 설정 파일에 등록해 주어야 한다. 하지만 스프링 3.0부터는 이 두 빈 객체를 기본 구현체로 사용하기 때문에 별도의 설정을 하지 않을 경우 @Controller 어노테이션이 적용된 클래스를 컨트롤러 구현체로 사용할 수 있게 된다.
2. 설정 파일에 ViewResolver 설정 추가
컨트롤러 클래스는 직접 또는 간접적으로 ModelAndView 객체를 생성하게 된다.
예를 들어 앞서 작성한 HelloController 클래스는 다음과 같이 ModelAndView 객체를 생성해서 리턴하였다.
public ModelAndView hello() {
ModelAndView mav = new ModelAndView();
// 뷰이름
mav.setViewName("hello");// setViewName() 메서드를 이용하여 뷰 이름을 지정한 모습
mav.addObject("greeting", getGreeting());
return mav;
}
컨트롤러의 처리 결과를 보여줄 뷰의 이름을 'hello'를 지정하였는데, DispatherServlet은 이 뷰 이름과 매칭되는 뷰 구현체를 찾기 위해 ViewResolver를 사용한다.
JSP를 뷰 기술로 사용할 경우 다음과 같이 InternalResourceViewResolver 구현체를 빈으로 등록해주면 된다.
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="WEB-INF/view"/>
<property name="suffix" value=".jsp/>
// 이는 ViewResolver가 "WEB-INF/view/뷰이름.jsp"를 뷰 JSP로 사용한다는 것을 의미한다.
// 즉, 앞의 예에서 HelloController는 뷰 이름으로 "hello"를 리턴하므로, 실제로 사용되는 뷰 파일은 "WEB-INF/view/hello.jsp"파일이 된다.
</bean>
InternalResourceViewResolver는 컨트롤러가 지정한 뷰 이름으로부터 실제로 사용될 뷰를 선택하는데, 이 때 컨트롤러가 지정한 뷰 이름 앞뒤로 prefix 프로퍼티와 suffix 프로퍼티를 추가한 값이 실제로 사용될 자원의 경로가 된다.
※ ViewResolver 구현 클래스
스프링 컨트롤러는 뷰에 의존적이지 않다. 컨트롤러는 아래 코드와 같이 결과를 생성할 뷰의 이름만 지정할 뿐이다.
컨트롤러가 지정한 뷰 이름으로부터 응답 결과 화면을 생성하는 View 객체는 ViewResolver가 구한다.
스프링은 몇 가지 ViewResolver 구현 클래스를 제공하고 있는데, 이중 주료 ViewResolver 구현 클래스는 다음과 같다.
3. ViewResolver 인터페이스
package org.springframework.web.servlet;
import java.util.Locale;
public interface ViewResolver{
View resolveViewName(String viewName, Locale locale) throws Exception;
}
ViewResolver는 뷰 이름과 지역화를 위한 Locale을 파라미터로 전달받으며, 매핑되는 View 객체를 리턴한다. 만약, 매핑되는 View 객체가 존재하지 않으면 null을 리턴한다.
4. View 객체
ViewResolver는 응답 결과를 생성할 뷰 객체를 리턴한다. 모든 뷰 클래스는 View 인터페이스를 구현하고 있으며, View 인터페이스는 다음과 같이 정의되어 있다.
public interface View {
String RESPONSE_STATUS_ATTRIBUTE = View.class.getName() + ".responseStatus";
String getContentType();
void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception;
}
getContentType() 메서드는 "text/html"과 같은 응답 결과의 컨텐츠 타입을 리턴한다. render() 메서드는 실제로 응답 결과를 생성한다. render() 메서드의 첫 번째 파라미터인 model에는
컨트롤러가 리턴한 ModelAndView 객체의 모델 데이터가 전달된다. 각각의 View 객체는 이 모델 데이터로부터 응답 결과를 생성하는데 필요한 정보를 구한다.
출처: http://devbox.tistory.com/entry/Spring-ViewResolver-설정 [장인개발자를 꿈꾸는 :: 기록하는 공간]
2018년 3월 11일 일요일
npm (소프트웨어)
npm (노드 패키지 매니저/Node Package Manager)은 자바스크립트 프로그래밍 언어를 위한 패키지 관리자이다. 자바스크립트 런타임 환경 Node.js의 기본 패키지 관리자이다. npm이라는 이름의 명령 줄 클라이언트, npm 레지스트리라는 이름의 그리고 공개 패키지와 지불 방식의 개인 패키지의 온라인 데이터베이스로 이루어져 있다. 이 레지스트리는 클라이언트를 통해 접근되며 사용 가능한 패키지들은 npm 웹사이트를 통해 찾아보고 검색할 수 있다. 패키지 관리자와 레지스트리는 npm사에 의해 관리된다.
npm은 온전히 자바스크립트로 작성되어 있으며 모듈 패키징이 엉망으로 완성되는 것을 관찰하고 펄의 CPAN과 PHP의 PEAR와 같은 기타 유사한 프로젝트의 단점들에서 영향을 받은 Isaac Z. Schlueter가 개발하였다.
원저자 Isaac Z. Schlueter
개발자 Rebecca Turner, Kat Marchan, others
발표일 2010년 1월 12일(8년 전)[1]
최근 버전 5.6.0 / 2017년 11월 28일(3달 전)[2]
프로그래밍 언어 자바스크립트
라이선스 아티스틱 라이선스
웹사이트 www.npmjs.com
npm은 온전히 자바스크립트로 작성되어 있으며 모듈 패키징이 엉망으로 완성되는 것을 관찰하고 펄의 CPAN과 PHP의 PEAR와 같은 기타 유사한 프로젝트의 단점들에서 영향을 받은 Isaac Z. Schlueter가 개발하였다.
원저자 Isaac Z. Schlueter
개발자 Rebecca Turner, Kat Marchan, others
발표일 2010년 1월 12일(8년 전)[1]
최근 버전 5.6.0 / 2017년 11월 28일(3달 전)[2]
프로그래밍 언어 자바스크립트
라이선스 아티스틱 라이선스
웹사이트 www.npmjs.com
Spring 개발도구와 환경
Spring 개발도구와 환경
* 본 포스트의 내용은 [토비의 스프링3] 내용에서 발췌된 것이다.
본 포스트의 내용은 Spring 3.0 을 기반으로 한다.
* 스프링으로 어떤것을 만들수 있는가?
스프링으로 만들수 있는 애플리케이션의 종류에는 제한이 없고 자바를 사용하는 모든 프로젝트에 사용할 수 있다. 하지만, 대부분 자바 엔터프라이즈 환경에서 동작하는 어플리케이션이다 (즉 서버에서 동작하여 클라이언트에게 서비스를 제공) 가장 많이 사용하는 구조는 클라이언트가 웹 브라우저이고, 백엔드 시스템이 DB인 구성이다.
* 개발도구와 환경
1. JavaSE/JDK : JDK 5.0 or higher (JDBC 4.0 API를 사용 하는 경우 JDK6.0)
2. JavaEE/J2EE : J2EE 1.4 or JavaEE 5.0 (J2EE 1.4 의 경우 JDK 5.0에서 사용불가능한 경우가 있으므로 주의)
3. IDE : Eclipse(or STS-SpringSource Tool Suite), NetBeans, IntelliJ IDEA
: STS - 최신 이클립스를 기반으로 주요한 스프링 지원 플러그인과 관련 도구들을 모아서 스프링 개발에 최적화되도록 구성된 IDE. 스프링소스가 제공하는 플로거인 조합이 완료된 STS를 사용하면, 플로그인 업데이트와 플러그인간 호환성 등에 신경쓸 필요가 없으므로 편리. 게다가 tcServer 를 함께 설치할수 있어서 편리.
tcServer) Spring 개발을 담당하는 SpringSource 는 apache httpd 서버와 tomcat 의 개발자들이 있어서 스프링어플리케이션에 최적화된 tcServer 를 개발했다. 기술지원을 받을 수 없는 오픈소스제품과 달리, tcServer를 사용하면 기술지원을 받을 수 있음. (개발자 버전은 무료이지만, 정식 운영서버에서 사용하고 기술지원 받으려면 유료 라이선스 구매 필요)
4. 스프링 관련 Plugin(s)
SpringIDE plugin
SpringIDE는 스프링 개발에 유용한 기능을 제공하는 플러그인의 모음. 스프링 프로젝트 설정파일 생성 위저드, XML 설정파일 에디터, bean의 의존관계 그래프, 네임스페이스 관리 기능 등의 기능과 도구를 제공함.
STS plugin
스프링 개발과 설정파일 편집을 지원하는 SpringIDE에 더해서 스프링 어플리케이션의 서버 배치와 같은 추가 기능을 제공해 준다.
STS 가 추가로 제공하는 기타 플러그인
- M2Eclipse : Maven 지원하는 Elipse plugin, 스프링은 그 자체로 20여개의 세부 모듈로 구성되어 있고 100개 이상의 의존 라이브러리가 있기 때문에 Maven의 의존 관리 기능을 활용하는게 좋다.
- AJDT (AspectJ Development Tool) : Elipse 에서 AspectJ AOP 를 이용한 개발을 지원.
- VMCI (Virtual Machine Core Integration) : VMWare 서버 혹은 워크스테이션과의 연동을 지원하는 플러그인. STS의 VMWare 배치기능에 주로 사용
- 이클립스 표준 플러그인 : 이클립스에서 제공하는 주요 표준 플러그인으로 웹 개발을 지원하는 WTP(Web Tool Platform), EMP(Elipse Modeling Project), Mylyn, DSDP(Device Software Developlemt Platform)
* 스프링 애플리케이션의 배포 단위
1. 독립 웹 모듈 (war) : 가장 일반적
2. 엔터프라이즈 애플리케이션 (ear) : 스프링애플리케이션에서 EJB 모듈을 이용하거나 EJB모듈이 스프링어플리케이션을 이용해야 하면, EJB와 스프링웹 모듈을 엔터프라이즈 애플리케이션으로 통합해서 배포해야 한다.
3. 백그라운드 서비스 모듈 (rar) : rar 는 리소스 커넥터를 만들어 배포할 때 사용하는 방식인데, 스프링어플리ㅔ이션이 UI가 없고, 서버내에서 백그라운드 서비스 처럼 동작할 필요가 있다면 rar 모듈로 만들어 배포할 수 있다.
* 라이브러리 관리와 빌드 툴
스프링은 자체로 20여개의 jar 모듈과 직접 참조하는 100개 이상의 의존 라이브러리가 있다. 이들의 버전관리도 문제지만, 모든 라이브러리가 다 사용되는게 아니므로, 라이브러리를 선정하는 것도 문제이다.
20여개이 모듈중 몇개는 필수모듈이지만 그 외의 모듈은 애플리케이션의 아키텍처와 사용기술에 따라 서택적으로 적용할 수 있다. 또한 스프링 모듈 사이에도 의존관계가 있고, 모듈의 의존 관계는 필수와 선택으로 나뉠 수 잇다.
- Elipse 같은 IDE의 자동 빌드 기능이 있고, 관련 빌더를 추가/확장 하는 것으로 빌드 작업을 간소화 시킬 수 있지만, IDE를 통한 빌드 환경이 아닌 경우에도 일관성 있는 빌드가 가능하도록 만들기 위해서, Maven 이나 Ant 같은 환경에 독립적인 빌드 툴을 함께 사용하는것이 바람직 하다. 그 중 절차적인 스크립트와 비슷한 Ant와 달리 Maven 은 POM을 이용하여 선언적으로 관리할 수 있다. 더 매력적인 점은 Maven의 의존 라이브러리 관리 기능이 Transitive (전이적)이고, 이는 스프링의 모든 모듈이 POM 정보를 가지고 있으므로, 스프링을 통한 라이브러리 관리를 좀더 편리하게 도와준다.
* 관련 web sites
* STS : http://www.springsource.com/downloads/sts
* Ecllipse : http://www.eclipse.org/downloads
* Eclipse Maven Plugin : http://www.eclipse.org/m2e/
출처: http://lefthand.tistory.com/43 [lefthand's note]
Spring 의 정의와 목적
* 본 포스팅 내용은 토비의 스프링3의 8장의 내용을 요약한 것이다.
Spring 이란 무엇인가?
자바 엔터프라이즈 개발을 편하게 해주는 오픈소스 경량급 애플리케이션 프레임워크
창시자 : Rod Johnson
기원 : Expert One-on-One J2EE Design and Development (2003) 의 sample code
- 애플리케이션 프레임워크
일반적으로 라이브러리나 프레임워크는 특정 업무 분야나 한가지 기술에 특화된 목표(예를들면, 웹 계층을 MVC구조로 변경한다거나, 간단한 설정만으로 RDB와 java object를 매칭해주는 ORM기술 제공등)를 가지고 만들어 지지만, 애플리케이션 프레임 워크란 특정 계층이나, 기술, 업무분야에 국한되지 않고 애플리케이션의 전 영역을 포괄하는 볌용적인 프레임워크이다. 애플리케이션 프레임워크는 애플리케이션 개발의 전 과정을 빠르고 편리하며 효율적으로 진행하는데 일차적인 목표를 두는 프레임워크이다.
- 경량급(lightweiight)
스프링 자체가 아주 가볍다거나 작은 규모의 코드로 이뤄졌다는 뜻이 아니다. 스프링은 20여개의 모듈로 세분화 되고 수십만 라인에 달하는 코드를 가진 방대한 규모의 프레임워크이다. 경량급의 의미는 EJB같은 과도한 엔지니어링이 적용된 기술에 대비하여 불필요하게 무겁지 않다는 의미이다.
EJB : 고가의 WAS필요, 난해한 설정파일, 까다로운 패키징, 불편한 deploy 등으로 인한 부담으로 인해 고가의 제품으로 구성된 제대로된 개발환경이 없이 개발이 어려움. 스프링은 tomcat 이나 jetty 에서도 완벽하게 동작한다. 즉, 서블릿 컨테이너만으로 충분하니, EJB컨테이너나 기타 기능을 사용하지 않아도 된다.
(1) 개발환경의 lightweight
(2) 서버 환경의 lightweight
(3) 코드의 상대적인 lightweight
- 자바 엔터프라이즈 개발을 편하게
로우레벨의 트랜잭션이나 상태관리, 멀티스레딩, 리소스 풀링 같은 복잡한 로우레벨 API 를 이해하지 못하더라도 아무런 문제 없이 어플리케이션을 개발할 수 있다.(From Enterprise JavaBeans 1.0 Specification, Chapter 2 Goals)
로우레벨 기술에 신경쓰지 않으면서, 애플리케이션의 핵심인 사용자의 요구사항, 비즈니스 로직을 빠르고 효과적으로 구현하는 것. 즉, 초기에 스프링의 기본 설정과 적용기술만을 잘 이해하고 있으면, 애플리케이션 개발중에는 스프링 관련 Code 에 신경쓸 필요가 없다.
- 오픈소스
스프링은 오픈소스 프로젝트 방식으로 개발되왔다. 지금도 여전히 오픈 소스 개발 모델과 라이선스를 가지고 개발하는 중이다.
라이센스 : Apache Licence Ver 2.0 (스프링을 상업제품에 포함시키거나 비공개프로젝트에서 사용해도 된다. (수정자유롭고 수정된 소스 공개 필요없음)
Spring 의 Goal
- 엔터프라이즈 개발의 복잡함
2000년대 초반 80% 이상의 자바 enterprise project 가 실패했다. 가장 대표적인 이유는 엔터프라이즈 시스템 개발이 너무 복잡해서 이다.
왜 복잡한가? 비즈니스 로직 이외에도 기술적으로 고려해야 할 사항들이 많다.(타시스템 과의 연계, 다양한 형태의 클라이언트 접속을 위한 리모팅 기술, 분산 트랜잭선의 지원, 보안 등) 또한 비즈니스 로직 자체도 점점 복잡해지고 잦은 변경이 요구된다)게다가 이런 엔터프라이즈 기술의 복잡함과 비즈니스 로직의 복잡함이 한데 얽혀서 복잡함이 배가된다.
- 복잡함을 해결하려는 도전
근본적으로 엔터프라이즈 기술의 복잡함과 비즈니스 로직의 복잡함은 줄일수 없다. 그러나 이 두가지 성질이 다른 복잡함을 분리해 낼수 있다. EJB도 이 목표를 지향하여 선언전 트랜잭션이나 선언적 보안, 컨테이너를 통한 리모팅 기술의 적용, 컴포넌트 단위의 배치, JNDI 를 통한 서비스 검색지원, 서비스 오브젝트의 풀링, 컴포넌트의 생명주기 관리등을 수행하여 이 목표를 달성하려 하였으나, 이를 위해 EJB라는 환경과 스펙에 종속되는 코드로 만들어야 하는 더 큰 복잡함을 안게되어 실패하였다. 게다가 EJB라는 틀 안에서 특정클래스를 상속하게 함으로 자바 언어의 원래 장점마저 상실하고 객체지향적인 특성을 잃어버진 서비스 스크립트성 코드로 변질돼 갔다.
스프링은 EJB와는 다르게 비침투적(non-invasive)기술을 적용하였고, 이는 코드상에 스프링과 관련된 규약과 코드가 등장하지 않는 것을 의미한다. 즉, 스프링이 코드에 불필요하게 등장해서 복잡함을 가중시키지 않는다.
- 복잡함을 상대하는 스프링의 전략
** 기술적 복잡함은 아래와 같이 서비스의 추상화와 AOP 로 상대한다.
1. 서비스의 추상화
트랜잭션 추상화, OXM 추상화, 데이터 액세스에 관한 일관된 예외변환 기능, 데이타 액세스 기술에 독립적인 트랜잭션 동기화 기능 등. 기술적인 복잡함은 추상화를 통해 로우레벨의 기술 구현 부분과 기술을 사용하는 인터페이스를 분리하고, 환경과 사용기술에 독립적인 접근 인터페이스를 제공한다.
2. AOP (Aspect Oriented Programming)
비즈니스 로직 전후로 경계가 설정되어야 하는 트랜잭션, 보안적용, 예외처리, 로깅, 감사 등 기술과 비즈니스 로직의 혼재는 최대한 제거해도 완전히 해결할 수 없으며, 이를 해결하기 위한 스프링의 전략이 AOP 이다. AOP는 최후까지 애플리케이션 로직에 남아있는 기술관련 코드를 깔끔하게 분리해서 별도의 모듈로 관리하게 해주는 강력할 기술이다.
** 비즈니스 로직의 복잡함을 상대하는 전략은 객체지향과 DI이다.
1. OOAD (Object Oriented Analysis & Design)
복잡함을 단순화 할 수 있는 것은 객체지향 기술 자체이며, 스프링은 환경 종속적이지 않고 비침투적인 기술이므로 핵심로직을 다루는 코드에는 스프링이 드러나지 않는다. 따라서 객체지향언어의 장점을 살려 로직의 복잡함을 효과적으로 다루어야 한다.
2. DI (Dependency Injection)
DI는 특별한 기술이라기 보다는 유연하게 확장가능한 오브젝트 설계를 하다보면 자연스럽게 적용하게 되는 객체지향 프로그래밍 기법이다. 스프링은 단지 그것을 더욱 편하고 쉽게 사용하도록 도와줄 뿐이다. DI는 적용하려다 보면 자연스럽게 확장성이 좋은 설계로 이끌어진다. 즉, 바뀔 수 있는 것은 무엇인가? 무엇이 성격이 다른가? 를 지속적으로 고민하게 되고 대상이 되는 Object는 DI를 적용해 분리하고, 인터페이스를 도입하고, DI로 관계를 연결해 주게 되므로 DI를 열심히 적용하다 보면 객체지향 설계의 원칙을 잘 따르고 그 장점을 살린 설계가 나올수도 있다.
출처: http://lefthand.tistory.com/42 [lefthand's note]
Singletone Pattern & Spring IoC Container
* 본 포스트의 내용은 [토비의 스프링3] 내용에서 발췌된 것이다.
* 내용
싱글톤 패턴으 GoF 의 디자인 패턴중 하나다. 디자인 패턴 중에서 가장 자주 활용되는 패턴이기도 하지만, 가장 많은 비판을 받는 패턴이기도 하다. 싱글톤 패턴은 어떤 클래스를 어플리케이션 내에서 제한된 인스턴스 수, 주로 하나만 존재하도록 강제하는 패턴이다. 이렇게 하면 이 클래스의 오브젝트는 애플리케이션 내에서 전역적으로 접근이 가능하다. 단일 오브젝트만 존재해야 하고, 이를 애플리케이션의 여러 곳에서 공유하는 경우에 주로 사용한다.
* Java 에서 Singleton 을 구현하는 일반적인 방법
- 생성자를 private 으로 설정하여 클래스 밖에서는 오브젝트를 생성하지 못하게 함
- 생성된 singleton 오브젝트를 저장할 수 있도록 클래스 내에 자신과 같은 타입의 static field 정의
- static factory method 인 getInstance()를 만들어 최초 호출 시점에만 오브젝트 생성하고 static field 에 저장.
public class UserObject {
private static UserObject INSTANCE;
...
private UserObject(..) {
..
}
public static synchronized UserObject getInstance() {
if (INSTANCE == null) INSTANCE = new UserObject(..);
return INSTANCE;
}
}
* Java 에서 위와같이 singleton을 구현하는 경우 singleton pattern 의 한계
- private 생성자를 갖고 있기 때문에 상속할 수 없다.
객체지향의 상속과 다형성 적용 불가
- 테스트가 어렵다.
싱글톤은 만들어지는 방식이 제한적이므로 테스트에서 Mock Object 로 대체하기가 힘들다.
- 서버환경에서는 singleton 이 하나만 만들어지는 것을 보장하지 못한다.
서버에서 class loader 를 구성하는 방법에 따라서 하나 이상의 오브젝트가 만들어 질 수 있다.
- 싱글톤의 사용은 전역 상태를 만들 수 있기 때문에 바람직 하지 못하다.
singleton의 static method 를 이용하여 어떤 client 라도 접근/사용할 수 있으므로, 전역상태(global status)로 사용되기 쉽다. 아무 객체나 자유롭게 접근/수정/공유하는 전역상태는 OOP에서는 권장되지 않는다.
* Spring Framework 에서의 singleton
Spring은 서버 환경에서 singleton으로 service object 를 사용하는 것을 지지한다. 다만, java 의 기본적인 singleton 구현방식은 상기의 단점이 있으므로, Spring Framework 자체에서 singleton 형태의 object를 만들고 관리하는 기능인, singleton registry 를 제공한다.
Spring의 ApplicationContext 는 Singleton을 저장하고 관리하는 Singleton registry 이다.
* Spring Registry
Spring 은 디폴트로 내부에서 생성하는 Bean object 를 singleton으로 만든다. 이것은 디자인 패턴의 싱글톤과 비슷한 개념이지만, 구현방법은 확연히 다르다. 즉, Spring container 에서 object 를 singleton registry 에 관리하며 singleton으로 동작하도록 제어한다.
왜 Spring은 singleton으로 bean 을 생성하는 것일까?
하나의 요청(Request)를 처리하기 위해서는 데이타 액세스 로직(DAO), 서비스 로직, 비즈니스 로직, 프리젠테이션 로직등 다양한 기능을 담당하는 오브젝트들이 계층형 구조로 이루어 진다. 매번 클라이언트 요청이 올때마다, 각 로직을 담당하는 오브젝트들을 새로 만들어 사용한다면, 아무리 Java가 오브젝트 생성과 GC(Garbage Collection) 성능이 좋아졌어도 서버가 부하를 감당하기 심들다. 이 때문에 엔터프라이즈 분야에서는 서비스오브젝트 라는 개념을 사용해 왔는데 Servlet 은 Java 엔터프라이즈 기술의 가장 기본이 되는 서비스 오브젝트라고 할수 있다. Servlet은 대부분 멀티스레드 환경에서 Singleton으로 동작한다. 즉, Servlet 클래스 당 하나의 오브젝트만 만들어 주고, 사용자의 요청을 담당하는 여러 스레드에서 하나의 오브젝트를 공유해서 사용한다.
Singleton registry 덕분에 singleton 으로 동작해야 할 어떤 클래스라도 평범한 java class 로 작성될 수 있다. 즉, public 생성자를 가질 수 있으며 static method 를 노출할 필요도 없다. 이것은 테스트 환경에서 자유롭게 object 를 만들 수 있고 또한 OOP의 장점을 그대로 가진다.
* Spring 에서 Singleton object 로 사용할 클래스 설계시 주의점
Spring 에서 singleton 이 멀티스레드 환경에서 서비스 오브젝트에 사용되는 경우에는 상태정보를 내부에 갖고 있지 않은 stateless 로 만들어야 한다. 이 경우, 각 요청에 대한 정보나 생성된 정보는 메소드 파라미터나 메소드 안의 로컬변수 혹은 리턴값 등으로 처리해야 한다. 싱글톤이라해도 메소드 안에서 생성되는 로컬변수는 method가 호출될 때마다 매번 새로 할당되므로 싱글톤이라 해도 여러 스레드가 변수의 값을 덮어쓸 일은 없다.
public class UserDao {
private ConnectionMaker connectionMaker; <-- (1)
private Connection c; <-- (2)
private User user; <-- (2)
public User get(String id) throws ClassNotFoundException, SQLException {
this.c = connectionMaker.makeConnection();
....
this.user = new User();
this.user.setId("...");
...
return user;
}
}
UserDao 는 IoC container 에 의해서 singleton object 로 생성/사용된다고 가정해 보자.
이런 경우, (2)번과 같이 멀티스레드 환경에서 변경될 수 있는 값을 클래스의 인스턴스 변수로 생성하는 경우, 문제가 발생한다. 따라서 Spring 의 singleton bean 으로 사용되는 클래스를 만들때는 (2)번의 경우는 method 내 로컬 변수로 사용하거나 파라미터로 주고 받으며 사용해야 한다.
단, 이 경우에도 클래스 인스턴스 변수로 사용가능한 경우가 있는데 이는 (1) 과 같다.
(1)은 자신이 사용하는 다른 singleton bean 을 저장하려는 용도라면, 인스턴스 변수로 사용해도 좋다. 스프링이 초기화 되고 나면, 이후에 수정되지 않는 경우라면, 멀티스레딩 환경에서 사용해도 문제없다
* Spring bean 의 스코프
scope : 스프링이 관리하는 오브젝트, 즉 빈의 생성/존재/소멸되는 범위
singleton : 스프링 bean 의 기본 scope 는 singleton 이다. 컨테이너 한개에 한개만 생성되며 강제로 제거하지 않는 한 컨테이너가 존재하는 동안 계속 유지된다.
prototype : 컨테이너에 빈을 요청할 때마다 매번 새로운 오브젝트를 만들어준다.
request : 웹을 통해 HTTP 요청시마다 생성되는 scope
session : 웹의 세션과 유사한 scope
출처: http://lefthand.tistory.com/41 [lefthand's note]
POJO (Plain Old Java Object)
* 본 포스트의 내용은 [토비의 스프링3] 내용에서 발췌된 것이다.
POJO (Plain Old Java Object) ?
1. 특정 규약(contract)에 종속되지 않는다.
Java 언어와 꼭 필요한 API 외에 종속되지 않는다. EJB2 의 EntityBean 상속이나 Struts 1 의 ActionForm 상속등 규약에 종속되지 않아야 한다.
2. 특정 환경에 종속되지 않는다.
EJB3 의 JNDI 서버 서비스의 의존이나 특정 벤더의 서버나 기업프레임워크안에서만 동작 가능한 코드가 아니다.
3. 객체지향원리에 충실해야 한다.
특정 기술규약과 환경에 종속되지 않은 Java Object 가 모두 POJO라 할수는 없다. 객체지향 개념이 녹아있지 않은 것만 POJO 이다.
Why POJO?
1. 코드의 간결함
비즈니스 로직과 특정 환경/low 레벨 종속적인 코드를 분리하므로 단순하다.
2. 자동화 테스트에 유리
환경 종속적인 코드는 자동화 테스트가 어렵지만, POJO 는 테스트가 매우 유연하다.
3. 객체지향적 설계의 자유로운 사용
특정 규약 종속적인 객체의 경우 특정 상속을 미리 지정해서, 단일상속만 제공하는 JAVA 언어로서는 더이상 객체지향적 설계를 하는데 제약을 가져오는 경우가 있으나, POJO 는 아무런 규약이나 규제가 없으므로 OO 설계에 매우 자유롭다.
What is POJO Framework?
POJO 프로그래밍이 가능하도록 기술기반을 제공하는 Framework.
1. Spring Framework
엔터프라이즈 기술에만 최소한으로 관여하고 비즈니스 로직을 담당하는 POJO에서는 관여하지 않는다.
2. Hibernate
Spring 의 핵심 기술?
기술과 비즈니스로직을 분리하고 POJO방식의 어플리케이션 개발을 가능하게 한다는 스프링의 목적을 쉽게 이루려면 스프링과 같은 POJO 프레임워크가 필요하다.
POJO 프로그래밍을 손쉽게 할 수 있도록 지원하는 세가지 가능기술(Enabling technology)
(1) IoC/DI (Inversion of Control / Dependency Injection)
IoC/DI 는 스프링의 가장 기본의 되는 기술이자 스프링의 핵심 개발원칙이다. 나머지 두가지 기술인 AOP 와 PSA도 IoC/DI에 바탕을 두고 있으며, 3대기술은 아니지만 자주 등장하는 템플릿/콜백 패턴의 적용도 IoC/DI가 핵심원리다.
(2) AOP (Aspect Oriented Programming)
핵심 관심사를 분리하여 프로그래매 모듈화를 향상시키는 프로그래밍 스타일이다. AOP는 객체를 핵심 관심사와 횡단 관심사로 분리하고, 횡단 관심사를 관점(Aspect)라는 모듈로 정의하고, 핵심 관심사와 엮어서 처리할 수 있는 방법을 제공한다. 스프링은 자체적으로 프록시 기반의 AOP를 지원하며, 로깅, 트랜잭션, 보안 이런것들이 전반적으로 처리하는데 사용됨.
(3) PSA (Portable Service Abstraction)
인터페이스가 다른 다양한 구현을 같은 방식으로 사용하도록 중간에 인터페이스 어댑터 역할을 해주는 레이어를 하나 추가하는 방법
출처: http://lefthand.tistory.com/40 [lefthand's note]
IoC(Inversion of Control) / DI(Dependency Injection)
* 본 포스트의 내용은 [토비의 스프링3] 내용에서 발췌된 것이다.
What is IoC (Inversion of Control)?
프로그램의 제어 흐름 구조가 뒤바뀌는 것.
일반적으로, main() 같은 프로그램이 시작되는 지점에서 다음에 사용할 오브젝트를 결정하고, 생성하고, 만들어진 오브젝트내의 메소드를 호출하고 하는 작업이 반복된다. 이런 프로그램 구조에서 각 오브젝트는 프로그램 흐름을 결정하거나 사용할 오브젝트를 구성하는 작업에 능동적으로 참여한다. 즉, 모든 종류의 작업을 사용하는 쪽에서 제어하는 구조이다.
제어의 역전이란, 제어 흐름의 개념을 거꾸로 뒤집는 것이다. 오브젝트는 자신이 사용할 오브젝트를 스스로 생성하거나 선택하지 않는다. 또한 자신도 어떻게 만들어지고 어디서 사용되는지 알수 없다. 모든 제어 권한을 자신이 아닌 다른 대상에게 위임한다. 프로그램의 시작을 담당하는 main()같은 엔트리 포인트를 제외하면 모든 오브젝트는 이렇게 위임받은 제어 권한을 갖는 특별한 오브젝트에 의해 결정되고 만들어 진다. 단지 스프링에서 사용되는 개념이 아니고, 매우 폭넓게 사용되는 프로그래밍 모델이다.
- 작업을 수행하는 쪽에서 Object 를 생성하는 제어 흐름의 개념을 거꾸로 뒤집는다.
- IoC 에서는 Object 가 자신이 사용할 Object 를 생성하거나 선택하지 않는다.
- 또한 Object 는 자신이 어떻게 생성되고 어떻게 사용되는지 알 수 없다.
- 모든 Object 는 제어 권한을 위임받는 특별한 Object 에 의해서 만들어 지고 사용된다.
What is DI (Dependency Injection) ?
- Spring이 지원하는 IoC방식을 좀더 명확히 설명.
- dependent object(의존 오브젝트) : 사용 대상이 되는 오브젝트
- 의존 오브젝트와 그것을 사용할 주체, 보통 클라이언트라고 부르는 오브젝트를 런타임시에 연결해 주는 작업.
의존관계주입의 조건
- 클래스 모델이나 코드에는 런타임 시점의 의존관계가 드러나지 않는다. (즉, 인터페이스에만 의존)
- 런타임 시점의 의존관계는 컨테이너나 팩토리같은 제 3의 존재가 결정한다.
- 의존관계는 의존 오브젝트 레퍼런스를 외부에서 제공(주입)해줌으로 만들어진다.
IoC 개념이 녹아 있는 Example
1. servlet 과 container.
: 서블릿에 대한 제어권한을 가진 컨테이너가 적절한 시점에 서블릿 클래스의 오브젝트를 만들고 그 안의 메소드를 호출한다.
2. Template Method Pattern (Design Pattern)
: http://lefthand.tistory.com/34
역시 제어권을 상위 템플릿 메소드에 넘기고 서브 클래스는 필요할 때 호출되어 사용되는 개념.
3. Framework
: 라이브러리를 사용하는 어플리케이션은 어플리케이션의 흐름을 직접 제어하지만, 프레임워크는 애플리케이션 코드가 프레임워크에 의해서 사용된다. 보통 프레임워크 위에 개발한 클래스를 등록해 두고, 프레임워크가 흐름을 주도하는 중에 개발자의 어플리케이션 코드를 사용하도록 만드는 방식이다. 즉, 제어의 역전 개념이 적용되어 있어야 한다.
스프링 IoC의 용어 정리
* bean
: 스프링에서 제어권을 가지고 직접 만들고 관계를 부여하는 오브젝트를 bean 이라 부른다. 자바빈, EJB의 빈과 비슷한 오브젝트 단위의 애플리케이션 컴포넌트를 말한다. 하지만 스프링을 사용하는 애플리케이션에서 만들어지는 모든 오브젝트가 빈은 아니다. 스프링의 빈은 스프링 컨테이너가 생성과 관계설정, 사용등을 제어해주는 오브젝트를 가리킨다.
* bean factory
스프링의 IoC를 담당하는 핵심 컨테이너를 가리킨다. 빈을 등록/생성/조회/반환/관리한다. 보통은 bean factory 를 바로 사용하지 않고 이를 확장한 application context 를 이용한다. BeanFactory 는 bean factory 가 구현하는 interface 이다. (getBean()등의 메소드가 정의되어 있음)
* application context
bean factory를 확장한 IoC 컨테이너이다. 빈의 등록/생성/조회/반환/관리의 기능은 bean factory 와 같지만, 여기에 spring 의 각종 부가 서비스를 추가로 제공한다. ApplicationContext는 application context가 구현해야 하는 interface이여, BeanFactory 를 상속한다.
* 설정정보/설정 메타정보 configuration metadata
application context 혹은 bean factory 가 IoC를 적용하기 위해 사용하는 메타정보이다. 스프링의 설정정보는 컨테이너에 어떤 기능을 세팅하거나 조정하는 경우에도 사용하지만 주로 bean 을 생성/구성하는 용도로 사용된다.
* container (IoC container)
IoC 방식으로 bean을 관리한다는 의미에서 bean factory 나 application context 를 가리킨다. (spring container = application context) application context는 그 자체로 ApplicationContext 인터페이스를 구현한 오브젝트를 가리키기도 하는데, 하나의 애플리케이션에 보통 여러개의 ApplicationContext Object가 만들어진다. 이를 통칭해서 strping container라고 부를 수 있다.
* spring framework
spring framework 는 IoC container, application context 를 포함해서 spring이 제공하는 모든 기능을 통칭할때 주로 사용된다.
Spring 에서 IoC/DI 활용 방법:
* DI를 이용한 핵심기능의 변경
디자인 패턴의 전략패턴에 해당하는 의존 대상의 implementation 의 변경에 사용함.
A->B 에서 A 기능 일부를 B에게 위임하는 경우 필요에 따라 B의 구현방식을 통째로 B1, B2, B3로 변경한다.
ex) DAO의 구현을 JDBC, JPA, Hibernate, JDO, iBatis 등으로 변경
ex) 사용자 등급 결정 정책을 DI로 새오운 클래스로 변경
* 핵심기능의 동적인 변경
DI 도 runtime 시에 동적으로 의존 Object 를 연결해 주긴 하지만, DI되면 정적인 관계가 형성된다. 하지만 DI 를 잘 이용하면, 애플리케이션이 동작하는 중간에 의존 대상을 dynamic 하게 변경할 수 있다.
ex)사용자 등급에 따른 DataSource의 선택
DAO->DataSource 일때, DAO 하나가 여러개의 DataSource 에 의존하게 만들어, 현재 접속한 사용자의 등급에 따라서 다른 DataSource 를 DAO가 사용하도록 한다.
ex) 사용자 별로 독립 Object 만들고 서비스 Object가 이를 DI 받아서 사용하는 경우.
* 부가기능의 추가
DI의 다른 활용방법은 핵심기능은 그대로 두고 부가기능을 추가하는 것이다. Decoration Pattern 의 경우임.
ex) 트랙잭션 기능 부여.
핵심 기능은 그대로 두고 결과나 전달 파라미터를 조작할 수 있고, 파라미터나 리턴 결과를 활용해 로깅이나 보안처리 같은 부가적인 작업을 수행 할 수도 있다. 이베트 발생 처리 등등.
* 인터페이스의 변경
클라이언트가 사용하는 실제 인터페이스와 실제 오브젝트 사이의 인터페이스가 일치하지 않는 경우에도 DI 는 유용하다. A->B인터페이스 고, C는 B인터페이스를 구현하지 않았더라도 A가 DI를 통해 B를 사용하므로, B의 구현 오브젝트에서 C를 호출해 주는 어댑터 처럼 동작하면 된다.
PSA (Portable Service Abstraction): 이를 좀 더 일반화 하여 아예 인터페이스가 다른 다양한 구현을 같은 방식으로 사용하도록, 중간에 인터페이스 어댑터 역할을 해주는 레이어를 하나 추가하는 방법이다.
* 프록시
laze loading(필요한 시점에서 실제 사용할 오브젝트를 초기화, 준비) 할때, 또는 원격 오브젝트를 호출할 때 마치 로컬에 존재하는 오브젝트 처럼 사용할 수 있도록 할때 프록시가 필요하고, 이 경우 DI를 필요로 한다. Spring이 지원하는 리모트 기술은 EJB원격호출, 웹 서비스, REST, HTTP 등 다양하다.
* 템플릿과 콜백
템플릿/콜백 패턴은 DI의 특별한 적용방법이다. 반복적으로 등장하지만, 항상 고정적인 작업 흐름과 그 사이에서 자주 바뀌는 부분은 분리해서 템플릿과 콜백으로 만들고 DI원리를 응용해 적용한다. Spring 이 기본으로 제공하는 20여가지의 템플릿/콜백외에도 직접 응용할 수 있어야 한다.
* Singleton 과 Object Scope
DI를 프레임워크로 이용한다는건 DI대상 오프젝트를 컨터이너가 관리한다는 의미이다. 오브젝트의 생성부터 관계설정, 이용, 소멸에 이르기까지 모든 과정을 DI컨테이너가 주관하기 때문에, 그 오브젝트의 스코프를 자유롭게 제어할 수 있다. 스프링의 DI는 기본적으로 singleton으로 오브젝트를 만들어서 사용하게 하고, 컨테이너가 알아서 싱글톤을 만들고 관리하므로 클레스 자체는 싱글톤을 고려하지 않아도 된다. 물론, 스프링에서는 싱글톤 외에도 다양한 스코프를 갖는 오브젝트를 만들어 DI 할 수 있다.
* 테스트
DI의 또다른 중요한 용도는 Test 이다.테스트 할 대상이 사용하는 오브젝트를 테스트 목적으로 만들어진 Mock 오브젝트로 대체하면 테스트가 매우 용이하다.
출처: http://lefthand.tistory.com/39 [lefthand's note]
apache module configuration
httpd.conf 에 LoadModule 되는 (혹은 static library로 포함되는) apache module 은 각각의 설정을 저장하기 위해 config 객체를 사용할 수 있다. 이 config 객체를 사용하는 경우 각 서버(virtual server 와 기본서버)별로 각각 생성된다. apache module config 객체를 사용하기 위해서, apache module 은 모듈 정의 부분에서 function을 지정할 수 있으며, 편의상 이하 이 function 을 create_server_config라 임의로 지칭하기로 한다.
[create_server_config function 호출 시기]
static void * (*pf_create_server_config) (apr_pool_t *p, server_rec *s);
1. apache start/stop 시 전역적으로 최소 1번 호출됨.
: default module config 객체를 생성과 초기 설정이 이루어짐.
apache 서버가 default server 이외에 1개 이상의 virtual server 를 구성하는 경우, 각 Virtual Server 에서 작성된 apache module 의 configuration command 를 사용하지 않으면, 이때 생성된 config 내 용이 각각의 virtual server module config 객체로 복제 된다.
2. 각 Virtual server 별로 overriding 가능
: 만약 virtual server 내에 configuration command 를 하나 이상 정의하면, 그때는 default module config 객체를 복제하지 않고, create_server_config 함수가 virtual server 를 위해 다시 호출된다.
! CAUTION1) create_server_config 에 전달되는 server_rec * 은 1번의 경우, host 정보가 null 로 들어오며, 2번의 경우에는 각 virtual server 의 설정 값을 갖는다.
!CAUTION2) create_server_config 는 configuration commend 호출 전에 호출돤다.
!CAUTION3) 전달되는 pool 은 pConf 이다. (apache pool hiarachy 참고)
[ap_hook_post_config 이용]
static int (*pf_post_config) (apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s);
apache module 은 여러가지 hook 을 제공하며, 사용자들이 기능을 추가/변경 할수 있도록 한다. module config 를 위해서 command 를 다 읽은 후에 설정 내용을 변경/수정 할수 있도록 ap_hook_post_config 를 제공하며, 여기에 기능을 추가 할 수 있다.
각 Virtual server 별로 설정을 달리 해야 할 것들이 있다면 여기서 수행하면 된다.
!CAUTION1) server_rec * 구조체에는 default server 와 Virtual Server 들을 모두 참조가능하도록 default server 의 server_rec 이 전달되며, s = s->next 값으로 모든 서버들의 설정을 검토할 수 있다.
!CAUTION2) 전달되는 pool 은 pConf 이다. (apache pool hiarachy 참고)
module config 는 각 서버당 1개씩 생성되고, 프로세스 간 공유되므로, 기본적으로 최초 apache 로딩 시 값 설정 후에는 실제 서비스에서 변경하지 않는 것이 좋다. 만약 module config 를 변경해야 할 일이 있다면, pConf 에 mutex 를 생성하여 사용해야 한다.
개인적으로는, mutex 사용보다는 메모리가 충분하다면, apache 가 MPM 이 prefork 방식인 경우, 각 process 별로 메모리를 전역으로 복제/갱신하여 사용하는 것이 더 나을 수 있다. (물론 메모리 크기와 갱신 주기 등등 여러가지를 고려해야 함)
출처: http://lefthand.tistory.com/38 [lefthand's note]
Rewrite & Redirect
아파치 설정의 Rewrite 와 Redirect 에 대해서 간략히 정리한다.
301 Redirect : Permanent Redirect, 브라우저에서 해당 내용을 cache 하여 다음에 요청시에 직접 변경된 주소로 접속한다.
302 Redirect : Temporary Recirect,
<mod_alias.c>
base 모듈(apache 설치시 디폴트로 함께 설치되는 모듈)
default - 302 Redirect (Temporary)
Redirect
RedirectMatch
<mod_rewrite.c>
Extension 모듈 (apache 설치 시 선택하여 설치해야 하는 모듈, static, dynamic 모두 가능)
!main server의 설정이 각각의 virtual host 에 상속되지 않는다. virtual host 별로 각각 설정해 줘야함.
default - 302 redirect
옵션 :
[NC] no-casesensitive
[NE] no-escape
[R] 주소창이 변하기 않기를 원할때
[L] last 적용
[OR] 컨디션의 or
...
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond
RewriteRule
</IfModule>
RewriteRule ^products/([0-9][0-9])$ /products/$1/ [R]
$1, $2, .. $9 첫번째그룹, 두번째 그룹...
출처: http://lefthand.tistory.com/31 [lefthand's note]
blocking/non-blocking socket
* Blocking Socket
- default 값 (socket() 으로 생성되는 기본값)
- connect : connection completion 까지 block
- read : 버퍼에 읽을 값이 없으면 block
- write : 버퍼가 꽉 차서 쓸 수 없으면 block
- accept : backlog queue 에 값이 없으면 block
: blocking 소켓 통신에서 어떤 에러 결과든지 메소드는 자동으로 에러를 규명하는 코드를 같이 리턴한다. 에러는 네트워크 종료, 닫힌 소켓, 아이오 에러 등이 될 수 있다
동기식 통신을 사용한다면 blocking 통신이 더 낫다.
* Non-blocking Socket
- connect : connection 요청 후 즉시 return. connection 이 완료되었는지 보증 안됨.(getsockopt 로 확인)
- read : 버퍼에 읽을 값이 없으면 -1 return (errno : EWOULDBLOCK or EAGAIN)
- write : 버퍼가 꽉 차서 쓸 수 없으면 -1 return (errno :EWOULDBLOCK or EAGAIN)
- accept : backlog queue 에 값이 없으면 -1 return (errno : EWOULDBLOCK or EAGAIN)
: 할수 있는 일이 없으면, 종료하고, 다른 작업(?) 을 할 수 있고, 할 수 있는 일이 있을 때만 작업한다.
비동기식 통신에서는 소켓이 묶이는 것을 피하기 위해 non-blocking 통신이 필요하다.
* Nonblocking socket 설정
int flag, sock_fd;
sock_fd = socket (AF_INET, SOCK_STREAM, 0);
flag = fcntl (sock_fd, F_GETFL, 0);
fcntl ( sock_fd, F_SETFL, flag|O_NONBLOCK );
* timeout 설정
출처: http://lefthand.tistory.com/29 [lefthand's note]
Linux 에서 사용자별 메모리 문제 발생시 대응 방법
본 문서에서는 Linux 에서 OOM(Out-Of-Memory) 발생 시 대응 방법들이다.
1. 문제 발생 방지
[설정파일을 통한 limit (/etc/security/limits.conf)]
: 각 사용자 혹은 그룹등에 리소스 사용 제약사항을 걸어두면, 자원의 무제한 사용을 막을 수 있다. 특정 사용자 혹은 그룹등이 사용하는 프로세스의 메모리가 예상 가능하며, 계속 증가되지 않는다고 가정하는 경우 사용하면 유용하다.
!) 현재는 (kernel : 2.6.31) 메모리 관련 item 으로는 rss (resident set size:real 할당 메모리)가 있지만 이 값에 설정한다고 해서, memory 사용을 막지는 못한다. 제대로 동작된다고 보여지지 않는다.
!) 메모리 제한을 위해서, 사용할 수 있는 방법은 as(address space) 에 limit 을 걸면 잘 동작한다.
as 는 Virtual Memory Address Space 이다. 따라서 내가 10M 정도의 제약을 가하고 싶다면 10*1024 = 10240 값을 주면 된다. (단위는 KB 이다.) 주의할 점은, 이 제약조건은 사용자 혹은 그룹등이총 사용하는 리소스가 아니라, 사용자 혹은 그룹등에서 사용하는 프로세스 당 제약 조건이다.
예) * soft as 10240
* hard as 10240
soft 는 기본적으로 적용되는 limit 항목이며, hard 까지 limit 상승이 가능하다. 프로그램 내부에서는 기본설정된 값(soft limit 조건)보다 더 큰 값을 사용해야 하는 경우 최대 hard 에 설정된 값까지 limit 을 증가시킬 수가 있지만, 이를 위해서는 root 권한이 필요하다.
!) /etc/security/limits.conf 값은 shell 이 생성될 때 적용되며, 기존 shell 에는 적용되지 않는다. 따라서 기존 shell 을 이용할 때는 명령창에 ulimit -v 10240 으로 동일하게 적용학 수 있다.
2. 원인 분석
[문제 발생 소스를 수정 가능한 경우]
: 문제의 재현스텝이 불분명하고, 발생 지점을 확인하기 어렵지만, 문제의 소스를 수정할 수 있는 경우, 기존에 짜여진 소스는 그대로 두고 memory hook 을 정의해서 문제 발생 지점을 확인 할 수 있다.
linux memory hook 사용 법
[문제 발생 소스를 수정 불가능한 경우]
: 문제의 재현스텝이 불분명하고, 발생 지점을 확인하기 어렵우며, 문제의 소스를 수정할 수 없는 경우, 컴파일을 다시 할 수 있다면 gcc -g 옵션을 추가해서 재 컴파일 한다. 디버깅 옵션이 설정되지 않은 상태에서 컴파일 옵션 마저 변경할 수 없는 경우라면, 더이상 진행 불가하다. 기존 바이너리가 -g 옵션으로 컴파일 되었거나, 컴파일을 -g 옵션으로 다시 할 수 있다면, 1번의 /etc/security/limits.conf 파일에 core 파일 생성을 unlimited 로 추가한다.
* - core unlimited
linux reboot 후에도 위의 옵션이 먹지 않는다면, /etc/profile 을 확인하자.
아래의 내용이 있다면, 주석처리한다.
#ulimit -S -c 0 > /devnull 2>&1
만약, 프로그램 동작 중, 다시 OOM 상황이 발생하는 경우, 1번에서 제한한 limit 값에 도달하면, 운 좋으면 core 를 떨어뜨리고 죽을 것이다. 여기서 운이 좋다는 것은 프로그램이 메모리를 사용하기 전에 NULL check 를 하지 않는 경우이다. 만약 프로그램이 메모리 사용전 NULL check 를 꼼꼼히 한다면, 프로그램은 오류 상태로 정상 종료 할 것이다.
[Tool 을 통한 분석]
프로그램이 -g 옵션으로 컴파일 되어 있고, 성능 이슈가 크지 않다면, valgrind 의 여러가지 툴을 이용해서 메모리 증가 지점에 대한 상세한 로그를 받을 수 있다. 단, valgrind 등 툴을 사용하여 프로세스를 띄우는 경우, 프로파일링을 위해서 많은 자원과 시간이 소모되므로, 실 서비스에 적용하여 테스트 하기에는 적합하지 않다.
출처: http://lefthand.tistory.com/28 [lefthand's note]
[SQL] mysql
command line 기준으로 간략히 정리함.
[로그온]
mysql -u[id] -p [dbname]
[계정생성]
: 많은 항목 중 다음의 컬럼만으로 기본 사용자 생성/등록
$ mysql -u root -p mysql
mysql> INSERT INTO user (Host, User, Password) VALUES ('localhost', 'userid', password('userpwd'));
mysql> INSERT INTO user (Host, User, Password) VALUES ('%', 'userid', password('userpwd'));
mysql> FLUSH PRIVILEGES;
[계정삭제]
mysql> DELETE FROM user WHERE user='userid';
mysql> FLUSH PRIVILEGES;
[데이타베이스 생성]
$ mysql -u root -p mysql
mysql> CREATE DATABASE dbname;
[데이타베이스 목록 조회]
mysql> SHOW DATABASES;
[데이타베이스 삭제]
mysql> DROP DATABASE [IF EXISTS] dbname;
IF EXISTS 는 db 가 없더라도 오류 발생시키지 않는다.
[작업db 변경]
mysql> USE dbname;
[db 접근권한 설정]
(1) 접근권한을 DB 에 직접 UPDATE 하는 방법
mysql> INSERT INTO db (Host, Db, User, Select_priv, Insert_priv, Update_priv, Delete_priv, Create_priv, Drop_priv, Grant_priv, References_priv, Index_priv, Alter_priv, Create_tmp_table_priv, Lock_tables_priv, Create_view_priv, Show_view_priv, Create_routine_priv, Alter_routine_priv, Execute_priv) VALUES ('localhost','dbname','userid','y','y','y','y','y','y','y','y','y','y','y','y','y','y','y','y','y');
mysql> FLUSH PRIVILEGES;
(2) grant 명령 이용 : 생성된 user 가 없는 경우, user 생성까지 수행한다.
mysql> GRANT ALL
-> ON dbname.* TO 'userid'@'host'
-> IDENTIFIED BY 'pwd';
mysql> FLUSH PRIVILEGES;
ex) 로컬호스트에서 userA가 dbA 에 수행항목과 접근 허용
GRANT SELECT, UPDATE, INSERT, DELETE, ALTER, CREATE
ON dbA TO 'userA'@'localhost'
IDENTIFIED BY 'userApwd';
ex2) 모든 서버에서 접근할 수 있도록 허용
GRANT SELECT, UPDATE, INSERT, DELETE, ALTER, CREATE
ON dbA TO 'userA'@'%'
IDENTIFIED BY 'userApwd';
[생성된 계정으로 로긴]
$ mysql -u userid -p [dbname]
[테이블 목록 조회]
mysql> SHOW TABLES;
[테이블 스키마 조회]
mysql> EXPLAIN tablename;
or
mysql> DESCRIBE tablename;
[테이블 생성]
mysql> CREATE TABLE tablename (
-> column_name1 INT UNSIGNED NOT NULL,
-> column_name2 VARCHAR(15) NOT NULL,
-> column_name3 INT );
[테이블 이름 변경]
mysql> RENAME TABLE tablename1 TO tablename2[, tablename3 TO tablename4];
[테이블 삭제]
mysql> DROP TABLE tablename;
[제약 조건 생성]
mysql> CREATE INDEX indexname ON tablename (columnname1[, columname2]);
[로컬 파일 import]
CSV 등 파일에서 import 하여 테이블을 생성한다.
mysql> LOAD DATA LOCAL INFILE 'filepath'
-> INTO TABLE tablename
-> FIELDS TERMINATED BY ','
-> OPTIONALLY ENCLOSED BY '\"'
-> LINES TERMINATED BY '\n' ;
[DB 상태 보기]
mysql> STATUS;
[INSERT]
mysql> INSERT INTO tablename VALUES(value1, value2, ...);
or
mysql> INSERT INTO tablename(column1, column2, ..) VALUES(value1, value2, ...);
[SELECT]
mysql> SELECT column1, column2, .. FROM tablename;
mysql> SELECT column1 AS 'Alias1', column2 AS 'Alias2', .. FROM tablename;
mysql> SELECT * FROM tablename ORDER BY column1 DESC;
mysql> SELECT * FROM tablename WHERE 조건;
[UPDATE]
mysql> UPDATE tablename SET column1=새값 WHERE 조건;
[DELETE]
mysql> DELETE FROM tablename WHERE 조건;
출처: http://lefthand.tistory.com/26 [lefthand's note]
windows application exception
- build 시 pdb 생성
- 유저모드 덤프 설정
(아래의 툴을 이용해서 덤프 출력.)
http://www.microsoft.com/downloads/details.aspx?FamilyID=E089CA41-6A87-40C8-BF69-28AC08570B7E&displaylang=en
:이걸 설치하면 옵션이 몇개 있는데 설정하고 해당 exe를 등록해 놓으면 그 exe가 exception이 나면 덤프가 자동을 떠짐
- windbg이용 덤프분석
windbg에서 !analyze -v 치면 바로 확인됨.
소스 연결해 놓으면 소스까지 다 찾아감
출처: http://lefthand.tistory.com/25 [lefthand's note]
* 본 포스트의 내용은 [토비의 스프링3] 내용에서 발췌된 것이다.
본 포스트의 내용은 Spring 3.0 을 기반으로 한다.
* 스프링으로 어떤것을 만들수 있는가?
스프링으로 만들수 있는 애플리케이션의 종류에는 제한이 없고 자바를 사용하는 모든 프로젝트에 사용할 수 있다. 하지만, 대부분 자바 엔터프라이즈 환경에서 동작하는 어플리케이션이다 (즉 서버에서 동작하여 클라이언트에게 서비스를 제공) 가장 많이 사용하는 구조는 클라이언트가 웹 브라우저이고, 백엔드 시스템이 DB인 구성이다.
* 개발도구와 환경
1. JavaSE/JDK : JDK 5.0 or higher (JDBC 4.0 API를 사용 하는 경우 JDK6.0)
2. JavaEE/J2EE : J2EE 1.4 or JavaEE 5.0 (J2EE 1.4 의 경우 JDK 5.0에서 사용불가능한 경우가 있으므로 주의)
3. IDE : Eclipse(or STS-SpringSource Tool Suite), NetBeans, IntelliJ IDEA
: STS - 최신 이클립스를 기반으로 주요한 스프링 지원 플러그인과 관련 도구들을 모아서 스프링 개발에 최적화되도록 구성된 IDE. 스프링소스가 제공하는 플로거인 조합이 완료된 STS를 사용하면, 플로그인 업데이트와 플러그인간 호환성 등에 신경쓸 필요가 없으므로 편리. 게다가 tcServer 를 함께 설치할수 있어서 편리.
tcServer) Spring 개발을 담당하는 SpringSource 는 apache httpd 서버와 tomcat 의 개발자들이 있어서 스프링어플리케이션에 최적화된 tcServer 를 개발했다. 기술지원을 받을 수 없는 오픈소스제품과 달리, tcServer를 사용하면 기술지원을 받을 수 있음. (개발자 버전은 무료이지만, 정식 운영서버에서 사용하고 기술지원 받으려면 유료 라이선스 구매 필요)
4. 스프링 관련 Plugin(s)
SpringIDE plugin
SpringIDE는 스프링 개발에 유용한 기능을 제공하는 플러그인의 모음. 스프링 프로젝트 설정파일 생성 위저드, XML 설정파일 에디터, bean의 의존관계 그래프, 네임스페이스 관리 기능 등의 기능과 도구를 제공함.
STS plugin
스프링 개발과 설정파일 편집을 지원하는 SpringIDE에 더해서 스프링 어플리케이션의 서버 배치와 같은 추가 기능을 제공해 준다.
STS 가 추가로 제공하는 기타 플러그인
- M2Eclipse : Maven 지원하는 Elipse plugin, 스프링은 그 자체로 20여개의 세부 모듈로 구성되어 있고 100개 이상의 의존 라이브러리가 있기 때문에 Maven의 의존 관리 기능을 활용하는게 좋다.
- AJDT (AspectJ Development Tool) : Elipse 에서 AspectJ AOP 를 이용한 개발을 지원.
- VMCI (Virtual Machine Core Integration) : VMWare 서버 혹은 워크스테이션과의 연동을 지원하는 플러그인. STS의 VMWare 배치기능에 주로 사용
- 이클립스 표준 플러그인 : 이클립스에서 제공하는 주요 표준 플러그인으로 웹 개발을 지원하는 WTP(Web Tool Platform), EMP(Elipse Modeling Project), Mylyn, DSDP(Device Software Developlemt Platform)
* 스프링 애플리케이션의 배포 단위
1. 독립 웹 모듈 (war) : 가장 일반적
2. 엔터프라이즈 애플리케이션 (ear) : 스프링애플리케이션에서 EJB 모듈을 이용하거나 EJB모듈이 스프링어플리케이션을 이용해야 하면, EJB와 스프링웹 모듈을 엔터프라이즈 애플리케이션으로 통합해서 배포해야 한다.
3. 백그라운드 서비스 모듈 (rar) : rar 는 리소스 커넥터를 만들어 배포할 때 사용하는 방식인데, 스프링어플리ㅔ이션이 UI가 없고, 서버내에서 백그라운드 서비스 처럼 동작할 필요가 있다면 rar 모듈로 만들어 배포할 수 있다.
* 라이브러리 관리와 빌드 툴
스프링은 자체로 20여개의 jar 모듈과 직접 참조하는 100개 이상의 의존 라이브러리가 있다. 이들의 버전관리도 문제지만, 모든 라이브러리가 다 사용되는게 아니므로, 라이브러리를 선정하는 것도 문제이다.
20여개이 모듈중 몇개는 필수모듈이지만 그 외의 모듈은 애플리케이션의 아키텍처와 사용기술에 따라 서택적으로 적용할 수 있다. 또한 스프링 모듈 사이에도 의존관계가 있고, 모듈의 의존 관계는 필수와 선택으로 나뉠 수 잇다.
- Elipse 같은 IDE의 자동 빌드 기능이 있고, 관련 빌더를 추가/확장 하는 것으로 빌드 작업을 간소화 시킬 수 있지만, IDE를 통한 빌드 환경이 아닌 경우에도 일관성 있는 빌드가 가능하도록 만들기 위해서, Maven 이나 Ant 같은 환경에 독립적인 빌드 툴을 함께 사용하는것이 바람직 하다. 그 중 절차적인 스크립트와 비슷한 Ant와 달리 Maven 은 POM을 이용하여 선언적으로 관리할 수 있다. 더 매력적인 점은 Maven의 의존 라이브러리 관리 기능이 Transitive (전이적)이고, 이는 스프링의 모든 모듈이 POM 정보를 가지고 있으므로, 스프링을 통한 라이브러리 관리를 좀더 편리하게 도와준다.
* 관련 web sites
* STS : http://www.springsource.com/downloads/sts
* Ecllipse : http://www.eclipse.org/downloads
* Eclipse Maven Plugin : http://www.eclipse.org/m2e/
출처: http://lefthand.tistory.com/43 [lefthand's note]
Spring 의 정의와 목적
* 본 포스팅 내용은 토비의 스프링3의 8장의 내용을 요약한 것이다.
Spring 이란 무엇인가?
자바 엔터프라이즈 개발을 편하게 해주는 오픈소스 경량급 애플리케이션 프레임워크
창시자 : Rod Johnson
기원 : Expert One-on-One J2EE Design and Development (2003) 의 sample code
- 애플리케이션 프레임워크
일반적으로 라이브러리나 프레임워크는 특정 업무 분야나 한가지 기술에 특화된 목표(예를들면, 웹 계층을 MVC구조로 변경한다거나, 간단한 설정만으로 RDB와 java object를 매칭해주는 ORM기술 제공등)를 가지고 만들어 지지만, 애플리케이션 프레임 워크란 특정 계층이나, 기술, 업무분야에 국한되지 않고 애플리케이션의 전 영역을 포괄하는 볌용적인 프레임워크이다. 애플리케이션 프레임워크는 애플리케이션 개발의 전 과정을 빠르고 편리하며 효율적으로 진행하는데 일차적인 목표를 두는 프레임워크이다.
- 경량급(lightweiight)
스프링 자체가 아주 가볍다거나 작은 규모의 코드로 이뤄졌다는 뜻이 아니다. 스프링은 20여개의 모듈로 세분화 되고 수십만 라인에 달하는 코드를 가진 방대한 규모의 프레임워크이다. 경량급의 의미는 EJB같은 과도한 엔지니어링이 적용된 기술에 대비하여 불필요하게 무겁지 않다는 의미이다.
EJB : 고가의 WAS필요, 난해한 설정파일, 까다로운 패키징, 불편한 deploy 등으로 인한 부담으로 인해 고가의 제품으로 구성된 제대로된 개발환경이 없이 개발이 어려움. 스프링은 tomcat 이나 jetty 에서도 완벽하게 동작한다. 즉, 서블릿 컨테이너만으로 충분하니, EJB컨테이너나 기타 기능을 사용하지 않아도 된다.
(1) 개발환경의 lightweight
(2) 서버 환경의 lightweight
(3) 코드의 상대적인 lightweight
- 자바 엔터프라이즈 개발을 편하게
로우레벨의 트랜잭션이나 상태관리, 멀티스레딩, 리소스 풀링 같은 복잡한 로우레벨 API 를 이해하지 못하더라도 아무런 문제 없이 어플리케이션을 개발할 수 있다.(From Enterprise JavaBeans 1.0 Specification, Chapter 2 Goals)
로우레벨 기술에 신경쓰지 않으면서, 애플리케이션의 핵심인 사용자의 요구사항, 비즈니스 로직을 빠르고 효과적으로 구현하는 것. 즉, 초기에 스프링의 기본 설정과 적용기술만을 잘 이해하고 있으면, 애플리케이션 개발중에는 스프링 관련 Code 에 신경쓸 필요가 없다.
- 오픈소스
스프링은 오픈소스 프로젝트 방식으로 개발되왔다. 지금도 여전히 오픈 소스 개발 모델과 라이선스를 가지고 개발하는 중이다.
라이센스 : Apache Licence Ver 2.0 (스프링을 상업제품에 포함시키거나 비공개프로젝트에서 사용해도 된다. (수정자유롭고 수정된 소스 공개 필요없음)
Spring 의 Goal
- 엔터프라이즈 개발의 복잡함
2000년대 초반 80% 이상의 자바 enterprise project 가 실패했다. 가장 대표적인 이유는 엔터프라이즈 시스템 개발이 너무 복잡해서 이다.
왜 복잡한가? 비즈니스 로직 이외에도 기술적으로 고려해야 할 사항들이 많다.(타시스템 과의 연계, 다양한 형태의 클라이언트 접속을 위한 리모팅 기술, 분산 트랜잭선의 지원, 보안 등) 또한 비즈니스 로직 자체도 점점 복잡해지고 잦은 변경이 요구된다)게다가 이런 엔터프라이즈 기술의 복잡함과 비즈니스 로직의 복잡함이 한데 얽혀서 복잡함이 배가된다.
- 복잡함을 해결하려는 도전
근본적으로 엔터프라이즈 기술의 복잡함과 비즈니스 로직의 복잡함은 줄일수 없다. 그러나 이 두가지 성질이 다른 복잡함을 분리해 낼수 있다. EJB도 이 목표를 지향하여 선언전 트랜잭션이나 선언적 보안, 컨테이너를 통한 리모팅 기술의 적용, 컴포넌트 단위의 배치, JNDI 를 통한 서비스 검색지원, 서비스 오브젝트의 풀링, 컴포넌트의 생명주기 관리등을 수행하여 이 목표를 달성하려 하였으나, 이를 위해 EJB라는 환경과 스펙에 종속되는 코드로 만들어야 하는 더 큰 복잡함을 안게되어 실패하였다. 게다가 EJB라는 틀 안에서 특정클래스를 상속하게 함으로 자바 언어의 원래 장점마저 상실하고 객체지향적인 특성을 잃어버진 서비스 스크립트성 코드로 변질돼 갔다.
스프링은 EJB와는 다르게 비침투적(non-invasive)기술을 적용하였고, 이는 코드상에 스프링과 관련된 규약과 코드가 등장하지 않는 것을 의미한다. 즉, 스프링이 코드에 불필요하게 등장해서 복잡함을 가중시키지 않는다.
- 복잡함을 상대하는 스프링의 전략
** 기술적 복잡함은 아래와 같이 서비스의 추상화와 AOP 로 상대한다.
1. 서비스의 추상화
트랜잭션 추상화, OXM 추상화, 데이터 액세스에 관한 일관된 예외변환 기능, 데이타 액세스 기술에 독립적인 트랜잭션 동기화 기능 등. 기술적인 복잡함은 추상화를 통해 로우레벨의 기술 구현 부분과 기술을 사용하는 인터페이스를 분리하고, 환경과 사용기술에 독립적인 접근 인터페이스를 제공한다.
2. AOP (Aspect Oriented Programming)
비즈니스 로직 전후로 경계가 설정되어야 하는 트랜잭션, 보안적용, 예외처리, 로깅, 감사 등 기술과 비즈니스 로직의 혼재는 최대한 제거해도 완전히 해결할 수 없으며, 이를 해결하기 위한 스프링의 전략이 AOP 이다. AOP는 최후까지 애플리케이션 로직에 남아있는 기술관련 코드를 깔끔하게 분리해서 별도의 모듈로 관리하게 해주는 강력할 기술이다.
** 비즈니스 로직의 복잡함을 상대하는 전략은 객체지향과 DI이다.
1. OOAD (Object Oriented Analysis & Design)
복잡함을 단순화 할 수 있는 것은 객체지향 기술 자체이며, 스프링은 환경 종속적이지 않고 비침투적인 기술이므로 핵심로직을 다루는 코드에는 스프링이 드러나지 않는다. 따라서 객체지향언어의 장점을 살려 로직의 복잡함을 효과적으로 다루어야 한다.
2. DI (Dependency Injection)
DI는 특별한 기술이라기 보다는 유연하게 확장가능한 오브젝트 설계를 하다보면 자연스럽게 적용하게 되는 객체지향 프로그래밍 기법이다. 스프링은 단지 그것을 더욱 편하고 쉽게 사용하도록 도와줄 뿐이다. DI는 적용하려다 보면 자연스럽게 확장성이 좋은 설계로 이끌어진다. 즉, 바뀔 수 있는 것은 무엇인가? 무엇이 성격이 다른가? 를 지속적으로 고민하게 되고 대상이 되는 Object는 DI를 적용해 분리하고, 인터페이스를 도입하고, DI로 관계를 연결해 주게 되므로 DI를 열심히 적용하다 보면 객체지향 설계의 원칙을 잘 따르고 그 장점을 살린 설계가 나올수도 있다.
출처: http://lefthand.tistory.com/42 [lefthand's note]
Singletone Pattern & Spring IoC Container
* 본 포스트의 내용은 [토비의 스프링3] 내용에서 발췌된 것이다.
* 내용
싱글톤 패턴으 GoF 의 디자인 패턴중 하나다. 디자인 패턴 중에서 가장 자주 활용되는 패턴이기도 하지만, 가장 많은 비판을 받는 패턴이기도 하다. 싱글톤 패턴은 어떤 클래스를 어플리케이션 내에서 제한된 인스턴스 수, 주로 하나만 존재하도록 강제하는 패턴이다. 이렇게 하면 이 클래스의 오브젝트는 애플리케이션 내에서 전역적으로 접근이 가능하다. 단일 오브젝트만 존재해야 하고, 이를 애플리케이션의 여러 곳에서 공유하는 경우에 주로 사용한다.
* Java 에서 Singleton 을 구현하는 일반적인 방법
- 생성자를 private 으로 설정하여 클래스 밖에서는 오브젝트를 생성하지 못하게 함
- 생성된 singleton 오브젝트를 저장할 수 있도록 클래스 내에 자신과 같은 타입의 static field 정의
- static factory method 인 getInstance()를 만들어 최초 호출 시점에만 오브젝트 생성하고 static field 에 저장.
public class UserObject {
private static UserObject INSTANCE;
...
private UserObject(..) {
..
}
public static synchronized UserObject getInstance() {
if (INSTANCE == null) INSTANCE = new UserObject(..);
return INSTANCE;
}
}
* Java 에서 위와같이 singleton을 구현하는 경우 singleton pattern 의 한계
- private 생성자를 갖고 있기 때문에 상속할 수 없다.
객체지향의 상속과 다형성 적용 불가
- 테스트가 어렵다.
싱글톤은 만들어지는 방식이 제한적이므로 테스트에서 Mock Object 로 대체하기가 힘들다.
- 서버환경에서는 singleton 이 하나만 만들어지는 것을 보장하지 못한다.
서버에서 class loader 를 구성하는 방법에 따라서 하나 이상의 오브젝트가 만들어 질 수 있다.
- 싱글톤의 사용은 전역 상태를 만들 수 있기 때문에 바람직 하지 못하다.
singleton의 static method 를 이용하여 어떤 client 라도 접근/사용할 수 있으므로, 전역상태(global status)로 사용되기 쉽다. 아무 객체나 자유롭게 접근/수정/공유하는 전역상태는 OOP에서는 권장되지 않는다.
* Spring Framework 에서의 singleton
Spring은 서버 환경에서 singleton으로 service object 를 사용하는 것을 지지한다. 다만, java 의 기본적인 singleton 구현방식은 상기의 단점이 있으므로, Spring Framework 자체에서 singleton 형태의 object를 만들고 관리하는 기능인, singleton registry 를 제공한다.
Spring의 ApplicationContext 는 Singleton을 저장하고 관리하는 Singleton registry 이다.
* Spring Registry
Spring 은 디폴트로 내부에서 생성하는 Bean object 를 singleton으로 만든다. 이것은 디자인 패턴의 싱글톤과 비슷한 개념이지만, 구현방법은 확연히 다르다. 즉, Spring container 에서 object 를 singleton registry 에 관리하며 singleton으로 동작하도록 제어한다.
왜 Spring은 singleton으로 bean 을 생성하는 것일까?
하나의 요청(Request)를 처리하기 위해서는 데이타 액세스 로직(DAO), 서비스 로직, 비즈니스 로직, 프리젠테이션 로직등 다양한 기능을 담당하는 오브젝트들이 계층형 구조로 이루어 진다. 매번 클라이언트 요청이 올때마다, 각 로직을 담당하는 오브젝트들을 새로 만들어 사용한다면, 아무리 Java가 오브젝트 생성과 GC(Garbage Collection) 성능이 좋아졌어도 서버가 부하를 감당하기 심들다. 이 때문에 엔터프라이즈 분야에서는 서비스오브젝트 라는 개념을 사용해 왔는데 Servlet 은 Java 엔터프라이즈 기술의 가장 기본이 되는 서비스 오브젝트라고 할수 있다. Servlet은 대부분 멀티스레드 환경에서 Singleton으로 동작한다. 즉, Servlet 클래스 당 하나의 오브젝트만 만들어 주고, 사용자의 요청을 담당하는 여러 스레드에서 하나의 오브젝트를 공유해서 사용한다.
Singleton registry 덕분에 singleton 으로 동작해야 할 어떤 클래스라도 평범한 java class 로 작성될 수 있다. 즉, public 생성자를 가질 수 있으며 static method 를 노출할 필요도 없다. 이것은 테스트 환경에서 자유롭게 object 를 만들 수 있고 또한 OOP의 장점을 그대로 가진다.
* Spring 에서 Singleton object 로 사용할 클래스 설계시 주의점
Spring 에서 singleton 이 멀티스레드 환경에서 서비스 오브젝트에 사용되는 경우에는 상태정보를 내부에 갖고 있지 않은 stateless 로 만들어야 한다. 이 경우, 각 요청에 대한 정보나 생성된 정보는 메소드 파라미터나 메소드 안의 로컬변수 혹은 리턴값 등으로 처리해야 한다. 싱글톤이라해도 메소드 안에서 생성되는 로컬변수는 method가 호출될 때마다 매번 새로 할당되므로 싱글톤이라 해도 여러 스레드가 변수의 값을 덮어쓸 일은 없다.
public class UserDao {
private ConnectionMaker connectionMaker; <-- (1)
private Connection c; <-- (2)
private User user; <-- (2)
public User get(String id) throws ClassNotFoundException, SQLException {
this.c = connectionMaker.makeConnection();
....
this.user = new User();
this.user.setId("...");
...
return user;
}
}
UserDao 는 IoC container 에 의해서 singleton object 로 생성/사용된다고 가정해 보자.
이런 경우, (2)번과 같이 멀티스레드 환경에서 변경될 수 있는 값을 클래스의 인스턴스 변수로 생성하는 경우, 문제가 발생한다. 따라서 Spring 의 singleton bean 으로 사용되는 클래스를 만들때는 (2)번의 경우는 method 내 로컬 변수로 사용하거나 파라미터로 주고 받으며 사용해야 한다.
단, 이 경우에도 클래스 인스턴스 변수로 사용가능한 경우가 있는데 이는 (1) 과 같다.
(1)은 자신이 사용하는 다른 singleton bean 을 저장하려는 용도라면, 인스턴스 변수로 사용해도 좋다. 스프링이 초기화 되고 나면, 이후에 수정되지 않는 경우라면, 멀티스레딩 환경에서 사용해도 문제없다
* Spring bean 의 스코프
scope : 스프링이 관리하는 오브젝트, 즉 빈의 생성/존재/소멸되는 범위
singleton : 스프링 bean 의 기본 scope 는 singleton 이다. 컨테이너 한개에 한개만 생성되며 강제로 제거하지 않는 한 컨테이너가 존재하는 동안 계속 유지된다.
prototype : 컨테이너에 빈을 요청할 때마다 매번 새로운 오브젝트를 만들어준다.
request : 웹을 통해 HTTP 요청시마다 생성되는 scope
session : 웹의 세션과 유사한 scope
출처: http://lefthand.tistory.com/41 [lefthand's note]
POJO (Plain Old Java Object)
* 본 포스트의 내용은 [토비의 스프링3] 내용에서 발췌된 것이다.
POJO (Plain Old Java Object) ?
1. 특정 규약(contract)에 종속되지 않는다.
Java 언어와 꼭 필요한 API 외에 종속되지 않는다. EJB2 의 EntityBean 상속이나 Struts 1 의 ActionForm 상속등 규약에 종속되지 않아야 한다.
2. 특정 환경에 종속되지 않는다.
EJB3 의 JNDI 서버 서비스의 의존이나 특정 벤더의 서버나 기업프레임워크안에서만 동작 가능한 코드가 아니다.
3. 객체지향원리에 충실해야 한다.
특정 기술규약과 환경에 종속되지 않은 Java Object 가 모두 POJO라 할수는 없다. 객체지향 개념이 녹아있지 않은 것만 POJO 이다.
Why POJO?
1. 코드의 간결함
비즈니스 로직과 특정 환경/low 레벨 종속적인 코드를 분리하므로 단순하다.
2. 자동화 테스트에 유리
환경 종속적인 코드는 자동화 테스트가 어렵지만, POJO 는 테스트가 매우 유연하다.
3. 객체지향적 설계의 자유로운 사용
특정 규약 종속적인 객체의 경우 특정 상속을 미리 지정해서, 단일상속만 제공하는 JAVA 언어로서는 더이상 객체지향적 설계를 하는데 제약을 가져오는 경우가 있으나, POJO 는 아무런 규약이나 규제가 없으므로 OO 설계에 매우 자유롭다.
What is POJO Framework?
POJO 프로그래밍이 가능하도록 기술기반을 제공하는 Framework.
1. Spring Framework
엔터프라이즈 기술에만 최소한으로 관여하고 비즈니스 로직을 담당하는 POJO에서는 관여하지 않는다.
2. Hibernate
Spring 의 핵심 기술?
기술과 비즈니스로직을 분리하고 POJO방식의 어플리케이션 개발을 가능하게 한다는 스프링의 목적을 쉽게 이루려면 스프링과 같은 POJO 프레임워크가 필요하다.
POJO 프로그래밍을 손쉽게 할 수 있도록 지원하는 세가지 가능기술(Enabling technology)
(1) IoC/DI (Inversion of Control / Dependency Injection)
IoC/DI 는 스프링의 가장 기본의 되는 기술이자 스프링의 핵심 개발원칙이다. 나머지 두가지 기술인 AOP 와 PSA도 IoC/DI에 바탕을 두고 있으며, 3대기술은 아니지만 자주 등장하는 템플릿/콜백 패턴의 적용도 IoC/DI가 핵심원리다.
(2) AOP (Aspect Oriented Programming)
핵심 관심사를 분리하여 프로그래매 모듈화를 향상시키는 프로그래밍 스타일이다. AOP는 객체를 핵심 관심사와 횡단 관심사로 분리하고, 횡단 관심사를 관점(Aspect)라는 모듈로 정의하고, 핵심 관심사와 엮어서 처리할 수 있는 방법을 제공한다. 스프링은 자체적으로 프록시 기반의 AOP를 지원하며, 로깅, 트랜잭션, 보안 이런것들이 전반적으로 처리하는데 사용됨.
(3) PSA (Portable Service Abstraction)
인터페이스가 다른 다양한 구현을 같은 방식으로 사용하도록 중간에 인터페이스 어댑터 역할을 해주는 레이어를 하나 추가하는 방법
출처: http://lefthand.tistory.com/40 [lefthand's note]
IoC(Inversion of Control) / DI(Dependency Injection)
* 본 포스트의 내용은 [토비의 스프링3] 내용에서 발췌된 것이다.
What is IoC (Inversion of Control)?
프로그램의 제어 흐름 구조가 뒤바뀌는 것.
일반적으로, main() 같은 프로그램이 시작되는 지점에서 다음에 사용할 오브젝트를 결정하고, 생성하고, 만들어진 오브젝트내의 메소드를 호출하고 하는 작업이 반복된다. 이런 프로그램 구조에서 각 오브젝트는 프로그램 흐름을 결정하거나 사용할 오브젝트를 구성하는 작업에 능동적으로 참여한다. 즉, 모든 종류의 작업을 사용하는 쪽에서 제어하는 구조이다.
제어의 역전이란, 제어 흐름의 개념을 거꾸로 뒤집는 것이다. 오브젝트는 자신이 사용할 오브젝트를 스스로 생성하거나 선택하지 않는다. 또한 자신도 어떻게 만들어지고 어디서 사용되는지 알수 없다. 모든 제어 권한을 자신이 아닌 다른 대상에게 위임한다. 프로그램의 시작을 담당하는 main()같은 엔트리 포인트를 제외하면 모든 오브젝트는 이렇게 위임받은 제어 권한을 갖는 특별한 오브젝트에 의해 결정되고 만들어 진다. 단지 스프링에서 사용되는 개념이 아니고, 매우 폭넓게 사용되는 프로그래밍 모델이다.
- 작업을 수행하는 쪽에서 Object 를 생성하는 제어 흐름의 개념을 거꾸로 뒤집는다.
- IoC 에서는 Object 가 자신이 사용할 Object 를 생성하거나 선택하지 않는다.
- 또한 Object 는 자신이 어떻게 생성되고 어떻게 사용되는지 알 수 없다.
- 모든 Object 는 제어 권한을 위임받는 특별한 Object 에 의해서 만들어 지고 사용된다.
What is DI (Dependency Injection) ?
- Spring이 지원하는 IoC방식을 좀더 명확히 설명.
- dependent object(의존 오브젝트) : 사용 대상이 되는 오브젝트
- 의존 오브젝트와 그것을 사용할 주체, 보통 클라이언트라고 부르는 오브젝트를 런타임시에 연결해 주는 작업.
의존관계주입의 조건
- 클래스 모델이나 코드에는 런타임 시점의 의존관계가 드러나지 않는다. (즉, 인터페이스에만 의존)
- 런타임 시점의 의존관계는 컨테이너나 팩토리같은 제 3의 존재가 결정한다.
- 의존관계는 의존 오브젝트 레퍼런스를 외부에서 제공(주입)해줌으로 만들어진다.
IoC 개념이 녹아 있는 Example
1. servlet 과 container.
: 서블릿에 대한 제어권한을 가진 컨테이너가 적절한 시점에 서블릿 클래스의 오브젝트를 만들고 그 안의 메소드를 호출한다.
2. Template Method Pattern (Design Pattern)
: http://lefthand.tistory.com/34
역시 제어권을 상위 템플릿 메소드에 넘기고 서브 클래스는 필요할 때 호출되어 사용되는 개념.
3. Framework
: 라이브러리를 사용하는 어플리케이션은 어플리케이션의 흐름을 직접 제어하지만, 프레임워크는 애플리케이션 코드가 프레임워크에 의해서 사용된다. 보통 프레임워크 위에 개발한 클래스를 등록해 두고, 프레임워크가 흐름을 주도하는 중에 개발자의 어플리케이션 코드를 사용하도록 만드는 방식이다. 즉, 제어의 역전 개념이 적용되어 있어야 한다.
스프링 IoC의 용어 정리
* bean
: 스프링에서 제어권을 가지고 직접 만들고 관계를 부여하는 오브젝트를 bean 이라 부른다. 자바빈, EJB의 빈과 비슷한 오브젝트 단위의 애플리케이션 컴포넌트를 말한다. 하지만 스프링을 사용하는 애플리케이션에서 만들어지는 모든 오브젝트가 빈은 아니다. 스프링의 빈은 스프링 컨테이너가 생성과 관계설정, 사용등을 제어해주는 오브젝트를 가리킨다.
* bean factory
스프링의 IoC를 담당하는 핵심 컨테이너를 가리킨다. 빈을 등록/생성/조회/반환/관리한다. 보통은 bean factory 를 바로 사용하지 않고 이를 확장한 application context 를 이용한다. BeanFactory 는 bean factory 가 구현하는 interface 이다. (getBean()등의 메소드가 정의되어 있음)
* application context
bean factory를 확장한 IoC 컨테이너이다. 빈의 등록/생성/조회/반환/관리의 기능은 bean factory 와 같지만, 여기에 spring 의 각종 부가 서비스를 추가로 제공한다. ApplicationContext는 application context가 구현해야 하는 interface이여, BeanFactory 를 상속한다.
* 설정정보/설정 메타정보 configuration metadata
application context 혹은 bean factory 가 IoC를 적용하기 위해 사용하는 메타정보이다. 스프링의 설정정보는 컨테이너에 어떤 기능을 세팅하거나 조정하는 경우에도 사용하지만 주로 bean 을 생성/구성하는 용도로 사용된다.
* container (IoC container)
IoC 방식으로 bean을 관리한다는 의미에서 bean factory 나 application context 를 가리킨다. (spring container = application context) application context는 그 자체로 ApplicationContext 인터페이스를 구현한 오브젝트를 가리키기도 하는데, 하나의 애플리케이션에 보통 여러개의 ApplicationContext Object가 만들어진다. 이를 통칭해서 strping container라고 부를 수 있다.
* spring framework
spring framework 는 IoC container, application context 를 포함해서 spring이 제공하는 모든 기능을 통칭할때 주로 사용된다.
Spring 에서 IoC/DI 활용 방법:
* DI를 이용한 핵심기능의 변경
디자인 패턴의 전략패턴에 해당하는 의존 대상의 implementation 의 변경에 사용함.
A->B 에서 A 기능 일부를 B에게 위임하는 경우 필요에 따라 B의 구현방식을 통째로 B1, B2, B3로 변경한다.
ex) DAO의 구현을 JDBC, JPA, Hibernate, JDO, iBatis 등으로 변경
ex) 사용자 등급 결정 정책을 DI로 새오운 클래스로 변경
* 핵심기능의 동적인 변경
DI 도 runtime 시에 동적으로 의존 Object 를 연결해 주긴 하지만, DI되면 정적인 관계가 형성된다. 하지만 DI 를 잘 이용하면, 애플리케이션이 동작하는 중간에 의존 대상을 dynamic 하게 변경할 수 있다.
ex)사용자 등급에 따른 DataSource의 선택
DAO->DataSource 일때, DAO 하나가 여러개의 DataSource 에 의존하게 만들어, 현재 접속한 사용자의 등급에 따라서 다른 DataSource 를 DAO가 사용하도록 한다.
ex) 사용자 별로 독립 Object 만들고 서비스 Object가 이를 DI 받아서 사용하는 경우.
* 부가기능의 추가
DI의 다른 활용방법은 핵심기능은 그대로 두고 부가기능을 추가하는 것이다. Decoration Pattern 의 경우임.
ex) 트랙잭션 기능 부여.
핵심 기능은 그대로 두고 결과나 전달 파라미터를 조작할 수 있고, 파라미터나 리턴 결과를 활용해 로깅이나 보안처리 같은 부가적인 작업을 수행 할 수도 있다. 이베트 발생 처리 등등.
* 인터페이스의 변경
클라이언트가 사용하는 실제 인터페이스와 실제 오브젝트 사이의 인터페이스가 일치하지 않는 경우에도 DI 는 유용하다. A->B인터페이스 고, C는 B인터페이스를 구현하지 않았더라도 A가 DI를 통해 B를 사용하므로, B의 구현 오브젝트에서 C를 호출해 주는 어댑터 처럼 동작하면 된다.
PSA (Portable Service Abstraction): 이를 좀 더 일반화 하여 아예 인터페이스가 다른 다양한 구현을 같은 방식으로 사용하도록, 중간에 인터페이스 어댑터 역할을 해주는 레이어를 하나 추가하는 방법이다.
* 프록시
laze loading(필요한 시점에서 실제 사용할 오브젝트를 초기화, 준비) 할때, 또는 원격 오브젝트를 호출할 때 마치 로컬에 존재하는 오브젝트 처럼 사용할 수 있도록 할때 프록시가 필요하고, 이 경우 DI를 필요로 한다. Spring이 지원하는 리모트 기술은 EJB원격호출, 웹 서비스, REST, HTTP 등 다양하다.
* 템플릿과 콜백
템플릿/콜백 패턴은 DI의 특별한 적용방법이다. 반복적으로 등장하지만, 항상 고정적인 작업 흐름과 그 사이에서 자주 바뀌는 부분은 분리해서 템플릿과 콜백으로 만들고 DI원리를 응용해 적용한다. Spring 이 기본으로 제공하는 20여가지의 템플릿/콜백외에도 직접 응용할 수 있어야 한다.
* Singleton 과 Object Scope
DI를 프레임워크로 이용한다는건 DI대상 오프젝트를 컨터이너가 관리한다는 의미이다. 오브젝트의 생성부터 관계설정, 이용, 소멸에 이르기까지 모든 과정을 DI컨테이너가 주관하기 때문에, 그 오브젝트의 스코프를 자유롭게 제어할 수 있다. 스프링의 DI는 기본적으로 singleton으로 오브젝트를 만들어서 사용하게 하고, 컨테이너가 알아서 싱글톤을 만들고 관리하므로 클레스 자체는 싱글톤을 고려하지 않아도 된다. 물론, 스프링에서는 싱글톤 외에도 다양한 스코프를 갖는 오브젝트를 만들어 DI 할 수 있다.
* 테스트
DI의 또다른 중요한 용도는 Test 이다.테스트 할 대상이 사용하는 오브젝트를 테스트 목적으로 만들어진 Mock 오브젝트로 대체하면 테스트가 매우 용이하다.
출처: http://lefthand.tistory.com/39 [lefthand's note]
apache module configuration
httpd.conf 에 LoadModule 되는 (혹은 static library로 포함되는) apache module 은 각각의 설정을 저장하기 위해 config 객체를 사용할 수 있다. 이 config 객체를 사용하는 경우 각 서버(virtual server 와 기본서버)별로 각각 생성된다. apache module config 객체를 사용하기 위해서, apache module 은 모듈 정의 부분에서 function을 지정할 수 있으며, 편의상 이하 이 function 을 create_server_config라 임의로 지칭하기로 한다.
[create_server_config function 호출 시기]
static void * (*pf_create_server_config) (apr_pool_t *p, server_rec *s);
1. apache start/stop 시 전역적으로 최소 1번 호출됨.
: default module config 객체를 생성과 초기 설정이 이루어짐.
apache 서버가 default server 이외에 1개 이상의 virtual server 를 구성하는 경우, 각 Virtual Server 에서 작성된 apache module 의 configuration command 를 사용하지 않으면, 이때 생성된 config 내 용이 각각의 virtual server module config 객체로 복제 된다.
2. 각 Virtual server 별로 overriding 가능
: 만약 virtual server 내에 configuration command 를 하나 이상 정의하면, 그때는 default module config 객체를 복제하지 않고, create_server_config 함수가 virtual server 를 위해 다시 호출된다.
! CAUTION1) create_server_config 에 전달되는 server_rec * 은 1번의 경우, host 정보가 null 로 들어오며, 2번의 경우에는 각 virtual server 의 설정 값을 갖는다.
!CAUTION2) create_server_config 는 configuration commend 호출 전에 호출돤다.
!CAUTION3) 전달되는 pool 은 pConf 이다. (apache pool hiarachy 참고)
[ap_hook_post_config 이용]
static int (*pf_post_config) (apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s);
apache module 은 여러가지 hook 을 제공하며, 사용자들이 기능을 추가/변경 할수 있도록 한다. module config 를 위해서 command 를 다 읽은 후에 설정 내용을 변경/수정 할수 있도록 ap_hook_post_config 를 제공하며, 여기에 기능을 추가 할 수 있다.
각 Virtual server 별로 설정을 달리 해야 할 것들이 있다면 여기서 수행하면 된다.
!CAUTION1) server_rec * 구조체에는 default server 와 Virtual Server 들을 모두 참조가능하도록 default server 의 server_rec 이 전달되며, s = s->next 값으로 모든 서버들의 설정을 검토할 수 있다.
!CAUTION2) 전달되는 pool 은 pConf 이다. (apache pool hiarachy 참고)
module config 는 각 서버당 1개씩 생성되고, 프로세스 간 공유되므로, 기본적으로 최초 apache 로딩 시 값 설정 후에는 실제 서비스에서 변경하지 않는 것이 좋다. 만약 module config 를 변경해야 할 일이 있다면, pConf 에 mutex 를 생성하여 사용해야 한다.
개인적으로는, mutex 사용보다는 메모리가 충분하다면, apache 가 MPM 이 prefork 방식인 경우, 각 process 별로 메모리를 전역으로 복제/갱신하여 사용하는 것이 더 나을 수 있다. (물론 메모리 크기와 갱신 주기 등등 여러가지를 고려해야 함)
출처: http://lefthand.tistory.com/38 [lefthand's note]
Rewrite & Redirect
아파치 설정의 Rewrite 와 Redirect 에 대해서 간략히 정리한다.
301 Redirect : Permanent Redirect, 브라우저에서 해당 내용을 cache 하여 다음에 요청시에 직접 변경된 주소로 접속한다.
302 Redirect : Temporary Recirect,
<mod_alias.c>
base 모듈(apache 설치시 디폴트로 함께 설치되는 모듈)
default - 302 Redirect (Temporary)
Redirect
RedirectMatch
<mod_rewrite.c>
Extension 모듈 (apache 설치 시 선택하여 설치해야 하는 모듈, static, dynamic 모두 가능)
!main server의 설정이 각각의 virtual host 에 상속되지 않는다. virtual host 별로 각각 설정해 줘야함.
default - 302 redirect
옵션 :
[NC] no-casesensitive
[NE] no-escape
[R] 주소창이 변하기 않기를 원할때
[L] last 적용
[OR] 컨디션의 or
...
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond
RewriteRule
</IfModule>
RewriteRule ^products/([0-9][0-9])$ /products/$1/ [R]
$1, $2, .. $9 첫번째그룹, 두번째 그룹...
출처: http://lefthand.tistory.com/31 [lefthand's note]
blocking/non-blocking socket
* Blocking Socket
- default 값 (socket() 으로 생성되는 기본값)
- connect : connection completion 까지 block
- read : 버퍼에 읽을 값이 없으면 block
- write : 버퍼가 꽉 차서 쓸 수 없으면 block
- accept : backlog queue 에 값이 없으면 block
: blocking 소켓 통신에서 어떤 에러 결과든지 메소드는 자동으로 에러를 규명하는 코드를 같이 리턴한다. 에러는 네트워크 종료, 닫힌 소켓, 아이오 에러 등이 될 수 있다
동기식 통신을 사용한다면 blocking 통신이 더 낫다.
* Non-blocking Socket
- connect : connection 요청 후 즉시 return. connection 이 완료되었는지 보증 안됨.(getsockopt 로 확인)
- read : 버퍼에 읽을 값이 없으면 -1 return (errno : EWOULDBLOCK or EAGAIN)
- write : 버퍼가 꽉 차서 쓸 수 없으면 -1 return (errno :EWOULDBLOCK or EAGAIN)
- accept : backlog queue 에 값이 없으면 -1 return (errno : EWOULDBLOCK or EAGAIN)
: 할수 있는 일이 없으면, 종료하고, 다른 작업(?) 을 할 수 있고, 할 수 있는 일이 있을 때만 작업한다.
비동기식 통신에서는 소켓이 묶이는 것을 피하기 위해 non-blocking 통신이 필요하다.
* Nonblocking socket 설정
int flag, sock_fd;
sock_fd = socket (AF_INET, SOCK_STREAM, 0);
flag = fcntl (sock_fd, F_GETFL, 0);
fcntl ( sock_fd, F_SETFL, flag|O_NONBLOCK );
* timeout 설정
출처: http://lefthand.tistory.com/29 [lefthand's note]
Linux 에서 사용자별 메모리 문제 발생시 대응 방법
본 문서에서는 Linux 에서 OOM(Out-Of-Memory) 발생 시 대응 방법들이다.
1. 문제 발생 방지
[설정파일을 통한 limit (/etc/security/limits.conf)]
: 각 사용자 혹은 그룹등에 리소스 사용 제약사항을 걸어두면, 자원의 무제한 사용을 막을 수 있다. 특정 사용자 혹은 그룹등이 사용하는 프로세스의 메모리가 예상 가능하며, 계속 증가되지 않는다고 가정하는 경우 사용하면 유용하다.
!) 현재는 (kernel : 2.6.31) 메모리 관련 item 으로는 rss (resident set size:real 할당 메모리)가 있지만 이 값에 설정한다고 해서, memory 사용을 막지는 못한다. 제대로 동작된다고 보여지지 않는다.
!) 메모리 제한을 위해서, 사용할 수 있는 방법은 as(address space) 에 limit 을 걸면 잘 동작한다.
as 는 Virtual Memory Address Space 이다. 따라서 내가 10M 정도의 제약을 가하고 싶다면 10*1024 = 10240 값을 주면 된다. (단위는 KB 이다.) 주의할 점은, 이 제약조건은 사용자 혹은 그룹등이총 사용하는 리소스가 아니라, 사용자 혹은 그룹등에서 사용하는 프로세스 당 제약 조건이다.
예) * soft as 10240
* hard as 10240
soft 는 기본적으로 적용되는 limit 항목이며, hard 까지 limit 상승이 가능하다. 프로그램 내부에서는 기본설정된 값(soft limit 조건)보다 더 큰 값을 사용해야 하는 경우 최대 hard 에 설정된 값까지 limit 을 증가시킬 수가 있지만, 이를 위해서는 root 권한이 필요하다.
!) /etc/security/limits.conf 값은 shell 이 생성될 때 적용되며, 기존 shell 에는 적용되지 않는다. 따라서 기존 shell 을 이용할 때는 명령창에 ulimit -v 10240 으로 동일하게 적용학 수 있다.
2. 원인 분석
[문제 발생 소스를 수정 가능한 경우]
: 문제의 재현스텝이 불분명하고, 발생 지점을 확인하기 어렵지만, 문제의 소스를 수정할 수 있는 경우, 기존에 짜여진 소스는 그대로 두고 memory hook 을 정의해서 문제 발생 지점을 확인 할 수 있다.
linux memory hook 사용 법
[문제 발생 소스를 수정 불가능한 경우]
: 문제의 재현스텝이 불분명하고, 발생 지점을 확인하기 어렵우며, 문제의 소스를 수정할 수 없는 경우, 컴파일을 다시 할 수 있다면 gcc -g 옵션을 추가해서 재 컴파일 한다. 디버깅 옵션이 설정되지 않은 상태에서 컴파일 옵션 마저 변경할 수 없는 경우라면, 더이상 진행 불가하다. 기존 바이너리가 -g 옵션으로 컴파일 되었거나, 컴파일을 -g 옵션으로 다시 할 수 있다면, 1번의 /etc/security/limits.conf 파일에 core 파일 생성을 unlimited 로 추가한다.
* - core unlimited
linux reboot 후에도 위의 옵션이 먹지 않는다면, /etc/profile 을 확인하자.
아래의 내용이 있다면, 주석처리한다.
#ulimit -S -c 0 > /devnull 2>&1
만약, 프로그램 동작 중, 다시 OOM 상황이 발생하는 경우, 1번에서 제한한 limit 값에 도달하면, 운 좋으면 core 를 떨어뜨리고 죽을 것이다. 여기서 운이 좋다는 것은 프로그램이 메모리를 사용하기 전에 NULL check 를 하지 않는 경우이다. 만약 프로그램이 메모리 사용전 NULL check 를 꼼꼼히 한다면, 프로그램은 오류 상태로 정상 종료 할 것이다.
[Tool 을 통한 분석]
프로그램이 -g 옵션으로 컴파일 되어 있고, 성능 이슈가 크지 않다면, valgrind 의 여러가지 툴을 이용해서 메모리 증가 지점에 대한 상세한 로그를 받을 수 있다. 단, valgrind 등 툴을 사용하여 프로세스를 띄우는 경우, 프로파일링을 위해서 많은 자원과 시간이 소모되므로, 실 서비스에 적용하여 테스트 하기에는 적합하지 않다.
출처: http://lefthand.tistory.com/28 [lefthand's note]
[SQL] mysql
command line 기준으로 간략히 정리함.
[로그온]
mysql -u[id] -p [dbname]
[계정생성]
: 많은 항목 중 다음의 컬럼만으로 기본 사용자 생성/등록
$ mysql -u root -p mysql
mysql> INSERT INTO user (Host, User, Password) VALUES ('localhost', 'userid', password('userpwd'));
mysql> INSERT INTO user (Host, User, Password) VALUES ('%', 'userid', password('userpwd'));
mysql> FLUSH PRIVILEGES;
[계정삭제]
mysql> DELETE FROM user WHERE user='userid';
mysql> FLUSH PRIVILEGES;
[데이타베이스 생성]
$ mysql -u root -p mysql
mysql> CREATE DATABASE dbname;
[데이타베이스 목록 조회]
mysql> SHOW DATABASES;
[데이타베이스 삭제]
mysql> DROP DATABASE [IF EXISTS] dbname;
IF EXISTS 는 db 가 없더라도 오류 발생시키지 않는다.
[작업db 변경]
mysql> USE dbname;
[db 접근권한 설정]
(1) 접근권한을 DB 에 직접 UPDATE 하는 방법
mysql> INSERT INTO db (Host, Db, User, Select_priv, Insert_priv, Update_priv, Delete_priv, Create_priv, Drop_priv, Grant_priv, References_priv, Index_priv, Alter_priv, Create_tmp_table_priv, Lock_tables_priv, Create_view_priv, Show_view_priv, Create_routine_priv, Alter_routine_priv, Execute_priv) VALUES ('localhost','dbname','userid','y','y','y','y','y','y','y','y','y','y','y','y','y','y','y','y','y');
mysql> FLUSH PRIVILEGES;
(2) grant 명령 이용 : 생성된 user 가 없는 경우, user 생성까지 수행한다.
mysql> GRANT ALL
-> ON dbname.* TO 'userid'@'host'
-> IDENTIFIED BY 'pwd';
mysql> FLUSH PRIVILEGES;
ex) 로컬호스트에서 userA가 dbA 에 수행항목과 접근 허용
GRANT SELECT, UPDATE, INSERT, DELETE, ALTER, CREATE
ON dbA TO 'userA'@'localhost'
IDENTIFIED BY 'userApwd';
ex2) 모든 서버에서 접근할 수 있도록 허용
GRANT SELECT, UPDATE, INSERT, DELETE, ALTER, CREATE
ON dbA TO 'userA'@'%'
IDENTIFIED BY 'userApwd';
[생성된 계정으로 로긴]
$ mysql -u userid -p [dbname]
[테이블 목록 조회]
mysql> SHOW TABLES;
[테이블 스키마 조회]
mysql> EXPLAIN tablename;
or
mysql> DESCRIBE tablename;
[테이블 생성]
mysql> CREATE TABLE tablename (
-> column_name1 INT UNSIGNED NOT NULL,
-> column_name2 VARCHAR(15) NOT NULL,
-> column_name3 INT );
[테이블 이름 변경]
mysql> RENAME TABLE tablename1 TO tablename2[, tablename3 TO tablename4];
[테이블 삭제]
mysql> DROP TABLE tablename;
[제약 조건 생성]
mysql> CREATE INDEX indexname ON tablename (columnname1[, columname2]);
[로컬 파일 import]
CSV 등 파일에서 import 하여 테이블을 생성한다.
mysql> LOAD DATA LOCAL INFILE 'filepath'
-> INTO TABLE tablename
-> FIELDS TERMINATED BY ','
-> OPTIONALLY ENCLOSED BY '\"'
-> LINES TERMINATED BY '\n' ;
[DB 상태 보기]
mysql> STATUS;
[INSERT]
mysql> INSERT INTO tablename VALUES(value1, value2, ...);
or
mysql> INSERT INTO tablename(column1, column2, ..) VALUES(value1, value2, ...);
[SELECT]
mysql> SELECT column1, column2, .. FROM tablename;
mysql> SELECT column1 AS 'Alias1', column2 AS 'Alias2', .. FROM tablename;
mysql> SELECT * FROM tablename ORDER BY column1 DESC;
mysql> SELECT * FROM tablename WHERE 조건;
[UPDATE]
mysql> UPDATE tablename SET column1=새값 WHERE 조건;
[DELETE]
mysql> DELETE FROM tablename WHERE 조건;
출처: http://lefthand.tistory.com/26 [lefthand's note]
windows application exception
- build 시 pdb 생성
- 유저모드 덤프 설정
(아래의 툴을 이용해서 덤프 출력.)
http://www.microsoft.com/downloads/details.aspx?FamilyID=E089CA41-6A87-40C8-BF69-28AC08570B7E&displaylang=en
:이걸 설치하면 옵션이 몇개 있는데 설정하고 해당 exe를 등록해 놓으면 그 exe가 exception이 나면 덤프가 자동을 떠짐
- windbg이용 덤프분석
windbg에서 !analyze -v 치면 바로 확인됨.
소스 연결해 놓으면 소스까지 다 찾아감
출처: http://lefthand.tistory.com/25 [lefthand's note]
피드 구독하기:
글 (Atom)