Use this skill when creating a BoxLang module: ModuleConfig.bx structure, lifecycle methods (configure/onLoad/onUnload), module metadata, registering interceptors and BIFs, Gradle build setup, publishing to ForgeBox, or using the official module template.
A BoxLang module is a packaged unit of functionality that extends the runtime
with new built-in functions (BIFs), components, interceptors, and Java libraries.
Modules are auto-discovered by the runtime on startup and managed through the
ModuleService. The official module template
is the recommended starting point.
my-module/
├── ModuleConfig.bx # Required: module descriptor and lifecycle
├── box.json # CommandBox/ForgeBox package manifest
├── build.gradle # Gradle build configuration
├── gradle/
│ └── wrapper/
├── bifs/ # Custom built-in functions
│ ├── MyFunction.bx # BoxLang BIF
│ └── MyJavaFunction.java # Java BIF
├── components/ # Custom tags/components
│ └── MyComponent.bx
├── interceptors/ # Event listeners
│ └── MyInterceptor.bx
├── models/ # Supporting classes and services
│ └── MyService.bx
├── libs/ # JAR dependencies (module-scoped)
│ └── some-library.jar
├── src/
│ ├── main/
│ │ ├── bx/ # BoxLang source (mirrored into module root)
│ │ └── java/ # Java source
│ └── test/
│ ├── bx/ # BoxLang tests
│ └── java/ # Java unit tests
└── settings.gradle
ModuleConfig.bxThe heart of every module. Must exist (can be empty, but lifecycle methods are recommended):
// ModuleConfig.bx
class {
// --- Module Metadata ---
// These are read by the ModuleService
this.title = "My Awesome Module"
this.author = "Your Name <[email protected]>"
this.description = "Does amazing things for BoxLang"
this.version = "1.0.0"
this.boxlangVersion = ">=1.10.0"
// Module settings with defaults (overridden by boxlang.json)
this.settings = {
apiKey : "",
baseUrl : "https://api.example.com",
timeout : 30,
retryCount : 3,
debugMode : false
}
// Interceptors to auto-register on module load
this.interceptors = [
{
class : "#moduleRecord.invocationPath#.interceptors.RequestLogger",
properties : { logLevel: "INFO" }
}
]
// Component paths to register
this.componentPaths = [
"#moduleRecord.physicalPath#/components"
]
// --- Lifecycle Methods ---
/**
* Called first. Set up default settings, validate config, etc.
* The `settings` struct is already merged with user overrides by this point.
*/
function configure() {
// Validate required settings
if ( !len( settings.apiKey ) ) {
throw(
message = "bx-mymodule: apiKey setting is required",
type = "bx-mymodule.ConfigurationError"
)
}
// Set computed settings
settings.baseUrlWithVersion = settings.baseUrl & "/v1"
// Register custom datasource, cache, etc.
}
/**
* Called after the module is fully loaded and registered.
* Use for resource initialization, warm-up, service registration.
*/
function onLoad() {
// Register a service in the BoxRuntime IOC container
// boxRuntime.registerService( "MyService", new models.MyService( settings ) )
// Log startup
log.info( "bx-mymodule loaded successfully. Version: #this.version#" )
}
/**
* Called when the module is unloaded (server shutdown, hot-reload).
* Use for cleanup, closing connections, flushing buffers.
*/
function onUnload() {
// Close connections, cleanup resources
log.info( "bx-mymodule unloaded." )
}
}
BoxLang injects these variables into ModuleConfig.bx automatically:
| Variable | Type | Description |
|---|---|---|
settings | Struct | Merged module settings (defaults + user overrides) |
moduleRecord | Struct | Module metadata: name, version, physicalPath, invocationPath |
boxRuntime | BoxRuntime | The BoxLang runtime instance |
log | Logger | Module-specific logger |
interceptorService | InterceptorService | To register interceptors programmatically |
moduleService | ModuleService | To interact with other modules |
wirebox | WireBox | IOC container (if bx-wirebox is installed) |
box.json — Package Manifest{
"name": "bx-mymodule",
"version": "1.0.0",
"author": "Your Name",
"description": "Does amazing things for BoxLang",
"homepage": "https://github.com/you/bx-mymodule",
"keywords": ["boxlang", "module"],
"license": "Apache-2.0",
"repository": {
"type": "git",
"url": "https://github.com/you/bx-mymodule"
},
"dependencies": {},
"devDependencies": {
"testbox": "^5.0.0"
},
"type": "boxlang-module",
"boxlangVersion": ">=1.10.0"
}
Based on the official module template:
// build.gradle
plugins {
id "java"
id "com.diffplug.spotless" version "6.25.0"
}
repositories {
mavenCentral()
maven { url "https://downloads.ortussolutions.com/maven" }
}
dependencies {
// BoxLang runtime (downloaded by downloadBoxLang task)
compileOnly files( "libs/boxlang-1.0.0-all.jar" )
testImplementation files( "libs/boxlang-1.0.0-all.jar" )
// Your dependencies
implementation "com.example:my-library:1.2.3"
}
// Key Gradle tasks:
// ./gradlew downloadBoxLang - Download the BoxLang binary (run first!)
// ./gradlew build - Compile and package
// ./gradlew test - Run all tests
// ./gradlew jar - Package into JAR only
// ./gradlew clean - Remove build artifacts
# Initial setup — download BoxLang runtime
./gradlew downloadBoxLang
# Full build
./gradlew build
# Run tests
./gradlew test
# Package for distribution
./gradlew jar
# Check code formatting
./gradlew spotlessCheck
# Auto-fix formatting
./gradlew spotlessApply
Users configure module settings in their boxlang.json:
{
"modules": {
"bx-mymodule": {
"enabled": true,
"settings": {
"apiKey" : "user-api-key-here",
"timeout" : 60,
"debugMode" : false
}
}
}
}
Access settings in ModuleConfig.bx or BIFs via the settings struct.
// In any BIF or interceptor inside your module
class {
function invoke() {
// Get the module settings
var moduleSettings = boxRuntime
.getModuleService()
.getModuleRecord( "bx-mymodule" )
.settings
var apiKey = moduleSettings.apiKey
// ...
}
}
# Login to ForgeBox
box forgebox login
# Publish
box forgebox publish
# Or bump version then publish
box bump --minor
box forgebox publish
# Reload a module without restarting the server
box server reload
# or via CommandBox shell:
box> reload
// tests/specs/MyModuleTest.bx
class extends="testbox.system.BaseSpec" {
function beforeAll() {
// Load the module into a test runtime
setup()
}
function run() {
describe( "My Module BIFs", function() {
it( "should call myFunction and return the expected result", function() {
var result = myFunction( "test" )
expect( result ).toBe( "expected" )
})
})
}
}
# Run tests
box testbox run
PyTorch深度学习模式与最佳实践,用于构建稳健、高效且可复现的训练流程、模型架构和数据加载。