我有一个 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变量之外的任何类级别变量)
如果您觉得有更好的方式或任何方式,请随时写信。
非常感谢我。
答案 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()
中的数据库的值。