0
1

Singleton作成時の注意点

Last updated at Posted at 2023-11-04
  • 複数のクライアントが1つの同じオブジェクト インスタンスを共有するため、無状態(stateless)に設計する必要がある。
  • 特定のクライアントに依存するフィールドがあってはならない。
  • なるべく読むことだけが可能でなければならない。 値を修正してはいけない。
  • フィールドの代わりにJavaで共有されない、ローカル変数、パラメータ、Thread Localなどを使用しなければならない。

<問題点>
例えば、以下のように状態を維持するフィールドを作ってしまうと、
stateful Service 1 で100、stateful Service 2 で200を注文しましたが、statefulService1が200を注文したと出てくる。

package hello.hellospring.singletone;

public class StatefulService {

    // 状態を保つフィールド
    private int price;

    public void order(String name, int price){
        this.price = price;
    }

    public int getPrice() {
        return price;
    }
}
package hello.hellospring;

public class SingleToneTest {
    static class TestConfig{
        @Bean
        public StatefulService statefulService() {
            return new StatefulService();
        }
    }

    @Test
    void stateFulTest(){
        ApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
        StatefulService statefulService1 = ac.getBean(StatefulService.class);
        StatefulService statefulService2 = ac.getBean(StatefulService.class);

        // ThreadA : Aユーザー 100 注文
        statefulService1.order("userA",100);
        // ThreadA : Bユーザー 200 注文
        statefulService2.order("userB", 200);

        System.out.println(statefulService1.getPrice());
        // 100ではなく200が出力される。
        // stateful Service 1、stateful Service 2 が同じインスタンスを使用し、
        // priceがstatefulになっているからだ。
        // このような場合が発生しないように、無状態(stateless)に設計しなければならない。
    }
}

<解決策>

this.price=priceを使わず、すぐにreturn priceするように変えなければならない。

package hello.hellospring.singletone;

public class StatefulService {

    public int order(String name, int price){
        return price;
    }
}
package hello.hellospring;

public class SingleToneTest {
    static class TestConfig{
        @Bean
        public StatefulService statefulService() {
            return new StatefulService();
        }
    }

    @Test
    void stateFulTest(){
        ApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
        StatefulService statefulService1 = ac.getBean(StatefulService.class);
        StatefulService statefulService2 = ac.getBean(StatefulService.class);

        int userAPrice = statefulService1.order("userA",100);
        int userBPrice = statefulService2.order("userB", 200);

        System.out.println(userAPrice);
        // 100
        System.out.println(userBPrice);
        // 200
    }
}
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1