• home
  • forum
  • my
  • kt
  • download
  • Groovier Spring Integration basics

    Author: 2009-04-16 09:50:39 From:

    Spring 2.0 introduced support for integrating dynamic languages into Spring-based applications. Out of the box, Spring supports Groovy, JRuby, and BeanShell. The portions of your application that you write in Groovy, JRuby, or any other supported language (including, of course, the Java™ language) will integrate seamlessly into your Spring application. The rest of your application's code doesn't need to know or care about the implementation language of individual Spring beans.

    Spring's support for dynamic languages means your applications can gain flexibility and dynamic behavior with no strings attached; you can have your cake and eat it too. In Part 1 of this series, you'll see how to use Spring and Groovy together, and how that powerful combination can add interesting capabilities to your application. For example, you might need to make frequent changes to small chunks of business logic, to the text contained in e-mail messages your application sends out, or to the formatting and layout of PDFs that your application generates. Traditional application architectures might require a complete redeployment of the application in order to make these kinds of changes. Spring's support for Groovy lets you make such changes to a deployed application and have them take effect immediately. I'll discuss the benefits this capability can bring to your application and the issues that might arise. The complete source code (see Download) for all of the article's examples is available for download.

    Spring's dynamic language support

    Dynamic-language support has changed Spring from a Java-centric application framework to a JVM-centric application framework. Now Spring doesn't just make Java development easier. It also makes development for the JVM easier by allowing code written in both static and dynamic languages to plug easily into the layered architectural approach Spring supports and facilitates. If you are already familiar with Spring, then you'll feel right at home: you can take advantage of all the features Spring already provides — inversion of control (IoC) and dependency injection, aspect-oriented programming (AOP), declarative transaction demarcation, Web and data-access framework integrations, remoting, and more — while using a flexible, dynamic language like Groovy.

    Spring supports dynamic-language integration via the ScriptFactory and ScriptSource interfaces. The ScriptFactory interface defines the mechanism for configuration and creation of scripted Spring beans. Theoretically, any language that runs on the JVM can be supported, and you could create your own implementation for your particular language of choice. ScriptSource defines how Spring accesses the actual script source code; for example, via the file system or a URL. Groovy language integration is supported via the GroovyScriptFactory implementation of ScriptFactory.

    Why Groovy?

    According to the official Groovy site, Groovy is "an agile and dynamic language for the Java Virtual Machine" that "builds upon the strengths of Java but has additional power features inspired by languages like Python, Ruby and Smalltalk" such as dynamic typing, closures, and support for metaprogramming (see Resources). It is a full-fledged object-oriented programming language that can be used as such, or it can be used purely as a scripting language. I like to think of it as the Java language minus all the code I don't like writing, plus closures and other features you find in dynamic languages.

    Groovy makes a particularly compelling choice to use with Spring's dynamic-language support because it was designed specifically for the JVM and with tight Java integration in mind, making it easy for Groovy and Java code to interoperate. And its Java-like syntax feels natural to Java developers.

    It's time to see how to integrate Groovy code into a Spring-based application.


    Groovier Spring beans

    Using Groovy beans in a Spring application is just as easy as using Java beans. (You have more options, however, in how you configure them, as you'll see later.) To start, you need to define an interface to serve as the contract that your Groovy beans follow. Although it's not strictly necessary to define an interface, most Spring applications define interactions and dependencies among application components via interfaces, rather than concrete implementation classes, to promote loose coupling and easier testing.

    As an example, assume you have an interface that defines how PDFs are generated from Invoice objects, as shown in Listing 1:


    Listing 1. PdfGenerator interface

    public interface PdfGenerator {
        byte[] pdfFor(Invoice invoice);
    }
    

    The PdfGenerator interface serves as the contract for your Groovy implementation class. Groovy classes can implement interfaces in the same manner as Java classes, so this is quite easy. Listing 2 shows the Groovy implementation of PdfGenerator using the iText library (see Resources) to do the actual PDF generation; it returns a byte array containing the PDF contents:


    Listing 2. GroovyPdfGenerator

    class GroovyPdfGenerator implements PdfGenerator {
    
        String companyName
    
        public byte[] pdfFor(Invoice invoice) {
            Document document = new Document(PageSize.LETTER)
            ByteArrayOutputStream output = new ByteArrayOutputStream()
            PdfWriter.getInstance(document, output)
            document.open()
            Font headerFont = new Font(family: Font.HELVETICA, size: 24.0, style: Font.ITALIC)
            document.add(new Paragraph("$companyName", headerFont))
            document.add(new Paragraph("Invoice $invoice.orderNumber"))
            document.add(new Paragraph("Total amount: \$ ${invoice.total}"))
            document.close()
            output.toByteArray()
        }
    }
    

    GroovyPdfGenerator is now ready for action. It defines a string property named companyName, which is used on the generated PDF invoice along with the order number and total. At this point, you're ready to integrate GroovyPdfGenerator into your Spring application. Beans written using the Java language must be compiled into .class files, but you have several options when using Groovy-based beans:

    • Groovy class compiled into a normal Java class file
    • Groovy class or script defined in a .groovy file
    • Groovy script written inline in your Spring configuration file

    Depending on which of these options you use for a Groovy bean, you can choose among several ways to define and configure your Groovy beans in a Spring application context. Next, I'll explore each of these configuration options.


    Groovy bean configuration

    Generally, you configure Spring beans written in Java code by using XML or — as of Spring 2.5 (see Resources) — using annotations, which significantly cuts down on XML configuration. When you configure your Groovy beans, the available options depend on whether you are using compiled Groovy classes or Groovy classes defined in .groovy files. The main point to remember is that you can implement beans using Groovy and either compile them as you normally would in Java programming, or you can implement them as classes or scripts in .groovy files and let Spring take care of compiling them upon creation of the application context.

    If you choose to implement your beans in .groovy files, you do not compile them yourself. Instead, Spring reads the files to obtain the script source code, compiles them at run time, and makes them available in the application context. This provides more flexibility than straight compilation because the .groovy files don't necessarily need to be deployed in your application's JAR or WAR file and could instead come from somewhere in the file system or perhaps from a URL.

    Now you'll take a look at the various configuration options in action. Keep in mind the difference between beans defined in Groovy classes you compile as part of your own build process and beans defined in .groovy scripts.

    Configuring compiled Groovy classes

    Configuring a Groovy bean that has already been compiled into a .class file is exactly the same as configuring a Java-based bean. Assuming you've already compiled GroovyPdfGenerator using the groovyc compiler, you can define the bean using normal Spring XML configuration, as shown in Listing 3:


    Listing 3. Configuring precompiled GroovyPdfGenerator using XML

    <bean id="pdfGenerator" class="groovierspring.GroovyPdfGenerator">
        <property name="companyName" value="Groovy Bookstore"/>
    </bean>
    

    No constructor-based injection on Groovy beans

    Unfortunately, you currently cannot use constructor injection to set properties on Groovy beans — or any other dynamic-language beans such as JRuby beans. One reason this is not possible is that your scripts can define multiple implementation classes and logic to select a different implementation depending on run-time environment or other factors. In other words, the script itself might do the actual construction rather than Spring. Spring uses setter injection to set properties on the returned bean. Listing 7 shows an example.

    The configuration in Listing 3 is a plain old Spring bean definition. The fact that it is implemented in Groovy is immaterial. Any other component in a Spring application that contains the pdfGenerator bean can use it without knowing or caring about its implementation details or language. You can also set properties on the bean as you normally would by using the <property> element. (Spring 2.0 introduced the p namespace as a more concise way to define properties, but I've stuck with <property> elements because I've found them to be more readable — strictly a matter of preference.)

    Alternatively, you can use annotation-based configuration of GroovyPdfGenerator if you are using Spring 2.5 or later. In that case, you don't actually define the bean in your XML application context; instead, you annotate your class with the @Component stereotype annotation, as shown in Listing 4:


    Listing 4. Annotating GroovyPdfGenerator with @Component

    @Component("pdfGenerator")
    class GroovyPdfGenerator implements PdfGenerator {
        ...
    }
    

    And you enable annotation configuration and component scanning in the Spring application context XML configuration, as shown in Listing 5:


    Listing 5. Enabling Spring annotation configuration and component scanning

    <context:annotation-config/>
    <context:component-scan base-package="groovierspring"/>
    

    Whether you configure a compiled Groovy bean using XML or using annotations, remember that the configuration is identical to configuring normal Java-based beans.

    Configuring beans from Groovy scripts

    Configuring Groovy beans from .groovy scripts is quite different from configuring compiled Groovy beans. This is where things start to get much more interesting. The mechanism for converting Groovy scripts into beans involves reading the Groovy script, compiling it, and making it available as a bean in the Spring application context. The first step is to define a bean whose type is ostensibly GroovyScriptFactory and that points to the location of the Groovy script, as shown in Listing 6:


    Listing 6. Defining GroovyScriptFactory bean

    <bean id="pdfGenerator"
          class="org.springframework.scripting.groovy.GroovyScriptFactory">
        <constructor-arg value="classpath:groovierspring/GroovyPdfGenerator.groovy"/>
        <property name="companyName" value="Groovier Bookstore"/>
    </bean>
    

    In this listing, the pdfGenerator bean is defined as a GroovyScriptFactory. The <constructor-arg> element defines the location of the Groovy script you are configuring; note specifically that this points to a Groovy script, not a compiled Groovy class. You set properties on scripted objects using the same syntax you normally use when defining Spring beans. The <property> element in Listing 6 sets the companyName property just as you would expect.

    The GroovyPdfGenerator.groovy script must contain at least one class that implements your interface. Usually it is best to follow standard Java practice by defining one Groovy class per .groovy file. However, you might want to implement logic within the script to determine which type of bean to create. For example, you could define two different implementations of the PdfGenerator interface in GroovyPdfGenerator.groovy and perform logic directly in the script to determine which of those implementations should be returned. Listing 7 defines two different PdfGenerator implementations and selects the one to use based on a system property:


    Listing 7. Multiple class definitions in a Groovy script

    class SimpleGroovyPdfGenerator implements PdfGenerator {
        ...
    }
    
    class ComplexGroovyPdfGenerator implements PdfGenerator {
        ...
    }
    
    def type = System.properties['generatorType']
    if (type == 'simple')
        return new SimpleGroovyPdfGenerator()
    }
    else {
        return new ComplexGroovyPdfGenerator()
    }
    

    As this snippet shows, you could use a scripted bean to select a different implementation based on a system property. When the generatorType system property is simple, the script creates and returns a SimpleGroovyPdfGenerator; otherwise, it returns a ComplexGroovyPdfGenerator. Because both the simple and complex implementations implement the PdfGenerator interface, code using the pdfGenerator bean from within your Spring application will neither know nor care what the actual implementation is.

    Note that you can still set properties, as in Listing 6, on the bean returned from your script. So if the script returns a ComplexGroovyPdfGenerator, the companyName property will be set on that bean. When you don't need the additional flexibility of defining multiple implementations, you can define just one class in the Groovy script file, as shown in Listing 8. In this case, Spring finds this one class and instantiates it for you.


    Listing 8. Typical Groovy script implementation

    class GroovyPdfGenerator implements PdfGenerator {
        ...
    }
    

    At this point, you might be wondering why Listing 6 defines the bean as a GroovyScriptFactory. The reason is that Spring creates scripted objects via a ScriptFactory implementation — in this case a Groovy factory — combined with a ScriptFactoryPostProcessor bean, which is responsible for replacing the factory beans with the actual object created by the factory. Listing 9 shows the additional configuration that adds the postprocessor bean:


    Listing 9. Defining the ScriptFactoryPostProcessor bean

    <bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>
    

    When Spring loads the application context, it first creates the factory beans (for example, the GroovyScriptFactory beans). Then the ScriptFactoryPostProcessor bean goes through and replaces all the factory beans with the actual scripted objects. For example, the configuration shown in Listing 6 and Listing 9 results in a bean named pdfGenerator whose type is groovierspring.GroovyPdfGenerator. (If you turn on debug-level logging in Spring and watch the application context start up, you'll see that Spring first creates a factory bean named scriptFactory.pdfGenerator, and later the ScriptFactoryPostProcessor creates the pdfGenerator bean from that factory bean.)

    Now that you know the low-level details involved in configuring scripted Groovy beans using GroovyScriptFactory and ScriptFactoryPostProcessor, I'll show you a much simpler and cleaner way to accomplish the same result. Spring provides the lang XML schema specifically for creating scripted beans. Listing 10 defines the pdfGenerator bean using the lang schema:


    Listing 10. Defining a scripted bean using <lang:groovy>

    <lang:groovy id="pdfGenerator"
                 script-source="classpath:groovierspring/GroovyPdfGenerator.groovy">
        <lang:property name="companyName" value="Really Groovy Bookstore"/>
    </lang:groovy>
    

    This code results in the same pdfGenerator bean as the more verbose configuration in Listing 6 and Listing 9 but is cleaner and more concise, and it makes the intent more clear. The <lang:groovy> bean definition requires the script-source attribute; this tells Spring how to locate the Groovy script source code. In addition, you can use the <lang:property> element to set properties for scripted beans. Defining Groovy-based beans using <lang:groovy> is a better option and more clear to anyone reading your Spring configuration.

    Configuring inline Groovy scripts

    For the sake of completeness, I'll mention that Spring also supports writing Groovy scripts directly in your bean definitions. Listing 11 creates the pdfGenerator bean using an inline script:


    Listing 11. Defining a scripted bean inline

    <lang:groovy id="pdfGenerator">
        <lang:inline-script>
            <![CDATA[
            class GroovyPdfGenerator implements PdfGenerator {
                ...
            }
            ]]>
        </lang:inline-script>
        <lang:property name="companyName" value="Icky Groovy Bookstore"/>
    </lang:groovy>
    

    This snippet defines the pdfGenerator bean using <lang:groovy> and the <lang:inline-script> tag, which contains the Groovy script defining the class. You can set properties as before using <lang:property>. As you might have guessed, I don't recommend defining scripted beans inside XML configuration files (or any type of code inside XML files for that matter).

    Configuring beans using the Grails Bean Builder

    The Grails Web framework relies on Spring under the covers. Grails provides the Bean Builder, a cool feature that gives you a way to define Spring beans programmatically using Groovy code (see Resources). Defining beans programmatically potentially provides more flexibility than XML configuration because you can embed logic in the bean-definition script, which is impossible to do in XML. Using Bean Builder, you can create bean definitions for both compiled Groovy classes and scripted Groovy beans. Listing 12 defines the pdfGenerator bean using a compiled Groovy class:


    Listing 12. Using Bean Builder to define compiled Groovy bean

    def builder = new grails.spring.BeanBuilder()
    builder.beans {
        pdfGenerator(GroovyPdfGenerator) {
            companyName = 'Compiled BeanBuilder Bookstore'
        }
    }
    def appContext = builder.createApplicationContext()
    def generator = context.pdfGenerator
    

    The code in Listing 12 first instantiates a BeanBuilder and then makes method calls to create the beans. Each method call and optional closure argument defines a bean and sets bean properties. For example, pdfGenerator(GroovyPdfGenerator) defines a bean named pdfGenerator of type GroovyPdfGenerator, and the code inside the closure sets the companyName property. You can of course define multiple beans inside the beans closure.

    Using Bean Builder, you can also create beans from Groovy scripts, as opposed to compiled Groovy classes. However, Bean Builder has no equivalent to the syntactic sugar you saw with the <lang:groovy> configuration, so you need to define the beans as GroovyScriptFactory and also create a ScriptFactoryPostProcessor bean. Listing 13 shows an example of using Bean Builder to configure a scripted Groovy bean:


    Listing 13. Using Bean Builder to define scripted Groovy bean

    def builder = new grails.spring.BeanBuilder()
    builder.beans {
        pdfGenerator(GroovyScriptFactory,
                    'classpath:groovierspring/GroovyPdfGenerator.groovy') {
            companyName = 'Scripted BeanBuilder Bookstore'
        }
        scriptFactoryPostProcessor(ScriptFactoryPostProcessor)
    }
    def appContext = builder.createApplicationContext()
    def generator = context.pdfGenerator
    

    The code in Listing 13 is logically equivalent to the XML configuration in Listing 6 and Listing 9, though of course Listing 13 uses Groovy code to define the beans. To define the pdfGenerator bean, Listing 13 specifies the type as GroovyScriptFactory. The second argument specifies the location of the script source and, as before, sets the companyName property inside the closure. It also defines a bean named scriptFactoryPostProcessor of type ScriptFactoryPostProcessor, which will replace the factory beans with the actual scripted objects.

    Which configuration option is best?

    You've now seen several different ways to configure Groovy-based beans, whether they are compiled or scripted. If you are simply using Groovy to replace the Java language as the primary language in your application, then configuring the beans is no different from configuring Java-based beans. You can use either XML or annotation-based configuration for compiled Groovy classes.

    For scripted Groovy objects, even though you can configure them in several ways, the <lang:groovy> option is the cleanest way to configure them and makes the intent most clear, as opposed to configuration using GroovyScriptFactory and ScriptFactoryPostProcessor or using <lang:inline-script>.

    You also saw the Grails Bean Builder, which is a completely different way to create a Spring application context from what most Spring applications use. If you want to create all your beans in Groovy and be able to add logic into the bean-building process, the Bean Builder might fit the bill nicely. On the other hand, defining Groovy beans using Bean Builder requires you to define the beans using GroovyScriptFactory and ScriptFactoryPostProcessor.


    Using Groovy beans

    Bean configuration and the various options available to you is the hard part of integrating Groovy and Spring (though as you've seen it isn't really very difficult). Actually using Groovy beans in your Spring application is easy. In fact, Spring's dynamic-language support makes using the beans completely transparent to application code, which neither knows nor cares about the implementation details. You write application code as you normally do in a Spring application, and you can take advantage of all the features Spring normally provides such as dependency injection, AOP, and integration with many third-party frameworks.

    Listing 14 shows a simple Groovy script that creates a Spring application context from an XML configuration file, retrieves the PDF generator bean, and uses it to generate a PDF version of an invoice:


    Listing 14. Using Groovy beans in a script

    def context = new ClassPathXmlApplicationContext("applicationContext.xml")
    def generator = context.getBean("pdfGenerator")
    
    Invoice invoice = new Invoice(orderNumber: "12345", orderDate: new Date())
    invoice.lineItems = [
        new LineItem(quantity: 1, description: 'Groovy in Action (ebook)', price: 22.00),
        new LineItem(quantity: 1, description: 'Programming Erlang', price: 45.00),
        new LineItem(quantity: 2, description: 'iText in Action (ebook)', price: 22.00)
    ]
    
    byte[] invoicePdf = generator.pdfFor(invoice)
    
    FileOutputStream file = new FileOutputStream("Invoice-${invoice.orderNumber}.pdf")
    file.withStream {
        file.write(invoicePdf)
    }
    println "Generated invoice $invoice.orderNumber"
    

    In Listing 14, most of the code is related to creating the Spring ApplicationContext, creating the invoice, and writing it out to a file. Using the pdfGenerator bean to generate the invoice is only one line of code. In typical Spring applications, you bootstrap the application context once, at application startup, and from that point on your components simply use the dependencies that Spring provided them. In Spring Web applications, you can configure a servlet context listener, and Spring is bootstrapped when the application starts. As an example, a PDF invoice-generation service might be defined as shown in Listing 15:


    Listing 15. Service class that uses a PDF generator

    @Service
    public class InvoicePdfServiceImpl implements InvoicePdfService {
    
        @Autowired
        private PdfGenerator pdfGenerator;
    
        public byte[] generatePdf(Long invoiceId) {
            Invoice invoice = getInvoiceSomehow(invoiceId);
            return pdfGenerator.pdfFor(invoice);
        }
    
        // Rest of implementation...
    
    }
    

    The InvoicePdfServiceImpl class in Listing 15 happens to be implemented as a Java class that depends on a PdfGenerator. It could just as easily been implemented as a Groovy bean. You can use the GroovyPdfGenerator implementation with any of the compiled or scripted bean configurations, and InvoicePdfServiceImpl is none the wiser. So, you can see that using Groovy (or any dynamic language) beans is transparent to application code. This is a good thing because it results in loose coupling between components, makes unit testing much easier, and allows you to use the most appropriate implementation language for the job.

    this two-article series, you saw how to make Spring applications more flexible using Groovy beans. Spring's Groovy support allows you to use compiled or scripted Groovy language beans and to configure them in several different ways including the lang XML schema and the Grails Bean Builder. When you integrate Groovy scripts into your application, you can include additional logic in the bean-creation process (for example, to determine which implementation strategy to use when creating a bean). You can also use separate scripted Groovy beans to provide additional deployment and packaging flexibility.

    Probably the most interesting and powerful feature of Spring's dynamic-language support is the ability to monitor and detect changes to dynamic-language scripts while your application is running and automatically reload the changed beans in the Spring application context. The potential use cases for automatically refreshing Spring beans in a running application are vast. A few examples include:

    • PDF generation (bills, invoices, sales reports, investment reports, receipts, schedules, and so on)
    • E-mail templates
    • Report generation
    • Externalized business logic, domain-specific languages (DSLs), and rules engines
    • System administrative tasks
    • Changing logging levels and run-time debugging

    I'm sure you can think of even more potential uses. This article shows you how to add bean refresh to your Spring applications and explores how it works. The complete source code (see Download) for all of the article's examples is available for download.

    Refreshable Groovy beans

    In Part 1, you defined the PdfGenerator interface and implemented it as a Groovy class (GroovyPdfGenerator) in the GroovyPdfGenerator.groovy script file located in the application CLASSPATH. You configured the Groovy-based pdfGenerator bean by specifying the location where the Groovy script is located. Listing 1 shows the interface, implementation, and configuration using the lang XML schema:


    Listing 1. PdfGenerator interface, implementation, and configuration
    // PdfGenerator.java
    public interface PdfGenerator {
        byte[] pdfFor(Invoice invoice);
    }
    
    // GroovyPdfGenerator.groovy
    class GroovyPdfGenerator implements PdfGenerator {
    
        String companyName
    
        public byte[] pdfFor(Invoice invoice) {
            ...
        }
    
    }
    
    // applicationContext.xml
    <lang:groovy id="pdfGenerator"
                 script-source="classpath:groovierspring/GroovyPdfGenerator.groovy">
        <lang:property name="companyName" value="Groovy Bookstore"/>
    </lang:groovy>
    

    So far, so good. You have a bean named pdfGenerator implemented in Groovy that resides in the application CLASSPATH. When the Spring application context is created, Spring reads the script, compiles it into a Java class, and instantiates a GroovyPdfGenerator in the application context. Any other classes that depend on pdfGenerator can simply declare it as a dependency, and Spring wires them together as usual.

    How Spring detects script changes

    Under the covers, Spring uses a Spring AOP (see Resources) RefreshableScriptTargetSource to intercept calls to the target object (the pdfGenerator bean), perform the reload check, and obtain a newer version of a bean. Basically, beans that depend on refreshable beans have a reference to an AOP proxy rather than to the beans themselves.

    Here is where things get really interesting. Suppose you make frequent changes to the PDF-generation code, and you'd like it if you could make changes while your application is running and have them take effect immediately. Spring makes adding this capability trivial. All you need to do is add the refresh-check-delay attribute to the <lang:groovy> element that defines your bean. This attribute defines the number of milliseconds after which Spring checks for changes to the underlying Groovy script. If a change to the script is detected (for example, the timestamp on the .groovy script has changed since last check), then Spring reads the script, compiles it, and replaces the old pdfGenerator bean with the new one. It does this without any of the beans that use pdfGenerator knowing anything about the change.

    Listing 2 shows the pdfGenerator bean configured with a refresh-check delay of 10 seconds (10,000 milliseconds). After adding refresh-check-delay, Spring configures the bean for automatic refresh when the underlying GroovyPdfGenerator.groovy script file changes.


    Listing 2. Adding refresh-check-delay to scripted bean definition
    <lang:groovy id="pdfGenerator"
                 script-source="classpath:groovierspring/GroovyPdfGenerator.groovy"
                 refresh-check-delay="10000">
        <lang:property name="companyName" value="Refreshable Groovy Bookstore"/>
    </lang:groovy>
    

    Now, if a change is made to the GroovyPdfGenerator.groovy script while the application is running, Spring detects the change and reloads the pdfGenerator bean at run time without requiring a restart. Note that the refresh check occurs only after the delay period has elapsed and a method is called on the refreshable bean. For example, suppose the refresh-check delay is 10 seconds for the pdfGenerator bean, but no method is invoked on the bean for 50 seconds. In that situation, Spring checks whether a refresh is required after 50 seconds, not every 10 seconds. To state it another way, Spring is not actively polling the script for changes; instead, it determines the time elapsed since the last method invocation and then calculates whether that time exceeds the refresh check delay. Only if the elapsed time exceeds the refresh-check delay does Spring check if the script has changed and thereby determine whether a refresh is needed. On the other hand, suppose the pdfGenerator bean is under heavy load and its methods are being invoked multiple times per second. With a 10-second refresh-check-delay, the bean can't be reloaded any faster than once every 10 seconds, regardless of the number of times it is used. So you don't need to worry about whether Spring is expending system resources actively polling Groovy scripts; it isn't.

    If you have more than one scripted Groovy bean in your Spring application and you want to set a default value for the refresh-check delay for all of them, you can easily do that using the <lang:defaults> element, as shown in Listing 3:


    Listing 3. Setting a default refresh-check delay
    <lang:defaults refresh-check-delay="20000"/>
    

    Using <lang:defaults> as shown in Listing 3, all scripted dynamic language beans (those written in Groovy, JRuby, BeanShell, and so on) have a 20-second refresh-check delay. You can override the default for individual beans simply by adding a refresh-check-delay attribute to each bean that should have a different value from the default. You can even turn the automatic refresh behavior for individual scripted beans off by setting refresh-check-delay to a negative value, as shown in Listing 4:


    Listing 4. Overriding the default refresh-check delay
    <lang:defaults refresh-check-delay="20000"/>
    
    <lang:groovy id="pdfGenerator"
                 script-source="classpath:groovierspring/GroovyPdfGenerator.groovy"
                 refresh-check-delay="60000">
        <lang:property name="companyName" value="Refreshable Groovy Bookstore"/>
    </lang:groovy>
    
    <lang:groovy id="invoiceEmailer"
                 script-source="classpath:groovierspring/GroovyInvoiceEmailer.groovy"
                 refresh-check-delay="-1"/>
    

    In Listing 4, you can see that the default refresh check delay is 20 seconds. However, I've configured the pdfGenerator bean refresh-check delay as 60 seconds and turned off the refresh check entirely on the invoiceEmailer bean.

    Configuring refreshable Groovy beans using the Grails Bean Builder

    In Part 1, you saw how the Grails Bean Builder (see Resources) can be used to define Spring beans programmatically. If you are using the Bean Builder, you can add automatic refresh to your beans relatively easily — though in this case more of Spring's internals are exposed because Bean Builder has no equivalent to the <lang:groovy> syntactic sugar. Listing 5 shows how to add a default refresh check to all scripted beans and how to set a refresh delay on an individual bean:


    Listing 5. Configuring refreshable Groovy beans using the Grails Bean Builder
    def builder = new grails.spring.BeanBuilder()
    builder.beans {
        scriptFactoryPostProcessor(ScriptFactoryPostProcessor) {
            defaultRefreshCheckDelay = 20000
        }
        pdfGenerator(GroovyScriptFactory,
                     'classpath:groovierspring/GroovyPdfGenerator.groovy') { bean ->
            companyName = 'Refreshable Bean Builder Bookstore'
            bean.beanDefinition.setAttribute(
                ScriptFactoryPostProcessor.REFRESH_CHECK_DELAY_ATTRIBUTE, 60000)
        }
    }
    

    The Bean Builder configuration in Listing 5 is logically equivalent to the configuration of the pdfGenerator bean in Listing 4. You set a default refresh-check delay on all scripted beans using the defaultRefreshCheckDelay property of the ScriptFactoryPostProcessor bean. To set a refresh-check delay on an individual bean when using Bean Builder, you must set an attribute on the underlying Spring bean definition. When you use the <lang:groovy> XML-based configuration, Spring takes care of the underlying details for you, whereas with Bean Builder you need to get your hands dirty and do it yourself. Note that you also need to declare a bean argument to the closure on the pdfGenerator bean in order to set the attribute on the bean definition.


    Customizing Groovy beans

    You've now seen how to make Groovy beans automatically update at run time using the refreshable beans feature and make your applications much more dynamic at run time. Spring's Groovy support provides an additional way to make Groovy beans even more flexible: customization. Customization is a way to inject custom logic into the Groovy bean-creation process. The GroovyObjectCustomizer interface (shown in Listing 6) allows you to perform custom logic on a newly created GroovyObject:


    Listing 6. GroovyObjectCustomizer interface
    public interface GroovyObjectCustomizer {
        void customize(GroovyObject goo);
    }
    

    A GroovyObjectCustomizer is a callback that Spring invokes after creating a Groovy bean. You can apply additional logic to a Groovy bean or perform metaprogramming magic, such as replacing the object's metaclass (see Resources). Listing 7 shows an implementation that writes how long it took to execute a method on a Groovy bean:


    Listing 7. Performance logging GroovyObjectCustomizer
    public class PerformanceLoggingCustomizer implements GroovyObjectCustomizer {
    
        public void customize(GroovyObject goo) {
            DelegatingMetaClass metaClass = new DelegatingMetaClass(goo.getMetaClass()) {
                @Override
                public Object invokeMethod(Object object, String method, Object[] args) {
                    long start = System.currentTimeMillis();
                    Object result = super.invokeMethod(object, method, args);
                    long elapsed = System.currentTimeMillis() - start;
                    System.out.printf("%s took %d millis on %s\n", method, elapsed, object);
                    return result;
                }
            };
            metaClass.initialize();
            goo.setMetaClass(metaClass);
        }
    }
    

    The PerformanceLoggingCustomizer in Listing 7 replaces the GroovyObject's metaclass and overrides invokeMethod in order to add the performance-timing logic. Next you need to configure your customizer so it gets applied to one or more Groovy beans. Listing 8 shows use of the customizer-ref attribute in <lang:groovy> to add a customizer to an existing Groovy bean:


    Listing 8. Configuring a Groovy object customizer
    <bean id="performanceLoggingCustomizer"
          class="groovierspring.PerformanceLoggingCustomizer"/>
    
    <lang:groovy id="pdfGenerator"
        refresh-check-delay="60000"
        script-source="classpath:groovierspring/GroovyPdfGenerator.groovy"
        customizer-ref="performanceLoggingCustomizer">
        <lang:property name="companyName" value="Customized Groovy Bookstore"/>
    </lang:groovy>
    

    Now when any method in the GroovyPdfGenerator is invoked, you'll see output like the following on standard output. (If you're thinking it would have been better to use a logging framework, you're probably right!)

    pdfFor took 18 millis on groovierspring.GroovyPdfGenerator@f491a6

    Adding customization to Groovy beans is pretty simple; the hard part is implementing the actual customization logic — that is, what you want to do to Groovy beans when they are created. You saw configuration using <lang:groovy> and its customizer-ref attribute. If you prefer using the Grails Bean Builder to build your Spring beans, it is simple to do. Listing 9 shows how to add the peformanceLoggingCustomizer bean:


    Listing 9. Adding a Groovy object customizer using the Grails Bean Builder
    builder.beans {
        performanceLoggingCustomizer(PerformanceLoggingCustomizer)
        scriptFactoryPostProcessor(ScriptFactoryPostProcessor) {
            defaultRefreshCheckDelay = 20000
        }
        pdfGenerator(GroovyScriptFactory,
                     'classpath:groovierspring/GroovyPdfGenerator.groovy',
                     performanceLoggingCustomizer) { bean ->
            companyName = 'Refreshable Bean Builder Bookstore'
            bean.beanDefinition.setAttribute(
                ScriptFactoryPostProcessor.REFRESH_CHECK_DELAY_ATTRIBUTE, 60000)
        }
    }
    


    Groovier databases

    Out of the JAR, Spring provides support for inline scripts and scripts loaded via the Spring Resource abstraction (see Resources). You saw inline scripts and Resource-based scripts — specifically CLASSPATH resources — in Part 1. You've just added more dynamic behavior using refreshable beans. Spring's ability to load, compile, and refresh dynamic language beans rests on the ScriptSource interface, shown in Listing 10 (Javadocs omitted):


    Listing 10. ScriptSource interface
    public interface ScriptSource {
    
        String getScriptAsString() throws IOException;
    
        boolean isModified();
    
        String suggestedClassName();
    }
    

    ScriptSource defines three methods: one to obtain the script source code, one to determine if the script has been modified, and one that returns a suggested class name for the script. Spring provides two implementations of this interface: StaticScriptSource and ResourceScriptSource. You use StaticScriptSource when defining scripts in your Spring configuration file. ResourceScriptSource is used to load scripts from any Resource (for example, from scripts located in files, on the CLASSPATH, or from URLs).

    Toward a pluggable script-source locator

    When I first implemented the capability to store Groovy scripts in a database, I thought perhaps this mechanism should be pluggable so that users can plug in different ScriptSource implementations and script-locator strategies. I consulted Keith Donald of SpringSource about this, and he agreed and asked me to submit a new feature request to Spring. As a result, in a future version of Spring (currently scheduled for 3.1RC1), the script-source locator mechanism will become pluggable (see Resources).

    Static and Resource-based scripts provide a wide range of places to define scripts, but you might want to use a database as the script location, for several good reasons. For example, many organizations do not allow file-system access to production machines, or they might require deployment as a WAR or EAR file. In addition, databases are transactional resources that most organizations already use and are familiar with. Databases also provide one relatively easy means to centralize data access and security without needing to know specifics about file systems, servers, and so on. Finally, storing scripts in a database means you could update the scripts from an application by allowing users to edit the scripts. (Of course, when you store active code in a database, it is important to consider the potential security implications and secure your application appropriately.)

    Suppose you want to store your Groovy scripts in a relational database. As of Spring 2.5, you can create new types of scripts, but you must create your own ScriptSource and extend some of the Spring classes. Specifically, you need to define your own ScriptSource implementation and modify Spring's ScriptFactoryPostProcessor so it knows how to work with your new type of ScriptSource.

    Listing 11 implements a DatabaseScriptSource that uses Spring JDBC to load scripts from a relational database:


    Listing 11. DatabaseScriptSource implementation
    public class DatabaseScriptSource implements ScriptSource {
    
        private final String scriptName;
        private final JdbcTemplate jdbcTemplate;
        private Timestamp lastKnownUpdate;
    
        private final Object lastModifiedMonitor = new Object();
    
        public DatabaseScriptSource(String scriptName, DataSource dataSource) {
            this.scriptName = scriptName;
            this.jdbcTemplate = new JdbcTemplate(dataSource);
        }
    
        public String getScriptAsString() throws IOException {
            synchronized (this.lastModifiedMonitor) {
                this.lastKnownUpdate = retrieveLastModifiedTime();
            }
            return (String) jdbcTemplate.queryForObject(
                    "select script_source from groovy_scripts where script_name = ?",
                    new Object[]{ this.scriptName }, String.class);
        }
    
        public boolean isModified() {
            synchronized (this.lastModifiedMonitor) {
                Timestamp lastUpdated = retrieveLastModifiedTime();
                return lastUpdated.after(this.lastKnownUpdate);
            }
        }
    
        public String suggestedClassName() {
            return StringUtils.stripFilenameExtension(this.scriptName);
        }
    
        private Timestamp retrieveLastModifiedTime() {
            return (Timestamp) this.jdbcTemplate.queryForObject(
                    "select last_updated from groovy_scripts where script_name = ?",
                    new Object[]{ this.scriptName }, Timestamp.class);
        }
    }
    

    DatabaseScriptSource in Listing 11 is fairly straightforward, though you could make it more generic in terms of the database table structure it expects. It assumes a table named groovy_scripts having columns script_name, script_source, and last_updated. It supports loading scripts from the groovy_scripts table and checking for modifications.

    Now, you need to teach Spring to recognize the DatabaseScriptSource. To do this, you must extend ScriptFactoryPostProcessor and override the convertToScriptSource method, which is responsible for converting a script-source locator (for example, classpath:groovierspring/GroovyPdfGenerator.groovy) into a ScriptSource. The default implementation in ScriptFactoryPostProcessor is shown in Listing 12:


    Listing 12. ScriptFactoryPostProcessor's convertToScriptSource method
    protected ScriptSource convertToScriptSource(
            String beanName, String scriptSourceLocator, ResourceLoader resourceLoader) {
    
        if (scriptSourceLocator.startsWith(INLINE_SCRIPT_PREFIX)) {
            return new StaticScriptSource(
                    scriptSourceLocator.substring(INLINE_SCRIPT_PREFIX.length()), beanName);
        }
        else {
            return new ResourceScriptSource(resourceLoader.getResource(scriptSourceLocator));
        }
    }
    

    As you can see, the default implementation handles only inline and resource-based scripts. You can create a new subclass of ScriptFactoryPostProcessor and override convertToScriptSource to load scripts from your database also, using the DatabaseScriptSource, as shown in Listing 13:


    Listing 13. CustomScriptFactoryPostProcessor implementation
    public class CustomScriptFactoryPostProcessor extends ScriptFactoryPostProcessor {
    
        public static final String DATABASE_SCRIPT_PREFIX = "database:";
    
        private DataSource dataSource;
    
        @Required
        public void setDataSource(DataSource dataSource) {
            this.dataSource = dataSource;
        }
    
        @Override
        protected ScriptSource convertToScriptSource(String beanName,
                                                     String scriptSourceLocator,
                                                     ResourceLoader resourceLoader) {
            if (scriptSourceLocator.startsWith(INLINE_SCRIPT_PREFIX)) {
                return new StaticScriptSource(
                    scriptSourceLocator.substring(INLINE_SCRIPT_PREFIX.length()), beanName);
            }
            else if (scriptSourceLocator.startsWith(DATABASE_SCRIPT_PREFIX)) {
                return new DatabaseScriptSource(
                    scriptSourceLocator.substring(DATABASE_SCRIPT_PREFIX.length()),
                    dataSource);
            }
            else {
                return new ResourceScriptSource(
                    resourceLoader.getResource(scriptSourceLocator));
            }
        }
    
    }
    

    The CustomScriptFactoryPostProcessor in this listing is similar to ScriptFactoryPostProcessor, except that it adds the ability to use a database-based script if the script source locator starts with database: (for example, database:groovierspring/GroovyPdfGenerator.groovy). Ideally, this mechanism would be more flexible (see the Toward a pluggable script source locator sidebar). But for now you have what you need to store Groovy scripts in your database.

    The only task remaining is to configure the pdfGenerator bean to be read from your database. You first need to define a scriptFactoryPostProcessor bean using the CustomScriptFactoryPostProcessor shown in Listing 13. Then you define the pdfGenerator bean using the database script-source locator. You could define the pdfGenerator bean using either plain <bean/> syntax or the more clear <lang:groovy> syntax. When you use <lang:groovy>, Spring checks to see if a ScriptFactoryPostProcessor bean is in the application context named scriptFactoryPostProcessor and creates one automatically if one does not already exist. If a scriptFactoryPostProcessor is already defined, Spring uses that bean, which is how you can substitute your own custom implementation. Listing 14 shows the new configuration:


    Listing 14. Database pdfGenerator bean configuration
    <jee:jndi-lookup id="dataSource" jndi-name="jdbc/GroovierSpringDataSource"/>
    
    <bean id="scriptFactoryPostProcessor"
          class="groovierspring.CustomScriptFactoryPostProcessor">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
    <lang:groovy id="pdfGenerator"
                 refresh-check-delay="60000"
                 script-source="database:groovierspring/GroovyPdfGenerator.groovy">
        <lang:property name="companyName" value="Database Groovy Bookstore"/>
    </lang:groovy>
    

    The code in Listing 14 is not much more complicated than anything you've seen so far. The scriptFactoryPostProcessor bean requires that a DataSource be injected, so you also define the dataSource bean. Otherwise, the only difference is the change from a CLASSPATH-based script to one that resides in a database. If you're more inclined to use the Grails Bean Builder, you can easily use it to configure the data source and the custom ScriptFactoryPostProcessor bean.

    At this point, you can load Groovy scripts from your database and also refresh them after making changes to the scripts in the database, making Spring's already flexible Groovy support even more flexible and dynamic. You've also seen how you can add your own ScriptSource implementation to allow scripts to be loaded from wherever you choose.


    When Groovy scripts go bad

    Everyone probably agrees you should thoroughly test your applications, though people may disagree on exactly how to go about it. For example, is 100 percent code coverage necessary, or possible, or simply a waste of time? Regardless of your personal view, testing becomes that much more important when you suddenly have the ability to deploy changes into a running production system and have those changes take effect immediately, as you can do with Spring's dynamic-language support.

    If you decide to use the refreshable beans feature, then you need a solid strategy to ensure that new code works properly and as expected. How to do this effectively depends on your situation:

    • How critical is the system?
    • If you break something, what is the impact?
    • How quickly can you fix problems that arise?

    Your specific situation probably involves additional considerations, but the bottom line is that the bean-refresh feature is both powerful and potentially dangerous. You need to use it responsibly. The two main types of problems you can encounter are script-compilation errors and run-time errors.

    Script-compilation errors

    Suppose you change a script at run time such that it will not compile. When Spring detects the change and tries to reload the bean, a ScriptCompilationException is thrown wrapping the original exception, such as a Groovy MultipleCompilationErrorsException. When this occurs, Spring cancels the attempt to reload the bean, and the original bean keeps on chugging as if nothing had happened. Your application needs to respond to ScriptCompilationExceptions appropriately. Mostly likely, you should display some kind of error message and send a notification (such as an e-mail message or instant message) to developers or operations staff. Of course, whoever is deploying the changes to the script should monitor the application to make sure the script compiles successfully and that the new bean replaces the old bean.

    All is not lost, however, because scripts that don't compile have no effect on already deployed beans. So, you can fix the problem that caused the compilation exception and try again. Assuming the bean compiles successfully, Spring replaces the existing bean with the new one transparently to application code. Your changes are now in place without requiring redeployment or restarting your application.

    Run-time script errors

    Run-time script errors have the same problems as run-time errors thrown by compiled code: they cause a failure condition in your application that most likely will propagate up to users and cause whatever action they try to perform to fail. For example, suppose you make a change to the GroovyPdfGenerator such that it compiles but throws a run-time exception whenever it tries to generate a PDF. In that case, the code using the pdfGenerator either must handle the exception or propagate it, and most likely the user will receive an error message stating that a PDF could not be generated (and that it will be fixed as soon as possible!)

    But as with script-compilation errors, all is not lost when run-time script errors occur. In fact, because scripts can be changed at run time, they can be fixed more easily than compiled code. You fix whatever problem exists in your script, and once the script is reloaded, the problem is no more. So from a certain perspective, the ability to change code at run time gives you not only more flexibility to make changes, but also more flexibility when errors strike. This doesn't mean you should make all beans in your Spring applications refreshable, though. Like many things, refreshable beans are probably best used in moderation.


    Script security

    One last, but certainly not least, consideration is security. It's important to secure your scripts and ensure that only authorized users or administrators can modify them. In some ways, this is no different from how you secure any other part of your application. For example, most applications need to ensure data integrity and restrict users' access to functionality that's specific to their roles or privileges. But on the other hand, this capability potentially opens up new attack vectors for hackers to intrude into your system and change not only data but also system behavior. You certainly want to reduce your application's attack surface and must weigh pros and cons as with all design trade-offs.

    What makes security perhaps more important is the fact that with Spring's dynamic-language support, you can change not just system data, but behavior as well. This is to some extent true anyway: think about an SQL injection attack that injects malicious code, or JavaScript cross-site scripting, or cross-site request forgery attacks that can change or replace your system's behavior. My point is that you need to think about how to ensure proper controls on your Groovy scripts, especially if they are refreshable.

    Depending on how you use refreshable beans, the additional security risk may be outweighed by the advantages of changing behavior at run time. Imagine a customer-facing sales application that needs frequent rule changes for offering discounts to customers, or perhaps an insurance application whose business rules can change frequently. In such cases, you could design a DSL written in Groovy that salespeople or insurance agents could change to suit the current business need. Maybe you want to add a bit of logic to offer a 10 percent discount on purchases over $50. It is certainly possible to accommodate this type of change by allowing users to edit small bits of a DSL directly in a running application. Or maybe you design a graphical editor they can use to change the discount policy.

     

    You've now seen how to integrate Groovy into Spring-based applications using either compiled Groovy classes or scripts that are dynamically compiled and loaded. You also know how to make scripted Groovy beans refreshable, how to customize Groovy beans at creation time, and even how to store them in a relational database. You've learned how script-compilation and run-time errors affect running applications in different ways, and how refreshable beans can make fixing bugs at run time easier than using traditional architectures that require redeployment or an application restart. Finally, I briefly touched on security implications of scripted and refreshable beans, noting that you need to assess thoroughly the type of level of security required for your applications.

    Together, Spring and Groovy make a powerful combination: Spring provides architecture and infrastructure, while Groovy adds dynamic capabilities. Spring's ability to reload Groovy scripts when they change can take your applications into uncharted territory. Remember though: "With great power comes great responsibility." Adding a much more dynamic nature to your applications is sure to make them more flexible and powerful, but it also brings up issues and challenges that you might not have had to deal with before.

    discuss this topic to forum

    relation tutorial

    No information

    Category

      Applet Building (6)
      Application Building (8)
      Communication (1)
      Database Related (10)
      Development (13)
      EJB (14)
      Game Programming (5)
      General Java (63)
      Javabeans (4)
      JSP and Servlets (9)
      Miscellaneous (28)
      Networking (1)
      Security (2)
      Swing (13)
      WAP and WML (2)
      XML and Java (4)

    New

    Hot