2. 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
CONFIDENTIAL 2
3. 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
CONFIDENTIAL 3
9. Grails Services
What is a Grails Service?
• Groovy class in grailsapp/services
• Great place for business logic
• A Spring bean, by default singleton scope
• Automatically transactional unless configured otherwise
CONFIDENTIAL 9
10. Grails Services
What is a Grails Service?
• Groovy class in grailsapp/services
• Great place for business logic
• A Spring bean, by default singleton scope
• Automatically transactional unless configured otherwise
• Proxied, sometimes multiple times
CONFIDENTIAL 10
21. Grails Services
src/java/test/UserManager.java
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");
}
...
}
}
CONFIDENTIAL 21
22. Grails Services
grails-app/services/test/UserService.groovy
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
}
}
CONFIDENTIAL 22
43. 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
CONFIDENTIAL 43
50. 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
CONFIDENTIAL 50
52. Aliases
As of Grails 2.1 aliases work fully
• You can create aliases pre2.1 but only if defined in the same
resources.groovy or plugin (doWithSpring)
beans = {
springConfig.addAlias 'alias', 'realBean'
}
CONFIDENTIAL 52
59. 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']
CONFIDENTIAL 59
60. 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()));
}
CONFIDENTIAL 60
62. Spring MVC
Use @Autowired for dependency injection (on fields in Groovy
classes, on setters or constructors in Java)
private GrailsApplication grailsApplication;
@Autowired
public void setGrailsApplication(GrailsApplication app) {
grailsApplication = app;
}
CONFIDENTIAL 62
66. Threadlocal 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
CONFIDENTIAL 66
70. Threadlocal 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
CONFIDENTIAL 70
73. Threadlocal holders
Plugins that enable asynchronous processing (Quartz, Gpars,
Executor) all implement patterns similar to OpenSessionInView
CONFIDENTIAL 73