読者です 読者をやめる 読者になる 読者になる

感謝のプログラミング 10000時間

たどり着いた結果(さき)は、感謝でした。

SpringフレームワークでDIするサンプルと、AOPの前準備。

<スポンサーリンク>

Springで普通にDIしてみる。

まずは、あるクラスを使うMainから書いてみる。
Springではまず、
BeanFactoryクラスを使って、オブジェクトを作るためのクラスを生成しなければならない。
BeanFactoryクラスのgetBean()メソッドで、使いたいオブジェクトのIDを指定すると、そのオブジェクトを参照することができるようになる。
new Hoge()みたいに、newすることなく、外のオブジェクトを利用できる。

package aop;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.FileSystemResource;

public class MainAop {
    private final static String TARGET_XML = "aopbean.xml";
    public static void main(String[] args) {
        BeanFactory factory = new XmlBeanFactory(new FileSystemResource(TARGET_XML));
        GreetingService greetBean = (GreetingService) factory.getBean("greet");
        
        greetBean.greet();
    }
}

で、上記のgetBean("greet")に注目してほしいのだけれど、このgetBeanで指定している"greet"。
これはXMLに定義する。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC
  "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
  <bean id="greet" class="aop.GreetingService">
    <property name="greeting">
        <value>Hello!everyone!</value>
    </property>
  </bean>
</beans>

真ん中あたりにbean id="greet"とあるが、これがID。
で、class="aop.GreetingService"とあるが、こうやって使用したいクラスの完全修飾名を定義する。
propertyタグは、セッターを通じてプロパティを外から注入するためのものだ。
ここに定義したプロパティがGreetingServiceオブジェクトにセットされる。

GreetingServiceオブジェクトはこんな感じ。

package aop;

public class GreetingService {
    private String greeting;

    public String getGreeting() {
        return greeting;
    }

    public void setGreeting(String greeting) {
        this.greeting = greeting;
    }
    
    public void greet() {
        System.out.println(greeting);
    }
}

で、これを実行した結果がどうなるかというと・・・

2013/06/15 20:39:17 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
情報: Loading XML bean definitions from file [C:\Users\workspace\spring\aopbean.xml]
Hello!everyone!

というように、XMLで定義した値が表示されていることがわかる。

SpringでAOP

今日のメインはAOPの勉強。
上記のサンプルに、こんな感じのLogを出力するクラスを追加してみる。

package util;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class Logger {
    private String logFilePath;
    private String logFileName;
    
    public String getLogFilePath() {
        return logFilePath;
    }

    public void setLogFilePath(String logFilePath) {
        this.logFilePath = logFilePath;
    }

    public String getLogFileName() {
        return logFileName;
    }

    public void setLogFileName(String logFileName) {
        this.logFileName = logFileName;
    }

    public void log(String message) {
        logFilePath = Utilities.checkSeparator(logFilePath);
        File file = new File(logFilePath + logFileName);
        PrintWriter pw = null;
        try {
            if (Utilities.fileCheck(file)) {
                pw = new PrintWriter(new BufferedWriter(new FileWriter(file,true)));
                pw.println(message);
                //ちゃんと明示的にcloseしないと、書き込みできないので注意。
                pw.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (pw != null) {
                pw.close();
            }
        }
    }
}

ちなみに追記モードでPrintWriterを作る記述は以下。

pw = new PrintWriter(new BufferedWriter(new FileWriter(file,true)));

Javaでは明示的にcloseしないと、ファイル書き込みができないように見えるので要注意。

Utilitiesクラスはこんな感じ。
使い手がパスを設定すると、パスの末尾に「\」があったりなかったりするので、チェックするようにした。
それがcheckSeparatorメソッド。
で、システムのセパレーターはOSによって異なる。Windowsだったら円マークとか、Linuxだったらスラッシュだったり。
JavaでOSごとのセパレータを取得するには、

String systemSeparator = System.getProperty("file.separator");

のように書く。

こちらが、上のLoggerクラスで使っているUtilitiesクラス。

package util;

import java.io.File;
import java.io.IOException;

public class Utilities {
    
    public static String checkSeparator(String orgPath) {
        String systemSeparator = System.getProperty("file.separator");
        if (orgPath.endsWith(systemSeparator)) {
            return orgPath;
        } else {
            orgPath = orgPath.concat(systemSeparator);
        }
        return orgPath;
    }
    
    public static boolean fileCheck(File file) throws IOException {
        if(file.exists()) {
            if(file.isFile() && file.canWrite()) {
                return true;
            }
        } else {
            if (file.createNewFile()) {
                return true;
            } else {
                return false;
            }
                
        }
        return false;
    }

}

XMLにはこんな感じのを追加した。

  <bean id="log" class="util.Logger">
    <property name="logFilePath">
        <value>C:\tmp</value>
    </property>
    <property name="logFileName">
        <value>log.txt</value>
    </property>
  </bean>

で、上に書いたMainにLoggerのメソッドを追加したものを実行する。

package aop;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.FileSystemResource;

import util.Logger;

public class MainAop {
    private final static String TARGET_XML = "aopbean.xml";
    public static void main(String[] args) {
        BeanFactory factory = new XmlBeanFactory(new FileSystemResource(TARGET_XML));
        GreetingService greetBean = (GreetingService) factory.getBean("greet");
        Logger logger = (Logger) factory.getBean("log");
        logger.log("start!");
        greetBean.greet();
    }
}

結果として、対象のテキストに追記モードでメッセージが書き込まれるようになる。

ちなみにこんなログが出たら、セッターとゲッターが無いかもしれないので確認してみよう。

Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'logFilePath' of bean class [util.Logger]: Bean property 'logFilePath' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?

ちょっと長くなりすぎたので、一回ここで区切って、次の記事とかで、このログをAOPによって、コードを書かずにロギング処理ができるようにしてみたい。

読んだ本

SpringによるWebアプリケーションスーパーサンプル 第2版

SpringによるWebアプリケーションスーパーサンプル 第2版


Springを勉強する本で、日本語の書籍では唯一と言っていいくらい素晴らしい本。
最新のSpringの動向を追いたいなら、Spring3入門などがある。
入門者はこっちのスーパーサンプルがいいと思う。

感謝のプログラミング

今回で感謝のプログラミングは【452時間目】
10000時間まで、あと【9548時間】