Implement Dynamic Discount Rules in Spring Boot with Drools

This guide shows how to integrate the Drools rule engine into a Spring Boot application to calculate e‑commerce discounts dynamically, covering Maven dependencies, configuration, model definitions, DRL rule creation, service and controller layers, and a simple test scenario demonstrating rule‑driven discount computation.

macrozheng
macrozheng
macrozheng
Implement Dynamic Discount Rules in Spring Boot with Drools

Introduction

When an e‑commerce system needs to calculate discounts based on flexible business rules—such as extra 5 % for VIP customers or an additional 10 % for orders over 1000 CNY—hard‑coding the logic would require code changes, retesting and redeployment each time a rule changes. Using a rule engine like Drools allows the rules to be externalised and modified without touching the business code.

Adding Maven Dependencies

Create a Spring Boot project and add the following Drools dependencies to pom.xml:

<dependency>
  <groupId>org.drools</groupId>
  <artifactId>drools-core</artifactId>
  <version>7.59.0.Final</version>
</dependency>
<dependency>
  <groupId>org.drools</groupId>
  <artifactId>drools-compiler</artifactId>
  <version>7.59.0.Final</version>
</dependency>
<dependency>
  <groupId>org.drools</groupId>
  <artifactId>drools-decisiontables</artifactId>
  <version>7.59.0.Final</version>
</dependency>

Drools Configuration Class

Create a DroolsConfig class that registers a KieContainer bean and loads the DRL files from src/main/resources/rules:

@Configuration
public class DroolsConfig {
    // Path to the rule file
    private static final String RULES_CUSTOMER_RULES_DRL = "rules/customer-discount.drl";
    private static final KieServices kieServices = KieServices.Factory.get();

    @Bean
    public KieContainer kieContainer() {
        KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
        kieFileSystem.write(ResourceFactory.newClassPathResource(RULES_CUSTOMER_RULES_DRL));
        KieBuilder kb = kieServices.newKieBuilder(kieFileSystem);
        kb.buildAll();
        KieModule kieModule = kb.getKieModule();
        return kieServices.newKieContainer(kieModule.getReleaseId());
    }
}

Defines a Spring bean of type KieContainer that loads the DRL file from the classpath.

Creates a KieFileSystem to write the rule file.

Builds the Drools module with KieBuilder.

Exposes the container as a Spring bean.

Business Model Classes

Define the request object, an enum for customer type, and a DTO for the discount result.

@Getter @Setter
public class OrderRequest {
    private String customerNumber;
    private Integer age;
    private Integer amount;
    private CustomerType customerType;
}
public enum CustomerType {
    LOYAL, NEW, DISSATISFIED;
    public String getValue() { return this.toString(); }
}
@Getter @Setter
public class OrderDiscount {
    private Integer discount = 0;
}

Drools Rules (customer-discount.drl)

The DRL file contains four rules that adjust a global orderDiscount object.

import com.alvin.drools.model.OrderRequest;
import com.alvin.drools.model.CustomerType;
global com.alvin.drools.model.OrderDiscount orderDiscount;

dialect "mvel"

// Rule 1: Age based discount
rule "Age based discount"
    when
        OrderRequest(age < 20 || age > 50)
    then
        System.out.println("==========Adding 10% discount for Kids/ senior customer=============");
        orderDiscount.setDiscount(orderDiscount.getDiscount() + 10);
end

// Rule 2: Loyal customer discount
rule "Customer type based discount - Loyal customer"
    when
        OrderRequest(customerType.getValue == "LOYAL")
    then
        System.out.println("==========Adding 5% discount for LOYAL customer=============");
        orderDiscount.setDiscount(orderDiscount.getDiscount() + 5);
end

// Rule 3: Other customer types
rule "Customer type based discount - others"
    when
        OrderRequest(customerType.getValue != "LOYAL")
    then
        System.out.println("==========Adding 3% discount for NEW or DISSATISFIED customer=============");
        orderDiscount.setDiscount(orderDiscount.getDiscount() + 3);
end

// Rule 4: Amount based discount
rule "Amount based discount"
    when
        OrderRequest(amount > 1000L)
    then
        System.out.println("==========Adding 5% discount for amount more than 1000$=============");
        orderDiscount.setDiscount(orderDiscount.getDiscount() + 5);
end

Service Layer

The OrderDiscountService obtains a KieSession, injects the global discount object, inserts the request, fires all rules and returns the calculated discount.

@Service
public class OrderDiscountService {

    @Autowired
    private KieContainer kieContainer;

    public OrderDiscount getDiscount(OrderRequest orderRequest) {
        OrderDiscount orderDiscount = new OrderDiscount();
        KieSession kieSession = kieContainer.newKieSession();
        kieSession.setGlobal("orderDiscount", orderDiscount);
        kieSession.insert(orderRequest);
        kieSession.fireAllRules();
        kieSession.dispose();
        return orderDiscount;
    }
}

Controller

Expose a REST endpoint that receives an OrderRequest JSON and returns the calculated OrderDiscount.

@RestController
public class OrderDiscountController {

    @Autowired
    private OrderDiscountService orderDiscountService;

    @PostMapping("/get-discount")
    public ResponseEntity<OrderDiscount> getDiscount(@RequestBody OrderRequest orderRequest) {
        OrderDiscount discount = orderDiscountService.getDiscount(orderRequest);
        return new ResponseEntity<>(discount, HttpStatus.OK);
    }
}

Testing

Run the Spring Boot application and POST a JSON payload such as:

{
  "customerNumber": "C001",
  "age": 18,
  "amount": 1200,
  "customerType": "LOYAL"
}

For a loyal customer younger than 20 with an order amount greater than 1000, the rules above produce a total discount of 20 % (10 % age discount + 5 % loyal‑customer discount + 5 % amount discount).

Conclusion

By integrating Drools with Spring Boot we can externalise discount logic into a DRL file, allowing business users or product managers to add or modify rules—such as a new rule for customers in a specific city—without changing Java code, thus speeding up iteration and reducing deployment risk.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

BackendjavaDroolsspring-bootdiscountrule-engine
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.