(Quick Reference)

2 Usage

Version: 2023.3.0-SNAPSHOT

2 Usage

Creating a new Spring app

$ spring init \
    -a=gs-spring-boot \
    -g=grace.guides \
    -n="Grace Guide for Spring Boot" \
    --description="Spring Boot Application with Grace Plugins" \
    --package-name=grace.guides \
    -l=groovy \
    --build=gradle \
    --format=project \
    -t=gradle-project \
    -d=devtools,actuator,web -x

Using Spring Boot 3.3.11

In this guide, I will use Spring Boot 3.3.11, Grace 2023.3.0-RC2 is now built upon version 3.3.11.

plugins {
        id 'groovy'
        id 'org.springframework.boot' version '3.3.11'
        id 'io.spring.dependency-management' version '1.1.7'
}

group = 'grace.guides'
version = '0.0.1-SNAPSHOT'

java {
        sourceCompatibility = '17'
}

repositories {
        mavenCentral()
}

configurations {
        developmentOlny
}

dependencies {
        developmentOlny 'org.springframework.boot:spring-boot-starter-devtools'
        implementation 'org.springframework.boot:spring-boot-starter-actuator'
        implementation 'org.springframework.boot:spring-boot-starter-web'
        implementation 'org.apache.groovy:groovy'
        testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
        useJUnitPlatform()
}

Adding Grace dependencies and plugins

First, import grace-bom, then add the Grace dependencies,

dependencyManagement {
        imports {
        mavenBom "org.graceframework:grace-bom:$graceVersion"
    }
}

dependencies {
        // Grace dependencies
        implementation 'org.graceframework:grace-boot'
        implementation 'org.graceframework:grace-plugin-core'
        implementation 'org.graceframework:grace-plugin-management'
        implementation 'org.graceframework.plugins:dynamic-modules:1.0.0-M1'
    ...
}

Enabling Endpoints

grace-plugin-management include a built-in endpoint /plugins.

management.endpoints.enabled-by-default=true
management.endpoints.web.exposure.include=*

Creating a Dynamic Plugin

LanguageGrailsPlugin is a DynamicPlugin, you can register dynamic modules by providing providedModules

def providedModules = [LanguageModuleDescriptor]
class LanguageGrailsPlugin extends DynamicPlugin {

    def version = "1.0.0"
    def providedModules = [LanguageModuleDescriptor]

    Closure doWithSpring() { {->
            // You can also use Spring AutoConfiguration
            languageManager(DefaultLanguageManager)
        }
    }

    Closure doWithDynamicModules() { {->
        // Supported Languages
        language(key: 'en_US', title: 'English', i18nNameKey: 'languages.en_US')
        language(key: 'zh_CN', title: 'Chinese (Simplified Chinese)', i18nNameKey: 'languages.zh_CN')
        language(key: 'zh_TW', title: 'Chinese (Traditional Chinese)', i18nNameKey: 'languages.zh_TW', enabled: true)
    }}

}

Using LanguageModuleDescriptor

@SpringBootApplication
class GraceBootApplication implements CommandLineRunner {

    @Autowired
    LanguageManager languageManager

    static void main(String[] args) {
        SpringApplication.run(GraceBootApplication, args)
    }

    @Override
    void run(String... args) throws Exception {
        List<LanguageModuleDescriptor> languageModuleDescriptors = this.languageManager.getLanguages()

        languageModuleDescriptors.each { md ->
            println "Language: key=$md.key, title=$md.title"
        }
    }

}

Starting

➜  gs-spring-boot git:(main) ✗ ./gradlew bootRun

> Task :bootRun

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::               (v3.3.11)

2025-05-13T23:40:44.028+08:00  INFO 28030 --- [           main] grace.guides.GraceBootApplication        : Starting GraceBootApplication using Java 17.0.15 with PID 28030 ....
2025-05-13T23:40:44.029+08:00  INFO 28030 --- [           main] grace.guides.GraceBootApplication        : No active profile set, falling back to 1 default profile: "default"
2025-05-13T23:40:44.406+08:00  INFO 28030 --- [           main] g.plugins.DefaultGrailsPluginManager     : Total 3 plugins loaded successfully, take in 43 ms
...
2025-05-13T23:40:44.937+08:00  INFO 28030 --- [           main] grace.guides.GraceBootApplication        : Started GraceBootApplication in 1.032 seconds (process running for 1.332)
2025-05-13T23:40:44.937+08:00 DEBUG 28030 --- [           main] PluginsInfoApplicationContextInitializer :
----------------------------------------------------------------------------------------------------------
Order      Plugin Name                        Plugin Version                                       Enabled
----------------------------------------------------------------------------------------------------------
    1      Core                               2023.3.0-RC2                                               Y
    2      DynamicModules                     1.0.0-M1                                                   Y
    3      Language                           1.0.0                                                      Y
----------------------------------------------------------------------------------------------------------

Language: key=en_US, title=English
Language: key=zh_CN, title=Chinese (Simplified Chinese)
Language: key=zh_TW, title=Chinese (Traditional Chinese)

Accessing endpoints plugins and info

➜  gs-spring-boot git:(main) ✗ http :8080/actuator/plugins
HTTP/1.1 200
Connection: keep-alive
Content-Type: application/json
Date: Tue, 13 May 2025 15:41:36 GMT
Keep-Alive: timeout=60
Transfer-Encoding: chunked

{
    "plugins": [
        {
            "dependencies": [],
            "name": "core",
            "type": "org.grails.plugins.core.CoreGrailsPlugin",
            "version": "2023.3.0-RC2"
        },
        {
            "dependencies": [],
            "name": "dynamicModules",
            "type": "org.grails.plugins.modules.DynamicModulesGrailsPlugin",
            "version": "1.0.0-M1"
        },
        {
            "dependencies": [],
            "name": "language",
            "type": "grace.guides.plugins.LanguageGrailsPlugin",
            "version": "1.0.0"
        }
    ]
}

➜  gs-spring-boot git:(main) ✗ http :8080/actuator/info
HTTP/1.1 200
Connection: keep-alive
Content-Type: application/json
Date: Tue, 13 May 2025 15:41:20 GMT
Keep-Alive: timeout=60
Transfer-Encoding: chunked

{
    "app": {
        "grailsVersion": "2023.3.0-RC2",
        "name": "grailsApplication",
        "servletVersion": "6.0"
    }
}