Under the Hood:
Using Spring in Grails
    Burt Beckwith
     SpringSource
Who Am I




  CONFIDENTIAL   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               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                     4
Bean PostProcessors




        CONFIDENTIAL   5
Bean PostProcessors


 o.s.b.factory.config.BeanPostProcessor
 • Object postProcessBeforeInitialization(Object bean, 

  String beanName)

 • Object postProcessAfterInitialization(Object bean, 

  String beanName)




                           CONFIDENTIAL                   6
Bean PostProcessors


 o.s.b.factory.config.BeanFactoryPostProcessor
 • void postProcessBeanFactory(ConfigurableListableBeanFactory 

  beanFactory)




                            CONFIDENTIAL                      7
Bean PostProcessors


 o.s.b.factory.support.BeanDefinitionRegistryPostProcessor
 • extends BeanFactoryPostProcessor

 • void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry 

  registry)




                                 CONFIDENTIAL                       8
Cloud Support Plugin (cloud­foundry, heroku)




   dataSourceBean.driverClassName = 
   updatedValues.driverClassName

   dataSourceBean.url = updatedValues.url + suffix

   dataSourceBean.username = updatedValues.userName

   dataSourceBean.password = updatedValues.password




                             CONFIDENTIAL             9
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                    10
Bean Aliases




   CONFIDENTIAL   11
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'
   }




                              CONFIDENTIAL                       12
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




                                 CONFIDENTIAL                            13
Spring MVC Controllers




         CONFIDENTIAL    14
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                        15
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                    16
Spring MVC


 @RequestMapping URI value must end in .dispatch
 Add entries in UrlMappings to create more natural URLs

   class UrlMappings {

      static mappings = {
         …

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

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



                              CONFIDENTIAL                 17
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                     18
Transactions




   CONFIDENTIAL   19
Utility Methods




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

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

     …
  }




                           CONFIDENTIAL                    20
Utility Methods




  // returns TransactionStatus
  metaClass.getCurrentTransactionStatus = { ­>
     if (!delegate.isTransactionActive()) {
         return null
     }
     TransactionAspectSupport.currentTransactionStatus()
  }




                           CONFIDENTIAL                    21
Utility Methods




  // void, throws NoTransactionException
  metaClass.setRollbackOnly = { ­>
     TransactionAspectSupport.currentTransactionStatus()
           .setRollbackOnly()
  }




                           CONFIDENTIAL                    22
Utility Methods




  // returns boolean
  metaClass.isRollbackOnly = { ­>
     if (!delegate.isTransactionActive()) {
         return false
     }
     delegate.getCurrentTransactionStatus().isRollbackOnly()
  }




                           CONFIDENTIAL                        23
Utility Methods




  // returns boolean
  metaClass.isTransactionActive = { ­>
     TransactionSynchronizationManager
           .isSynchronizationActive()
  }




                           CONFIDENTIAL   24
Proxies




 CONFIDENTIAL   25
A Simple Proxied Bean – The interface



     package gr8conf.eu.spring;

     public interface ThingManager {

         void method1();

         int methodTwo(boolean foo);
     }




                             CONFIDENTIAL   26
A Simple Proxied Bean – The implementation



     package gr8conf.eu.spring;

     public class ThingManagerImpl
            implements ThingManager {

         public void method1() {
            System.out.println("You called method1");
         }

         public int methodTwo(boolean foo) {
            System.out.println("You called methodTwo");
            return 42;
         }
     }




                            CONFIDENTIAL                  27
A Simple Proxied Bean – The FactoryBean

     package gr8conf.eu.spring;

     public class ThingManagerProxyFactoryBean
            implements FactoryBean<ThingManager>,
                       InitializingBean {

        private ThingManager managerProxy;
        private ThingManager target;

        public ThingManager getObject() {
           return managerProxy;
        }

        public Class<ThingManager> getObjectType() {
           return ThingManager.class;
        }

        public boolean isSingleton() {
           return true;
        }
                            CONFIDENTIAL               28
A Simple Proxied Bean – The FactoryBean

     public void setTarget(ThingManager manager) {
        target = manager;
     }

     public void afterPropertiesSet() {

        Assert.notNull(target,
            "The proxied manager must be set");

        Class<?>[] interfaces = { ThingManager.class };

        InvocationHandler invocationHandler =
           new InvocationHandler() {
              public Object invoke(Object proxy,
                 Method m, Object[] args)
                    throws Throwable {




                            CONFIDENTIAL                  29
A Simple Proxied Bean – The FactoryBean

              System.out.println("Before invoke " +
                                 m.getName());

              Object value = m.invoke(target, args);

              System.out.println("After invoke " +
                                 m.getName());

              return value;
           }
        };

        managerProxy = (ThingManager)Proxy.newProxyInstance(
           ThingManager.class.getClassLoader(),
           interfaces,
           invocationHandler);
        }
     }



                              CONFIDENTIAL                     30
A Simple Proxied Bean – resources.groovy

     import gr8conf.eu.spring.ThingManager
     import gr8conf.eu.spring.ThingManagerImpl
     import gr8conf.eu.spring.ThingManagerProxyFactoryBean

     beans = {

        realThingManager(ThingManagerImpl) {
           // properties, etc.
        }

        thingManager(ThingManagerProxyFactoryBean) { bean ­>
           // bean.scope = ...
           // bean.lazyInit = true
           // target = ref('realThingManager')
        }
     }




                            CONFIDENTIAL                       31
A Simple Proxied Bean – resources.groovy

     import gr8conf.eu.spring.ThingManager
     import gr8conf.eu.spring.ThingManagerImpl
     import gr8conf.eu.spring.ThingManagerProxyFactoryBean

     beans = {

        thingManager(ThingManagerProxyFactoryBean) { bean ­>
           // bean.scope = ...
           // bean.lazyInit = true

           target = { ThingManagerImpl thing ­>
              // properties, etc.
           }
        }
     }




                            CONFIDENTIAL                       32
Want More Information?




         CONFIDENTIAL    33
Thank You




  CONFIDENTIAL   35

Under the Hood: Using Spring in Grails