ssm基础整合_整合基础

Spring 2.0引入了将动态语言集成到基于Spring的应用程序中的支持。 Spring开箱即用,支持Groovy,JRuby和BeanShell。 用Groovy,JRuby或任何其他支持的语言(当然包括Java™语言)编写的应用程序部分将无缝集成到Spring应用程序中。 您应用程序的其余代码无需了解或关心单个Spring bean的实现语言。

Spring对动态语言的支持意味着您的应用程序无需附加任何字符串即可获得灵活性和动态行为。 你也可以吃蛋糕。 在本系列的第1部分中,您将看到如何一起使用Spring和Groovy,以及这种强大的组合如何为您的应用程序添加有趣的功能。 例如,您可能需要经常更改一小部分业务逻辑,更改应用程序发出的电子邮件中包含的文本或更改应用程序生成的PDF的格式和布局。 传统的应用程序体系结构可能需要彻底重新部署应用程序,以进行此类更改。 Spring对Groovy的支持使您可以对已部署的应用程序进行此类更改,并使它们立即生效。 我将讨论此功能可以为您的应用程序带来的好处以及可能出现的问题。 可以下载本文所有示例的完整源代码( 请参阅下载 )。

Spring的动态语言支持

动态语言支持已将Spring从以Java为中心的应用程序框架更改为以JVM为中心的应用程序框架。 现在,Spring不仅使Java开发更加容易。 通过允许用静态和动态语言编写的代码轻松插入Spring支持和促进的分层体系结构方法,这也使JVM的开发更加容易。 如果您已经熟悉Spring,那么您会感到宾至如归:您可以利用Spring已经提供的所有功能-控制反转(IoC)和依赖项注入,面向方面的编程(AOP),声明式事务划分,Web和数据访问框架集成,远程处理等,同时使用诸如Groovy之类的灵活,动态语言。

Spring通过ScriptFactoryScriptSource接口支持动态语言集成。 ScriptFactory接口定义用于配置和创建脚本化Spring Bean的机制。 从理论上讲,可以支持在JVM上运行的任何语言,并且您可以为自己选择的特定语言创建自己的实现。 ScriptSource定义Spring如何访问实际的脚本源代码。 例如,通过文件系统或URL。 Groovy语言集成通过GroovyScriptFactory实现来ScriptFactory

为什么选择Groovy?

根据Groovy官方网站的说法,Groovy是“一种用于Java虚拟机的敏捷和动态语言”,“基于Java的优势,但具有受Python,Ruby和Smalltalk等语言启发的其他强大功能”,例如动态类型,闭包和元编程支持(参见相关主题 )。 它是一种成熟的面向对象的编程语言,可以按原样使用,也可以将其纯粹用作脚本语言。 我喜欢将其视为Java语言减去我不喜欢编写的所有代码,再加上动态语言中的闭包和其他功能。

Groovy是与Spring的动态语言支持一起使用的一个特别引人注目的选择,因为它是专门为JVM设计的,并且考虑到Java的紧密集成,从而使Groovy和Java代码易于互操作。 Java开发人员喜欢使用类似Java的语法。

现在该看看如何将Groovy代码集成到基于Spring的应用程序中了。

GroovierSpring Bean

在Spring应用程序中使用Groovy bean与使用Java bean一样容易。 (但是,如何配置它们还有更多选择,如您将在后面看到的。)首先,您需要定义一个接口以用作Groovy bean遵循的协定。 尽管并不是必须要定义一个接口,但是大多数Spring应用程序都是通过接口而不是具体的实现类来定义应用程序组件之间的交互和依赖关系,以促进松散的耦合和更容易的测试。

举例来说,假设您有一个接口定义了如何从Invoice对象生成PDF,如清单1所示:

清单1. PdfGenerator接口
public interface PdfGenerator {
    byte[] pdfFor(Invoice invoice);
}

PdfGenerator接口充当Groovy实现类的协定。 Groovy类可以以与Java类相同的方式实现接口,因此这非常容易。 清单2只显示了Groovy实现的PdfGenerator使用iText库(参见相关主题 )来完成实际的PDF生成; 它返回一个包含PDF内容的字节数组:

清单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现在准备采取行动。 它定义了一个名为companyName的字符串属性,该属性与订单号和总数一起在生成的PDF发票上使用。 至此,您已经准备好将GroovyPdfGenerator集成到Spring应用程序中。 必须将使用Java语言编写的Bean编译为.class文件,但是在使用基于Groovy的Bean时,您有几种选择:

  • Groovy类编译成普通的Java类文件
  • .groovy文件中定义的Groovy类或脚本
  • 在Spring配置文件中内联编写的Groovy脚本

根据用于Groovy Bean的这些选项中的哪一个,可以在Spring应用程序上下文中定义和配置Groovy Bean的几种方法中进行选择。 接下来,我将探讨每个配置选项。

Groovy bean配置

通常,您可以使用XML或使用注解来配置用Java代码编写的Spring Bean(从Spring 2.5开始(请参阅参考资料 )),从而大大减少了XML配置。 配置Groovy Bean时,可用选项取决于您使用的是编译的Groovy类还是.groovy文件中定义的Groovy类。 要记住的主要点是,您可以使用Groovy实现bean并像通常在Java编程中那样编译它们,或者可以将它们作为.groovy文件中的类或脚本来实现,并让Spring在创建bean时负责对其进行编译。应用程序上下文。

如果选择在.groovy文件中实现bean,则不要自己编译它们。 相反,Spring读取文件以获得脚本源代码,在运行时对其进行编译,并使其在应用程序上下文中可用。 与直接编译相比,这提供了更大的灵活性,因为.groovy文件不一定需要部署在应用程序的JAR或WAR文件中,而是可以来自文件系统中的某个位置,也可以来自URL。

现在,您将了解正在使用的各种配置选项。 请记住,您在自己的构建过程中编译的Groovy类中定义的bean与.groovy脚本中定义的bean之间的区别。

配置编译的Groovy类

配置已经编译到.class文件中的Groovy bean与配置基于Java的bean完全相同。 假设您已经使用GroovyPdfGenerator groovyc器编译了GroovyPdfGenerator ,则可以使用常规的Spring XML配置定义bean,如清单3所示:

清单3.使用XML配置预编译的GroovyPdfGenerator
<bean id="pdfGenerator" class="groovierspring.GroovyPdfGenerator">
    <property name="companyName" value="Groovy Bookstore"/>
</bean>

清单3中的配置是一个简单的旧Spring bean定义。 它在Groovy中实现的事实并不重要。 Spring应用程序中包含pdfGenerator bean的任何其他组件都可以使用它,而无需了解或关心其实现细节或语言。 您还可以像平常一样通过使用<property>元素在bean上设置属性。 (Spring 2.0引入了p名称空间,这是一种更简洁的定义属性的方式,但是我坚持使用<property>元素,因为我发现它们更具可读性-严格来说是优先考虑的问题。)

另外,如果您使用的是Spring 2.5或更高版本,则可以使用GroovyPdfGenerator的基于注释的配置。 在那种情况下,您实际上并没有在XML应用程序上下文中定义Bean;而是在Bean中定义了。 而是使用@Component型注释对@Component注释,如清单4所示:

清单4.用@Component注释GroovyPdfGenerator
@Component("pdfGenerator")
class GroovyPdfGenerator implements PdfGenerator {
    ...
}

然后在Spring应用程序上下文XML配置中启用注释配置和组件扫描,如清单5所示:

清单5.启用Spring注释配置和组件扫描
<context:annotation-config/>
<context:component-scan base-package="groovierspring"/>

无论您是使用XML还是使用注释来配置已编译的Groovy Bean,请记住该配置与配置普通的基于Java的Bean相同。

从Groovy脚本配置bean

从.groovy脚本配置Groovy Bean与配置已编译的Groovy Bean完全不同。 这是事情开始变得更加有趣的地方。 将Groovy脚本转换为Bean的机制包括读取Groovy脚本,对其进行编译,以及使其在Spring应用程序上下文中作为Bean可用。 第一步是定义一个表面上为GroovyScriptFactory的bean,它指向Groovy脚本的位置,如清单6所示:

清单6.定义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>

在此清单中, pdfGenerator bean被定义为GroovyScriptFactory<constructor-arg>元素定义您正在配置的Groovy脚本的位置。 请特别注意,这指向的是Groovy 脚本 ,而不是编译的Groovy类。 您可以使用定义Spring Bean时通常使用的相同语法在脚本对象上设置属性。 清单6中<property>元素按照您的期望设置了companyName属性。

GroovyPdfGenerator.groovy 脚本必须至少包含一个实现您的接口的类。 通常最好遵循标准Java惯例,即为每个.groovy文件定义一个Groovy类。 但是,您可能希望在脚本中实现逻辑以确定要创建的bean类型。 例如,您可以在PdfGenerator定义PdfGenerator接口的两个不同实现,并直接在脚本中执行逻辑以确定应返回这些实现中的哪个。 清单7定义了两种不同的PdfGenerator实现,并根据系统属性选择要使用的一种:

清单7. Groovy脚本中的多个类定义
class SimpleGroovyPdfGenerator implements PdfGenerator {
    ...
}

class ComplexGroovyPdfGenerator implements PdfGenerator {
    ...
}

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

如该代码片段所示,您可以使用脚本化的Bean根据系统属性选择其他实现。 当generatorType系统属性很simple ,脚本将创建并返回SimpleGroovyPdfGenerator ; 否则,它返回ComplexGroovyPdfGenerator 。 因为简单和复杂的实现都实现了PdfGenerator接口,所以从Spring应用程序内部使用pdfGenerator bean进行编码将既不知道也不关心实际的实现。

请注意,您仍然可以在脚本返回的bean上设置属性,如清单6所示 。 因此,如果脚本返回ComplexGroovyPdfGenerator ,则将在该bean上设置companyName属性。 当您不需要定义多个实现的额外灵活性时,可以在Groovy脚本文件中仅定义一个类,如清单8所示。在这种情况下,Spring会找到该类并为您实例化。

清单8.典型的Groovy脚本实现
class GroovyPdfGenerator implements PdfGenerator {
    ...
}

此时,您可能想知道为什么清单6将bean定义为GroovyScriptFactory 。 原因是Spring通过ScriptFactory实现(在本例中为Groovy工厂)与ScriptFactoryPostProcessor bean结合创建了脚本对象,该ScriptFactoryPostProcessor bean负责用工厂创建的实际对象替换工厂bean。 清单9显示了添加后处理器bean的附加配置:

清单9.定义ScriptFactoryPostProcessor bean
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>

当Spring加载应用程序上下文时,它首先创建工厂bean(例如GroovyScriptFactory bean)。 然后, ScriptFactoryPostProcessor bean进行遍历,并用实际的脚本对象替换所有工厂bean。 例如, 清单6清单9中所示的配置将生成一个名为pdfGenerator其类型为groovierspring.GroovyPdfGenerator 。 (如果在Spring中打开调试级别的日志记录,并观察应用程序上下文的启动,您将看到Spring首先创建一个名为scriptFactory.pdfGenerator的工厂bean,然后ScriptFactoryPostProcessor从该工厂bean创建pdfGenerator bean。)

既然您知道了使用GroovyScriptFactoryScriptFactoryPostProcessor配置脚本化Groovy Bean所涉及的低级细节,我将向您展示一种更简单,更简洁的方法来实现相同的结果。 Spring提供了专门用于创建脚本bean的lang XML模式。 清单10使用lang模式定义了pdfGenerator bean:

清单10.使用<lang:groovy>定义脚本化的bean
<lang:groovy id="pdfGenerator"
             script-source="classpath:groovierspring/GroovyPdfGenerator.groovy">
    <lang:property name="companyName" value="Really Groovy Bookstore"/>
</lang:groovy>

这段代码产生的pdfGenerator bean与清单6清单9中更详细的配置相同,但是更加简洁明了,并且使意图更加清晰。 <lang:groovy> bean定义需要script-source属性。 这告诉Spring如何找到Groovy脚本源代码。 另外,您可以使用<lang:property>元素来设置脚本化bean的属性。 使用<lang:groovy>定义基于Groovy的bean是一个更好的选择,并且对于阅读Spring配置的任何人来说都更加清楚。

配置内联Groovy脚本

为了完整起见,我将提到Spring还支持直接在bean定义中编写Groovy脚本。 清单11使用内联脚本创建pdfGenerator bean:

清单11.内联定义脚本化的bean
<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>

此代码段使用<lang:groovy><lang:inline-script>标记定义了pdfGenerator bean,其中包含定义类的Groovy脚本。 您可以使用<lang:property>像以前一样设置属性。 您可能已经猜到了,我不建议在XML配置文件中定义脚本化的bean(或者在XML文件中定义任何类型的代码)。

使用Grails Bean Builder配置Bean

Grails Web框架完全依靠Spring。 Grails提供了Bean Builder,这是一个很酷的功能,它为您提供了一种使用Groovy代码以编程方式定义Spring Bean的方法(请参阅参考资料 )。 以编程方式定义bean可能比XML配置提供更多的灵活性,因为您可以将逻辑嵌入到bean定义脚本中,而这在XML中是不可能做到的。 使用Bean Builder,可以为已编译的Groovy类和脚本化的Groovy Bean创建Bean定义。 清单12使用已编译的Groovy类定义了pdfGenerator bean:

清单12.使用Bean Builder定义编译的Groovy bean
def builder = new grails.spring.BeanBuilder()
builder.beans {
    pdfGenerator(GroovyPdfGenerator) {
        companyName = 'Compiled BeanBuilder Bookstore'
    }
}
def appContext = builder.createApplicationContext()
def generator = context.pdfGenerator

清单12中的代码首先实例化BeanBuilder ,然后进行方法调用以创建bean。 每个方法调用和可选的闭包参数都定义一个bean并设置bean属性。 例如, pdfGenerator(GroovyPdfGenerator)定义了类型为GroovyPdfGenerator名为pdfGenerator的bean,闭包中的代码设置了companyName属性。 您当然可以在beans闭包内定义多个bean。

使用Bean Builder,您还可以从Groovy脚本创建Bean,这与已编译的Groovy类相反。 但是,Bean Builder不具有您在<lang:groovy>配置中看到的语法糖,因此您需要将bean定义为GroovyScriptFactory并创建一个ScriptFactoryPostProcessor bean。 清单13显示了一个使用Bean Builder配置脚本化Groovy Bean的示例:

清单13.使用Bean Builder定义脚本化的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

清单13中的代码在逻辑上等效于清单6清单9中的XML配置,尽管清单13当然使用Groovy代码定义了bean。 为了定义pdfGenerator bean, 清单13将类型指定为GroovyScriptFactory 。 第二个参数指定脚本源的位置,并像以前一样在闭包内部设置companyName属性。 它还定义了一个名为豆scriptFactoryPostProcessorScriptFactoryPostProcessor ,这将与实际脚本对象替换工厂bean。

哪个配置选项最好?

现在,您已经看到了配置基于Groovy的bean的几种不同方法,无论它们是编译的还是脚本编写的。 如果仅使用Groovy替换Java语言作为应用程序中的主要语言,则配置Bean与配置基于Java的Bean并无不同。 您可以将XML或基于注释的配置用于已编译的Groovy类。

对于脚本化的Groovy对象,即使您可以通过多种方式对其进行配置,与使用GroovyScriptFactoryScriptFactoryPostProcessor或使用<lang:inline-script>进行配置相比, <lang:groovy>选项也是最干净的方式来配置它们并使意图最清晰。 <lang:inline-script>

您还看到了Grails Bean Builder,它是与大多数Spring应用程序使用的完全不同的创建Spring应用程序上下文的方式。 如果要在Groovy中创建所有bean并能够在bean的构建过程中添加逻辑,则Bean Builder可能很合适。 另一方面,使用Bean Builder定义Groovy Bean要求您使用GroovyScriptFactoryScriptFactoryPostProcessor定义Bean。

使用Groovy bean

Bean配置和可供您使用的各种选项是集成Groovy和Spring的难点(尽管您已经看到,它并不是很困难)。 实际上,在Spring应用程序中使用Groovy bean很容易。 实际上,Spring的动态语言支持使使用Bean对应用程序代码完全透明,既不知道也不在乎实现细节。 您可以像通常在Spring应用程序中一样编写应用程序代码,并且可以利用Spring通常提供的所有功能,例如依赖项注入,AOP以及与许多第三方框架的集成。

清单14显示了一个简单的Groovy脚本,该脚本从XML配置文件创建Spring应用程序上下文,检索PDF生成器bean,并使用它生成发票的PDF版本:

清单14.在脚本中使用Groovy bean
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"

清单14中 ,大多数代码与创建Spring ApplicationContext ,创建发票并将其写到文件有关。 使用pdfGenerator bean生成发票只是一行代码。 在典型的Spring应用程序中,您可以在应用程序启动时引导一次应用程序上下文,然后从这一点开始在组件上仅使用Spring提供的依赖项即可。 在Spring Web应用程序中,您可以配置Servlet上下文侦听器,并且在应用程序启动时会引导Spring。 例如,可以定义一个PDF发票生成服务,如清单15所示:

清单15.使用PDF生成器的服务类
@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...

}

清单15中的InvoicePdfServiceImpl类恰好实现为依赖于PdfGenerator的Java类。 它可以像Groovy bean一样容易地实现。 您可以将GroovyPdfGenerator实现与任何已编译或脚本化的bean配置一起使用,而InvoicePdfServiceImplInvoicePdfServiceImpl 。 因此,您可以看到使用Groovy(或任何动态语言)bean对应用程序代码是透明的。 这是一件好事,因为它导致组件之间的松散耦合,使单元测试更加容易,并允许您使用最合适的实现语言来完成工作。

第1部分的结论

现在,您已经了解了几种配置Groovy语言Bean的方法,以及在基于Spring的应用程序中使用它们的难易程度。 您可以使用已编译的Groovy类,与使用Java类完全相同。 您还看到了几种不同的方法来配置脚本化Groovy对象。 您应该选择的选项取决于您在应用程序中如何使用Groovy。 您还可以在同一应用程序中组合已编译和脚本化的Groovy bean。 实际上,如果您确实需要,则可以将Java,Groovy,JRuby和BeanShell bean都放在同一应用程序中,尽管我不建议这样做。 作为开发人员,您必须权衡在应用程序中使用多种语言的利弊。

与Java语言相比,Groovy作为语言的灵活性使它成为一个有吸引力的选择,即使您仅选择编译Groovy类也是如此。 Spring集成脚本化动态语言Bean的能力使Groovy成为更具吸引力的选择,因为您可以在脚本化Bean中引入其他逻辑和灵活性。 例如,如前所述,您可以添加逻辑以确定基于业务逻辑在应用程序启动时实例化的bean的类型。 或者,您可以通过将脚本对象部署在应用程序CLASSPATH或文件系统中某个位置但未打包在WAR文件中的.groovy文件中来获得Web应用程序部署的灵活性。

到目前为止,您所看到的所有内容都为Spring工具包增加了灵活性和功能。 但是,Spring动态语言支持中最引人注目的功能可能是能够在应用程序运行时监视和检测对动态语言脚本的更改,并自动在Spring应用程序上下文中重新加载更改的bean。 第2部分将深入探讨该功能,与使用静态配置(包含在运行时无法更改的bean)相比,此功能显着提高了灵活性。


翻译自: https://www.ibm.com/developerworks/java/library/j-groovierspring1/index.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值