Spring启动应用程序线程安全

时间:2017-08-18 16:17:31

标签: java spring spring-boot cassandra apache-kafka

我有一个 Spring-boot Java 应用程序,它可以连续地从 Kafka 流式传输数据,并在应用业务逻辑后将其保存到数据库 Cassandra

以下是完全类似于我的应用程序的伪类和函数。

KafkaStreamer

 @Configuration
 @EnableKafka
 public class KafkaStreamer {

    private static final Logger LOGGER = LoggerFactory.getLogger(MyDomain.class);

    @Autowired
    private MyController myController;

    @KafkaListener(topics = "${my-topic}", group = "${my-group}")
    public void streamFromKafka(String payload) {
        myController.processPayload(payload);
        LOGGER.info("I am continously streaming data from Kafka "
                + "and forwarding it to controller for further processing...!");
    }
}

myController的

@Controller
public class MyController {

    private static final Logger LOGGER = LoggerFactory.getLogger(MyDomain.class);

    @Autowired
    private MyService myService;

    public void processPayload(String payload) {
        myService.applyBusinessLogic(payload);
        LOGGER.info("Send to service for business-logic processing");
    }
}

为MyService

@Service
public class MyService {
    private static final Logger LOGGER = LoggerFactory.getLogger(MyDomain.class);

    @Autowired
    private MyDomain myDomain;

    public void applyBusinessLogic(String payload) {
        myDomain.saveToDatabase(payload);
        LOGGER.info("Applied business-logic");
    }
}

MYDOMAIN

    @Repository
    public class MyDomain {

        private static final Logger LOGGER = LoggerFactory.getLogger(MyDomain.class);

   @Autowired
    private CassandraOperations cassandraTemplate;

    /** The session. */
    private Session session = null;

        public void saveToDatabase(String payload) {
            saveToTableA(payload);
            saveToTableB(payload);
            // Hello, I have saved data to database
            LOGGER.info("Saved data to database");
        }

        private void saveToTableB(String payload) {
             if (session == null)
                   session = cassandraTemplate.getSession();
             session.execute(payload);
        }

        private void saveToTableA(String payload) {
            if (session == null)
                   session = cassandraTemplate.getSession()
          session.execute(payload);

        }

    }

上面的伪代码完全类似于我的原始应用程序。

正如您所看到的,没有任何类级变量 除了记录器,MyDomain类中的一些自动连线变量和cassandra会话

根据我的知识,spring-boot默认情况下 auto-wire singleton

我将有效负载(这是我从Kafka传来的消息)从函数参数中的一个类传递到另一个类,而不是设置为其他类的类级属性。

我的问题是,

我的上述应用程序架构或代码线程是否安全?

Autowire可以创建问题,因为默认情况下它会给出一个类的单例引用(这里需要注意的是我没有除logger和auto-wire变量之外的任何类级别变量)

如果您觉得有更好的方式或任何方式,请随时写信。

非常感谢我。

1 个答案:

答案 0 :(得分:0)

如果您开始改变共享对象的状态,那么您的解决方案将停止为线程安全。

例如,如果payload单例Spring bean中有MyDomain属性,并将其值设置为saveToDatabase稍后(即使采用相同方法),请咨询它,这将是变异,你的代码将不是线程安全的。

例如:

@Repository
public class MyDomain {

   private String payload;

   public void saveToDatabase(String payload) {
        this.payload = payload;
        saveToTableA();
        saveToTableB();
   }


   private void saveToTableA() {
      tableA.save(this.payload);
   }

在这种情况下,当多个线程同时使用不同的值调用saveToDatabase时,无法保证您将真正保存到saveToTableA()中的数据库的值。