Lubuntu 24.04 LTS を古いPCにインストールしてみました。

ubuntu22.04LTS を載せているASUSのPCがあるのですが、いまいち動きがもっさりしているので lubuntu に入れ替えてみることにしました。lubuntu は ubuntu の軽量版のOSとのことです。インストール手順は ubuntu と同様にライブUSBを作成してインストールをします。

まずは lubuntu のISOイメージを取得します。lubuntu のダウンロードページ ( https://lubuntu.me/downloads/ ) から取得します。

LTS版のほうの「Desktop 64bit」をクリックします。

ISOイメージの一覧の中から「lubuntu-24.04.3-desktop-amd64.iso」を選びます。

ISOイメージがダウンロードされます。

インストール用のライブUSBを作成します。作成にはRufusを使いました。Rufusはwindows向けのライブUSBを作成するツールです。Rufusを起動して設定項目に入力をしていきます。

入力内容です。

  • デバイス・・・USBメモリを選択。
  • ブートの種類・・・ダウンロードした lubuntu のISOイメージを選択。
  • パーティション構成・・・GPT を選択。
  • ターゲットシステム・・・UEFI (CSM無効) を選択。
  • ボリュームラベル・・・自動入力 (そのまま) 。
  • ファイルシステム・・・FAT32 (規定) を選択。
  • クラスターサイズ・・・8192バイト (規定) を選択。

この設定の中で悩むのがパーティション構成とターゲットシステムです。これはインストールをするPCのBIOSによるためです。かなり古いPCだと以下の組み合わせのほうが良いです。

  • パーティション構成・・・MBR を選択。
  • ターゲットシステム・・・BIOSまたはUEFI-CSM を選択。

今回の場合ですが、BIOSの設定画面ではMBRやUEFIの表示がなくて困りました(どっちなのかわからない)。ただBIOSの画面の中にUEFIの特徴である Secure Boot の項目があったのでUEFIと判断しました。

他には、UEFIかどうか判断できるものに GOP Version というものがあるようです。GOP( Graphics Output Protocol ) はUEFI専用の仕組みで、この表示があるPCはUEFIファームウェアを搭載しているとのことです。

Rufusの設定画面のスタートボタンを押下するとライブUSBの作成が始まります。作成が完了すると下のバー全体が緑色になります。

閉じるボタンでRufusを終了します。

ライブUSBをPCに挿して電源ボタンを押下します。PCの種類によりますが、BIOS画面を呼び出すためにF2キーを押しておきます。BIOSの画面でブートの優先順位をUSBに変更します。

BIOS画面で設定をセーブして続けると、ライブUSBから lubuntu が立ち上がります。

「Install Lubuntu」のほうを選択します。

ちなみに上の2項目(言語とインターネット接続)も選択しておけばよかったのですが、忘れました。ただ言語はインストールの途中で設定ができて、インターネットは接続していなくてもインストールは完了します。インストール完了後にWiFiの設定をすれば問題ないです。

インストーラーの指示に従って設定をしていきます。画面キャプチャはないのですが設定の要領です。

[ ロケーション ]
Asia/Tokyo を選択します。言語は日本語を選択です。

[ キーボード ]
Japanese/Default を選択します。

[ Customize ]
ノーマルインストールかミニマムインストールかを選びます。ミニマムインストールのほうを選択しました。

[ パーティション ]
パーティションの置換、ディスクの消去、手動パーティション の中から選びます。パーティションの置換を選択しました。ファイルシステムを選ぶので ext4 にします。

[ ユーザー情報 ]
ユーザー情報を入力します。ユーザー名、パスワード、ホスト名を設定します。

インストールが完了すると再起動を促されます。再起動時には「インストールメディアを取り除いてからエンターキーを押下」と指示が出るので、そのようにします。再起動が完了すると lubuntu が起動します。

lubuntu のデスクトップ画面です。

フォルダを開いたときのものです。雰囲気ですが昔の Power Macintosh の Finder っぽく見えました(個人的な感想です)。

ターミナルはこのような感じです。

デスクトップ画面の左下の lubuntu の青い鳥のマークをクリックすると設定の中に Lubuntu Update があるのでやっておきます。

下部にある「Check for Updates」でアップデートするパッケージがあるか確認をします。インストールしたばかりだといくつかのアップデートが必要です。「Install Updates」をクリックするとインストールが行われます。

最小構成でインストールをしたのですが、ほとんどアプリが入っていなかったです。。ubuntu の最小構成を想定していたのですが軽量OSというだけあって本当に少ないです。vim はありましたがテキストエディターはなかったです。ウェブブラウザ( Firefox )も入っていませんでした。

とりあえずメモ書き程度はしたいので ubuntu と同じテキストエディターを追加でインストールしました。


$ sudo apt update
$ sudo apt install gnome-text-editor

テキストエディターのバージョンの確認です。


$ gnome-text-editor --version

テキストエディターをインストールしただけなので、このままでは日本語の入力ができません。日本語のパッケージも入れておきます。

日本語のパッケージ、および、フォントのインストールです。


$ sudo apt update
$ sudo apt install language-pack-ja language-pack-ja-base language-pack-gnome-ja language-pack-gnome-ja-base fonts-noto-cjk
  • language-pack-ja・・・システムメッセージの日本語化をします。
  • language-pack-gnome-ja・・・GNOME系アプリ ( gnome-text-editor など ) の日本語化をします。
  • fonts-noto-cjk・・・日本語フォントです。

IMEのインストールをします。


$ sudo apt install fcitx5 fcitx5-mozc fcitx5-config-qt fcitx5-frontend-qt6 fcitx5-frontend-gtk4
  • fcitx5・・・入力メソッド本体です。
  • fcitx5-mozc・・・日本語入力ベースの変換エンジンです。
  • fcitx5-config-qt・・・設定ツールです。

fcitx5-frontend-qt6、および、fcitx5-frontend-gtk4 は必要に応じてのようです(どういうものかはわかっていない)。

環境変数の設定を行います。ホームディレクトリに .xprofile というファイルを新規作成します。.xprofile はログイン時に自動で読み込まれるユーザー専用の初期化ファイルです。


$ vi ~/.xprofile

.xprofile には以下を記載します。


export GTK_IM_MODULE=fcitx
export QT_IM_MODULE=fcitx
export XMODIFIERS="@im=fcitx"

ロケールの切り替えをします。


$ sudo update-locale LANG=ja_JP.UTF-8

OSの再起動を行います。

再起動後、日本語入力が有効になってテキストエディターに日本語が入力可能になります。ファイル名にも日本語が使用できるようになります。

rootのパスワードも設定をしておきます。ターミナルから passwd コマンドで実施します。


$ sudo passwd root
[sudo] tak のパスワード: 
新しいパスワード: 
新しいパスワードを再入力してください: 
passwd: パスワードは正しく更新されました 

最後に。
lubuntu24.04LTS のサポート期間ですが、通常の ubuntu とは異なり3年間です。27年4月までのサポートとなります。

Spring Boot で AOP のサンプルプログラムを作ってみた。

Spring Boot で AOP( Aspect Oriented Programming ) のサンプルプログラムを作ってみました。コマンドラインから実行して文字列を画面に標準出力するだけのものですが、AOPによりメソッドの前後で標準出力が追加されることを確認しました。

以下がサンプルプログラムの実行例です。

AOPをしていない状態のときのものです(実行結果①とします)。

処理 : Hello, World. と出力しています。

AOPをしてメソッドの前後で標準出力を追加したときのものです(実行家結果②とします)。

処理 : Hello, World. の前後に 開始 と 終了 の出力が追加されています。

Spring Boot のプロジェクトは Spring Initializr で生成しました。Spring Initializr のURLは https://start.spring.io/ です。

Group、Artifact、Name は以下としました。

Group : com.example
Artifact : demo12
Name : demo12

ビルドは Gradle です。プロジェクトをダウンロードします。

今回の Spring Boot のサンプルプログラムでは、標準出力を行うサービス、および、AOPを行うコンポーネントを作成します。

Applicationクラス
Demo12Application.java

サービス
CommandService.java
CommandServiceImpl.java

AOPのコンポーネント
CommonLog.java

プロジェクト内のファイルの構成は、このようになります。赤字が追加・修正をするファイルです。

Applicationクラスの Demo12Application.java の説明からします。

Demo12Application.java は Spring Initializr により最初から生成されていますが、これを以下のように書き換えます(テキストファイルの画像ですのでソースは最後に載せておきます)。

Demo12Application は ApplicationRunner の実装をしています。ApplicationRunner のrunメソッドをオーバーライドすることによりコマンドラインの引数を取得します。引数は ApplicationArguments が保持しています。

runメソッドではサービスのメソッドを呼び出しています。画面への標準出力の処理はサービスのほうに記載しています。サービスは @Autowired でフィールドインジェクションをしています。

サンプルプログラムでは setBannerMode をオフにして Spring Boot のバナー表示を抑止しています。

サービスの説明です。

サービスはインターフェースの CommandService.java と、それを実装した CommandServiceImpl.java を用意します。サービスのパッケージは別にしているため service フォルダを作成して、その中にこれらのファイルを格納します。

CommandService.java のソースです。

display01( )、および、display02( ) というメソッドを定義しています。ApplicationクラスがサービスをDIして使うようにしているためインターフェイスを用意しています。

CommandServiceImpl.java のソースです。CommandService の実装をします。

Service アノテーションを付けています。これにより CommandServiceImpl がDIコンテナに格納されます。各メソッドでは文字列の標準出力を行っています。

AOPのコンポーネントを説明する前にAOPなしの状態で動かしてみます。

build.gradle の dependencies に太字部分を追加します。


dependencies {
	implementation 'org.springframework.boot:spring-boot-starter'
	implementation 'org.springframework.boot:spring-boot-starter-aop'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

Spring Boot を起動します。

$ ./gradlew bootRun

最初に示した「実行結果①」になります。もしうまくいかない場合は --refresh-dependencies を付けて実行してみてください。

AOPで標準出力を追加します。aop フォルダを作成して、その中に CommonLog.java を新規で作成します。

CommonLog.java のソースです。

Aspect アノテーションと Component アノテーションを付けています。

アスペクト( Aspect )とはプログラムの複数の場所に散在する共通処理をまとめたものです。アスペクトという単位でモジュール化したものらしいですが意味がわからないので「まとめたもの」と書いています。AOPをするクラス(共通処理を行うクラス)に Aspect アノテーション付けておくことでアスペクトとして機能するようです。またこの共通処理のことをアドバイス( Advice )と呼んでいます。アスペクトによって実行されるアクションがアドバイスということです。

Component アノテーションを付けることでアスペクトがDIコンテナに格納されます。

Before アノテーション と AfterReturning アノテーションですが、これはAOPの実行タイミングを指定するものです。AOPの実行タイミングには以下のものがあります。

  • @Before・・・対象メソッドが行われる前に実行する。
  • @After・・・対象メソッドが行われた後に実行する(例外発生の有無に関わらない)。
  • @AfterReturning・・・対象メソッドが正常終了した場合に実行する。
  • @AfterThrowing・・・対象メソッドに例外が発生した場合に実行する。
  • @Around・・・対象メソッドの前後で実行する。

beforeLog( ) には @Before を付けていますので beforeLog( ) が特定の処理の前に実行されます。同様に afterLog( ) には @AfterReturning が付いていますので特定の処理の後に afterLog( ) が実行されます。

では特定の処理とは何かと言うと execution で指定しているメソッドが該当します。サンプルでは以下です。execution で指定するメソッドにはワイルドカードが使えます。

* com.example.demo12.service.*.*(..)

  • アスタリスク ( * ) ・・・任意の1つの文字列にマッチする。
  • ドットドット ( .. ) ・・・任意の0個以上の文字にマッチする。

先頭のアスタリスクは戻り値が任意ということです。対象のクラス、メソッドは com.example.demo12.service.*.* であるため service パッケージに含まれる任意のクラス、メソッドになります。最後の ( .. ) はメソッドの引数を表しています。

サンプルでは service パッケージに CommandServiceImpl があり、このクラスには display01( )、および、display02( ) のメソッドがあります。display01( )、display02( ) とも execution の指定にマッチしますので beforeLog( ) と afterLog( ) が指定のタイミングで実行されます。

なお、このAOPされるメソッド( execution で指定されたメソッド )のことをポイントカットと呼んでいます。

beforeLog( ) と afterLog( ) の引数に JoinPoint というクラスがありますが、これはポイントカットでAOPされた実際のクラス、メソッドの情報です。outputLog( ) では JoinPoint を使ってクラス、および、メソッド名を取得しています。

それではもう一度、gradlew bootRun で Spring Boot を起動してみます。今度の結果は「実行結果②」になります。

AOPのコンポーネントである CommonLog.java を追加したのですが、既存のソースには何も手を加えないで処理の追加ができたことがわかります。AOPはログの出力をする際に役に立ちます。

実行結果①、②ですが、bootRun での実行であるため引数を受け取れていません。jarファイルを作成してコマンドラインに引数を渡します。

ビルドをします。

$ ./gradlew build

jarファイルが /demo12/build/libs 配下にできます。jarファイルを実行します。引数に --SpringBoot を付与するかどうかによって実行結果が変わります。

$ java -jar demo12-0.0.1-SNAPSHOT.jar

$ java -jar demo12-0.0.1-SNAPSHOT.jar --SpringBoot

サンプルプログラムのソースを以下に記載しておきます。

Applicationクラス


package com.example.demo12;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.Banner.Mode;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.ApplicationArguments;
import org.springframework.beans.factory.annotation.Autowired;
import com.example.demo12.service.CommandService;

@SpringBootApplication
public class Demo12Application implements ApplicationRunner {

	@Autowired
	CommandService service;

	public static void main(String[] args) {

		SpringApplication app = new SpringApplication(Demo12Application.class);
		app.setBannerMode(Mode.OFF);
		app.run(args);

	}

	@Override
	public void run( ApplicationArguments args ) {

		if ( args.containsOption("SpringBoot") )
			service.display01();
		else
			service.display02();

	}

}

サービス


package com.example.demo12.service;

public interface CommandService {

	void display01();
	void display02();

}

package com.example.demo12.service;

import org.springframework.stereotype.Service;

@Service
public class CommandServiceImpl implements CommandService {

	public void display01() {
		System.out.println("処理 : Hello, Spring Boot.");
	}

	public void display02() {
		System.out.println("処理 : Hello, World.");
	}

}

AOPのコンポーネント


package com.example.demo12.aop;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.JoinPoint;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class CommonLog {

	@Before( "execution( * com.example.demo12.service.*.*(..) )" )
	public void beforeLog( JoinPoint jp ) {
		outputLog("開始", jp);
	}

	@AfterReturning( "execution( * com.example.demo12.service.*.*(..) )" )
	public void afterLog( JoinPoint jp ) {
		outputLog("終了", jp);
	}

	private void outputLog( String str, JoinPoint jp ) {

		String className = jp.getTarget().getClass().getSimpleName();
		String methodName = jp.getSignature().getName();
		System.out.println( str + " : " + className + "." +methodName + "()" );

	}

}