はじめに
JavaでLogを出力際には、Log4jやLogbackなどのライブラリを使ったりjava.util.loggingを使ったりします。どのライブラリ・APIでも大抵は以下のようにLoggerインスタンスを取得・生成します。
Logger logger = Logger.getLogger(Hoge.class);
すべてのクラスでこれらを書いていくのは面倒です。
Springを使ってもうちょっとシンプルに書く方法を探してみましょう。
元ネタ
ほぼ、このサイトの実装の紹介です。
http://memorynotfound.com/spring-inject-logger-annotation-example/
ありとうございます。
SpringによるLoggerのInjection
Springを使っている場合、以下のようにアノテーションが付いているfiledに対してLoggerをInjectionすることができます。
    @Log
    private static Logger logger;
記述量は少しですがへりましたし、引数のクラスを明示しなくてもよくなることでLoggerのミス(コピペで時々あるはずです)をなくすることができます。
いかに実装方法を説明していきます。
Logアノテーション
以下のようにLogアノテーションを作成します。
@Retention(RUNTIME)
@Target(FIELD)
@Documented
public @interface Log {
}
ランタイムで参照するので@Retention(RUNTIME) 、対象はフィールドなので@Target(FIELD)とします。
LogInjector
Springをつかって、先ほど作成した@Logアノテーションが付与されたフィールドに、LoggerをInjectionするコードを書きます。
以下のようにSpringのBeanPostProcessor実装を作成し、その中でLoggerを作成します。
@Component
public class LogInjector implements BeanPostProcessor {
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
    @Override
    public Object postProcessBeforeInitialization(final Object bean, String name) throws BeansException {
        ReflectionUtils.doWithFields(bean.getClass(), new ReflectionUtils.FieldCallback() {
            public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
                // make the field accessible if defined private
                ReflectionUtils.makeAccessible(field);
                if (field.getAnnotation(Log.class) != null) {
                    Logger log = Logger.getLogger(bean.getClass());
                    field.set(bean, log);
                }
            }
        });
        return bean;
    }
}
使用方法
これで準備は整いました。あとは以下の手順で使えるようになります。
- LogInjectorをSpring管理下におく。
- LoggerをInjectionしたいクラスのstatic filedに @Logを付与する。
これで毎回 getLogger しなくて済むようになりました。