under the hood: using spring in grails

80
© 2010 SpringSource, A division of VMware. All rights reserved CONFIDENTIAL CONFIDENTIAL Under the Hood: Using Spring in Grails Burt Beckwith SpringSource

Upload: burt-beckwith

Post on 08-Sep-2014

4.603 views

Category:

Sports


2 download

DESCRIPTION

Talk on using Spring in Grails given at SpringOne 2GX and the Groovy & Grails Exchange in 2012

TRANSCRIPT

Page 1: Under the Hood: Using Spring in Grails

© 2010 SpringSource, A division of VMware. All rights reserved

CONFIDENTIALCONFIDENTIAL

Under the Hood: Using Spring in Grails

Burt Beckwith

SpringSource

Page 2: Under the Hood: Using Spring in Grails

2CONFIDENTIAL 2CONFIDENTIAL

Who Am I

Java developer for over 13 years

Background in Spring, Hibernate, Spring Security

Grails developer for 5 years

SpringSource employee on the Grails team

Created or reworked over 40 Grails plugins

http://burtbeckwith.com/blog/

https://twitter.com/#!/burtbeckwith

Page 3: Under the Hood: Using Spring in Grails

3CONFIDENTIAL 3CONFIDENTIAL

Spring Overview

Main functions of Spring

• Bean container: ApplicationContext and BeanFactory

• Dependency Injection (DI) and Inversion of Control (IoC)

• Proxies

• Transactions

• Security

• Caching

• Event publishing and listening

• Exception conversion

Page 4: Under the Hood: Using Spring in Grails

4CONFIDENTIAL 4CONFIDENTIAL

Grails Services

Page 5: Under the Hood: Using Spring in Grails

5CONFIDENTIAL 5CONFIDENTIAL

Grails Services

What is a Grails Service?

Page 6: Under the Hood: Using Spring in Grails

6CONFIDENTIAL 6CONFIDENTIAL

Grails Services

What is a Grails Service?

•Groovy class in grails­app/services

Page 7: Under the Hood: Using Spring in Grails

7CONFIDENTIAL 7CONFIDENTIAL

Grails Services

What is a Grails Service?

•Groovy class in grails­app/services

•Great place for business logic

Page 8: Under the Hood: Using Spring in Grails

8CONFIDENTIAL 8CONFIDENTIAL

Grails Services

What is a Grails Service?

•Groovy class in grails­app/services

•Great place for business logic

•A Spring bean, by default singleton scope

Page 9: Under the Hood: Using Spring in Grails

9CONFIDENTIAL 9CONFIDENTIAL

Grails Services

What is a Grails Service?

•Groovy class in grails­app/services

•Great place for business logic

•A Spring bean, by default singleton scope

•Automatically transactional unless configured otherwise

Page 10: Under the Hood: Using Spring in Grails

10CONFIDENTIAL 10CONFIDENTIAL

Grails Services

What is a Grails Service?

•Groovy class in grails­app/services

•Great place for business logic

•A Spring bean, by default singleton scope

•Automatically transactional unless configured otherwise

•Proxied, sometimes multiple times

Page 11: Under the Hood: Using Spring in Grails

11CONFIDENTIAL 11CONFIDENTIAL

Manually Wiring

Page 12: Under the Hood: Using Spring in Grails

12CONFIDENTIAL 12CONFIDENTIAL

Grails Services

package test;

import other.LoggingService;import auth.User;

public class UserManager {

private LoggingService loggingService;

public void setLoggingService(LoggingService service) { loggingService = service; }

public User createUser(String username) { User user = new User(); user.setUsername(username); user.save(); loggingService.logMessage( "Created user with username " + username); return user; }}

src/java/test/UserManager.java

Page 13: Under the Hood: Using Spring in Grails

13CONFIDENTIAL 13CONFIDENTIAL

Grails Services

import test.UserManager

beans = { userService(UserManager) { loggingService = ref('loggingService') }}

grails-app/conf/spring/resources.groovy

Page 14: Under the Hood: Using Spring in Grails

14CONFIDENTIAL 14CONFIDENTIAL

Grails Services

import test.UserManager

beans = { userService(UserManager) { bean -> bean.autowire = 'byName' }}

grails-app/conf/spring/resources.groovy

Page 15: Under the Hood: Using Spring in Grails

15CONFIDENTIAL 15CONFIDENTIAL

How to Make it Transactional?

Page 16: Under the Hood: Using Spring in Grails

16CONFIDENTIAL 16CONFIDENTIAL

Grails Services

import org.codehaus.groovy.grails.orm.support.GroovyAwareNamedTransactionAttributeSourceimport org.springframework.transaction.interceptor.TransactionProxyFactoryBean

import test.UserManager

beans = {

userService(TransactionProxyFactoryBean) { bean -> bean.lazyInit = true

target = { innerBean -> innerBean.lazyInit = true innerBean.autowire = 'byName' innerBean.beanClass = UserManager }

proxyTargetClass = true

def props = ['*': 'PROPAGATION_REQUIRED'] as Properties TransactionAttributeSource = new GroovyAwareNamedTransactionAttributeSource(transactionalAttributes: props)

transactionManager = ref('transactionManager') }}

grails-app/conf/spring/resources.groovy

Page 17: Under the Hood: Using Spring in Grails

17CONFIDENTIAL 17CONFIDENTIAL

or

Page 18: Under the Hood: Using Spring in Grails

18CONFIDENTIAL 18CONFIDENTIAL

Grails Services

package test;

import org.springframework.transaction.annotation.Transactional;import other.LoggingService;import auth.User;

@Transactionalpublic class UserManager {

private LoggingService loggingService;

public void setLoggingService(LoggingService service) { loggingService = service; }

public User createUser(String username) { ... }}

src/java/test/UserManager.java

Page 19: Under the Hood: Using Spring in Grails

19CONFIDENTIAL 19CONFIDENTIAL

Grails Services

import test.UserManager

beans = {

userService(UserManager) { bean -> bean.lazyInit = true bean.autowire = 'byName' }}

grails-app/conf/spring/resources.groovy

Page 20: Under the Hood: Using Spring in Grails

20CONFIDENTIAL 20CONFIDENTIAL

How to be sure it's Transactional?

Page 21: Under the Hood: Using Spring in Grails

21CONFIDENTIAL 21CONFIDENTIAL

Grails Services

package test;

import org.springframework.transaction.TransactionStatus;import org.springframework.transaction.annotation.Transactional;import org.springframework.transaction.interceptor.TransactionAspectSupport;import org.springframework.transaction.support.TransactionSynchronizationManager;

...

public User createUser(String username) {

if (TransactionSynchronizationManager.isSynchronizationActive()) { TransactionStatus status = TransactionAspectSupport.currentTransactionStatus(); System.out.println("TX is active; isRollbackOnly: " + status.isRollbackOnly()); } else { System.out.println("Uh-oh, TX not active"); }

... }}

src/java/test/UserManager.java

Page 22: Under the Hood: Using Spring in Grails

22CONFIDENTIAL 22CONFIDENTIAL

Grails Services

package test

import auth.User

class UserService {

def loggingService

User createUser(String username) { def user = new User(username: username) user.save() loggingService.logMessage( "Created user with username $username") user }}

grails-app/services/test/UserService.groovy

Page 23: Under the Hood: Using Spring in Grails

23CONFIDENTIAL 23CONFIDENTIAL

Transaction Helper Methods

Page 24: Under the Hood: Using Spring in Grails

24CONFIDENTIAL 24CONFIDENTIAL

Utility Methods

import o.s.t.interceptor.TransactionAspectSupportimport o.s.t.support.TransactionSynchronizationManager

for (sc in grailsApplication.serviceClasses) {   def metaClass = sc.clazz.metaClass

   …}

Page 25: Under the Hood: Using Spring in Grails

25CONFIDENTIAL 25CONFIDENTIAL

Utility Methods

// returns TransactionStatusmetaClass.getCurrentTransactionStatus = { ­>

if (!delegate.isTransactionActive()) {return null

}TransactionAspectSupport.currentTransactionStatus()

}

Page 26: Under the Hood: Using Spring in Grails

26CONFIDENTIAL 26CONFIDENTIAL

Utility Methods

// void, throws NoTransactionExceptionmetaClass.setRollbackOnly = { ­>

TransactionAspectSupport.currentTransactionStatus()         .setRollbackOnly()}

Page 27: Under the Hood: Using Spring in Grails

27CONFIDENTIAL 27CONFIDENTIAL

Utility Methods

// returns booleanmetaClass.isRollbackOnly = { ­>

if (!delegate.isTransactionActive()) {return false

}delegate.getCurrentTransactionStatus().isRollbackOnly()

}

Page 28: Under the Hood: Using Spring in Grails

28CONFIDENTIAL 28CONFIDENTIAL

Utility Methods

// returns booleanmetaClass.isTransactionActive = { ­>

TransactionSynchronizationManager         .isSynchronizationActive()}

Page 29: Under the Hood: Using Spring in Grails

29CONFIDENTIAL 29CONFIDENTIAL

Dependency Injection

Page 30: Under the Hood: Using Spring in Grails

30CONFIDENTIAL 30CONFIDENTIAL

Inversion of Control and Dependency Injection

def userService

Page 31: Under the Hood: Using Spring in Grails

31CONFIDENTIAL 31CONFIDENTIAL

Inversion of Control and Dependency Injection

def userService

private Object userService

void setUserService(Object userService) {   this.userService = userService}

Object getUserService() {   return userService}

Page 32: Under the Hood: Using Spring in Grails

32CONFIDENTIAL 32CONFIDENTIAL

Complex dependency configuration using Spring 

SpEL

Page 33: Under the Hood: Using Spring in Grails

33CONFIDENTIAL 33CONFIDENTIAL

Complex dependency configuration using Spring SpEL

beans = {   bar(Bar)

   foo(Foo) {      name = '#{bar.name}'   }}

Page 34: Under the Hood: Using Spring in Grails

34CONFIDENTIAL 34CONFIDENTIAL

Complex dependency configuration using Spring SpEL

beans = {   bar(Bar)

   foo(Foo) {      name = '#{bar.resourceName()}'   }}

Page 35: Under the Hood: Using Spring in Grails

35CONFIDENTIAL 35CONFIDENTIAL

Manually injecting dependencies at runtime

Page 36: Under the Hood: Using Spring in Grails

36CONFIDENTIAL 36CONFIDENTIAL

Manually injecting dependencies at runtime

import org.springframework.beans.factory.config.AutowireCapableBeanFactory

...

def grailsApplication

...

def instance = new XXX(...)

def ctx = grailsApplication.mainContextctx.beanFactory.autowireBeanProperties(   instance,   AutowireCapableBeanFactory.AUTOWIRE_BY_NAME,   false)

Page 37: Under the Hood: Using Spring in Grails

37CONFIDENTIAL 37CONFIDENTIAL

Bean Scopes

Page 38: Under the Hood: Using Spring in Grails

38CONFIDENTIAL 38CONFIDENTIAL

Bean Scopes

By default Spring beans are singletons

Page 39: Under the Hood: Using Spring in Grails

39CONFIDENTIAL 39CONFIDENTIAL

Bean Scopes

Other scopes

• prototype

• session

• request

Page 40: Under the Hood: Using Spring in Grails

40CONFIDENTIAL 40CONFIDENTIAL

Bean Scopes

You can even create your own custom scope:

• implement 

org.springframework.beans.factory.config.Scope

• register: ctx.beanFactory.registerScope 

'myScope', new MyScope()

Page 41: Under the Hood: Using Spring in Grails

41CONFIDENTIAL 41CONFIDENTIAL

Bean lifecycles and interfaces

Page 42: Under the Hood: Using Spring in Grails

42CONFIDENTIAL 42CONFIDENTIAL

Bean lifecycles and interfaces

Set the initMethod and/or the destroyMethod names 

when registering beans

import com.mycompany.myapp.LdapAuthenticationManager

...

authenticationManager(LdapAuthenticationManager) { bean ­>   serverUrl = '...'   password = '...'   bean.initMethod = 'init'   bean.destroyMethod = 'destroy'}

Page 43: Under the Hood: Using Spring in Grails

43CONFIDENTIAL 43CONFIDENTIAL

Bean lifecycles and interfaces

Implement the

org.springframework.beans.factory.InitializingBean

interface and its afterPropertiesSet method and/or the

org.springframework.beans.factory.DisposableBean

interface and its destroy method

Page 44: Under the Hood: Using Spring in Grails

44CONFIDENTIAL 44CONFIDENTIAL

Bean lifecycles and interfaces

package com.mycompany.myapp

import org.springframework.beans.factory.DisposableBeanimport org.springframework.beans.factory.InitializingBean

class LdapAuthenticationManager implements InitializingBean, DisposableBean {

   ...

   void afterPropertiesSet() {      // initialization work   }

   void destroy() {      // shutdown work   }}

Page 45: Under the Hood: Using Spring in Grails

45CONFIDENTIAL 45CONFIDENTIAL

Bean PostProcessors

Page 46: Under the Hood: Using Spring in Grails

46CONFIDENTIAL 46CONFIDENTIAL

Bean PostProcessors

o.s.b.factory.config.BeanPostProcessor

• Object postProcessBeforeInitialization(Object bean, 

String beanName)

• Object postProcessAfterInitialization(Object bean, 

String beanName)

Page 47: Under the Hood: Using Spring in Grails

47CONFIDENTIAL 47CONFIDENTIAL

Bean PostProcessors

o.s.b.factory.config.BeanFactoryPostProcessor

• void postProcessBeanFactory(ConfigurableListableBeanFactory 

beanFactory)

Page 48: Under the Hood: Using Spring in Grails

48CONFIDENTIAL 48CONFIDENTIAL

Bean PostProcessors

o.s.b.factory.support.BeanDefinitionRegistryPostProcessor

• extends BeanFactoryPostProcessor

• void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry 

registry)

Page 49: Under the Hood: Using Spring in Grails

49CONFIDENTIAL 49CONFIDENTIAL

Cloud Support Plugin (cloud­foundry, heroku)

dataSourceBean.driverClassName = updatedValues.driverClassName

dataSourceBean.url = updatedValues.url + suffix

dataSourceBean.username = updatedValues.userName

dataSourceBean.password = updatedValues.password

Page 50: Under the Hood: Using Spring in Grails

50CONFIDENTIAL 50CONFIDENTIAL

Alternate approach to BeanDefinition modification

def doWithSpring = {

   def mybeanDef = delegate.getBeanDefinition('mybean')

   mybeanDef.beanClass = NewClass

   mybeanDef.propertyValues.add("order",         application.config.plugin?.rendering?.order ?: 42)}

● Use loadAfter = ['plugin1', 'plugin2'] to

ensure the bean is loaded

● Only valid in a plugin, not the app's resources.groovy

Page 51: Under the Hood: Using Spring in Grails

51CONFIDENTIAL 51CONFIDENTIAL

Bean Aliases

Page 52: Under the Hood: Using Spring in Grails

52CONFIDENTIAL 52CONFIDENTIAL

Aliases

As of Grails 2.1 aliases work fully

• You can create aliases pre­2.1 but only if defined in the same 

resources.groovy or plugin (doWithSpring)

beans = {   springConfig.addAlias 'alias', 'realBean'}

Page 53: Under the Hood: Using Spring in Grails

53CONFIDENTIAL 53CONFIDENTIAL

Aliases

The cache plugin registers the alias cacheOperationSource for 

the bean registered as 

org.springframework.cache.annotation.AnnotationCacheOperationSource#0

Can use to have multiple implementations of a bean and choose 

one via configuration at startup, e.g. per­environment or some 

other rule

Page 54: Under the Hood: Using Spring in Grails

54CONFIDENTIAL 54CONFIDENTIAL

Aliases

import grails.util.Environment

beans = {

   String realBeanName

   switch (Environment.current) {

      case Environment.TEST:         realBeanName = 'testCardProcessingService'; break

      case Environment.PRODUCTION:         realBeanName = 'productionCardProcessingService'; break

      default: // Environment.DEVELOPMENT, custom envs         realBeanName = 'mockCardProcessingService'; break   }

   springConfig.addAlias 'cardProcessingService', realBeanName}

Page 55: Under the Hood: Using Spring in Grails

55CONFIDENTIAL 55CONFIDENTIAL

Internationalization

Page 56: Under the Hood: Using Spring in Grails

56CONFIDENTIAL 56CONFIDENTIAL

Internationalization

First­class support in Grails via .properties files in grails­app/i18n

All generated controllers, GSPs, and layouts are fully 

internationalized with no hard­coded strings

Domain class validation errors are internationalized the same way

Enabled under the hood by the messageSource bean 

(org.springframework.context.MessageSource)

Page 57: Under the Hood: Using Spring in Grails

57CONFIDENTIAL 57CONFIDENTIAL

Internationalization

Use the <g:message> tag in GSPs, message method in 

controllers

Or use dependency injection like with any Spring bean

• def messageSource

Page 58: Under the Hood: Using Spring in Grails

58CONFIDENTIAL 58CONFIDENTIAL

Spring MVC Controllers

Page 59: Under the Hood: Using Spring in Grails

59CONFIDENTIAL 59CONFIDENTIAL

Spring MVC

New in Grails 1.2

Annotate src/java or src/groovy classes with @Controller

Add all packages to the grails.spring.bean.packages list in

Config.groovy

• e.g.grails.spring.bean.packages = ['gr8conf.testapp.foo']

Page 60: Under the Hood: Using Spring in Grails

60CONFIDENTIAL 60CONFIDENTIAL

Spring MVC

Annotate methods with

@o.s.w.bind.annotation.RequestMapping

@RequestMapping("/mvc/hello.dispatch")public ModelMap handleRequest() {   return new ModelMap()      .addAttribute("text", "some text")      .addAttribute("cost", 42)      .addAttribute("config",          grailsApplication.getConfig().flatten()));}

Page 61: Under the Hood: Using Spring in Grails

61CONFIDENTIAL 61CONFIDENTIAL

Spring MVC

class UrlMappings {

   static mappings = {      …

      "/mvc/hello"(uri:"/mvc/hello.dispatch")

      "/mvc/other"(uri:"/mvc/other.dispatch")   }}

@RequestMapping URI value must end in .dispatch

Add entries in UrlMappings to create more natural URLs

Page 62: Under the Hood: Using Spring in Grails

62CONFIDENTIAL 62CONFIDENTIAL

Spring MVC

Use @Autowired for dependency injection (on fields in Groovy 

classes, on setters or constructors in Java)

private GrailsApplication grailsApplication;

@Autowiredpublic void setGrailsApplication(GrailsApplication app) {   grailsApplication = app;}

Page 63: Under the Hood: Using Spring in Grails

63CONFIDENTIAL 63CONFIDENTIAL

Hibernate Integration

Page 64: Under the Hood: Using Spring in Grails

64CONFIDENTIAL 64CONFIDENTIAL

Hibernate Integration

org.springframework.orm.hibernate3. 

LocalSessionFactoryBean factory bean configures 

org.hibernate.SessionFactory instances

Page 65: Under the Hood: Using Spring in Grails

65CONFIDENTIAL 65CONFIDENTIAL

Hibernate Integration

org.springframework.orm.hibernate3. 

HibernateTransactionManager implements 

org.springframework.transaction. 

PlatformTransactionManager to abstract away the details of 

transaction management

Page 66: Under the Hood: Using Spring in Grails

66CONFIDENTIAL 66CONFIDENTIAL

Thread­local holders

Cumbersome to explicitly open a Hibernate Session or start a

transaction and have to pass one or more related objects from

method to method

Page 67: Under the Hood: Using Spring in Grails

67CONFIDENTIAL 67CONFIDENTIAL

Thread­local holders

Spring uses ThreadLocal scope since web requests are handled

per-thread

Page 68: Under the Hood: Using Spring in Grails

68CONFIDENTIAL 68CONFIDENTIAL

Thread­local holders

See org.springframework.transaction.support. 

TransactionSynchronizationManager and

org.springframework.orm.hibernate3. 

SessionFactoryUtils helper classes

Page 69: Under the Hood: Using Spring in Grails

69CONFIDENTIAL 69CONFIDENTIAL

Thread­local holders

Further helped by

org.codehaus.groovy.grails.orm.hibernate.support. 

GrailsOpenSessionInViewInterceptor

Page 70: Under the Hood: Using Spring in Grails

70CONFIDENTIAL 70CONFIDENTIAL

Thread­local holders

Opens a Hibernate Session at the start of all controller requests

and registers it in thread-local scope

For the duration of the request, there is always an active session

After the request it flushes and closes the Session

Page 71: Under the Hood: Using Spring in Grails

71CONFIDENTIAL 71CONFIDENTIAL

Thread­local holders

Hibernate implementation of GORM uses a

org.springframework.orm.hibernate3. 

HibernateTemplate under the hood to execute most queries

Page 72: Under the Hood: Using Spring in Grails

72CONFIDENTIAL 72CONFIDENTIAL

Thread­local holders

HibernateTemplate uses SessionFactoryUtils.getSession() to

find or create a Session

Page 73: Under the Hood: Using Spring in Grails

73CONFIDENTIAL 73CONFIDENTIAL

Thread­local holders

Plugins that enable asynchronous processing (Quartz, Gpars,

Executor) all implement patterns similar to OpenSessionInView

Page 74: Under the Hood: Using Spring in Grails

74CONFIDENTIAL 74CONFIDENTIAL

Other Cool Stuff

Page 75: Under the Hood: Using Spring in Grails

75CONFIDENTIAL 75CONFIDENTIAL

Other Cool Stuff

Standard and Custom Events

Resources

Data Binding and Validation

Marshalling XML using O/X Mappers

JMS (see Grails jms and ActiveMQ plugins)

EJBs

Page 76: Under the Hood: Using Spring in Grails

76CONFIDENTIAL 76CONFIDENTIAL

Other Cool Stuff

Remoting (see the Grails remoting plugin)

• Remote Method Invocation (RMI)

• Hessian (Caucho's lightweight binary HTTP­based protocol)

• Burlap (another protocol from Caucho which uses XML)

• Spring's HTTP invoker

JMX (see the Grails jmx plugin)

Email (see the Grails mail plugin)

Page 77: Under the Hood: Using Spring in Grails

77CONFIDENTIAL 77CONFIDENTIAL

Other Cool Stuff

Other persistence support

• HibernateTemplate

• JdbcTemplate

• Other database support

• JDO

• JPA

• iBATIS (2.x) SQL Maps

Page 78: Under the Hood: Using Spring in Grails

78CONFIDENTIAL 78CONFIDENTIAL

Want More Information?

Page 79: Under the Hood: Using Spring in Grails
Page 80: Under the Hood: Using Spring in Grails

80CONFIDENTIAL 80CONFIDENTIAL

Thank You