Core Spring – continued (2) – SpEL, Annotation based bean defs, Java-based configuration

Spring Expression Language (SpEL) introduced in Spring 3.0 introduces EL style language for referencing beans and properties, and gives a standard syntax for doing property replacement into beans.

Annotation based bean definition

  • component scan allows you to configure annotated beans – simplest approach, avoids xml:

Enabled with context:component-scan in xml file:

<context:component-scan base-package="your.package"/>
  • @Component – declares beans
  • @Autowired – bean of a matching type is automatically injected into contructor, method, or field
  • Only one constructor can be autowired, but multiple methods and attributes can be autowired
  • @Autowired properties don’t need setters
  • @Autowired methods don’t need to be setters, and don’t need to be named ‘set…()’
  • @Qualifier allows you to specify a specific bean id if matching beans by type is ambiguous

‘The spirit of autowiring is by type’ – use of the @Qualifier should be only if necessary, since it restricts the flexibility and power of the Autowiring.

Use of @Autowired implies @Required (don’t need to explicitly defined @Required if @Autowired)

Stereotype annotations

Also enabled via context:component-scan

  • @Service – indicates purpose in layering, but doesn’t add any additional behavior

Following stereotypes do add extra behavior:

  • @Repository – data access
  • @Controller – MVC controller
  • @Configuration – programmatic Spring configuration

Other Spring projects use similar annotation approach for adding additional stereotype based functionality.

JSR 330 CDI Annotation Support

  • Spring is a an implementation of JSR330
  • provides support for JSR330 standard @Named, @Inject, @Scope, @Singleton
  • Spring provides other Spring specific annotations not supported in JSR330 (@Value, @Required, @Lazy)

Bean configuration using Annotations & Java: @Configuration

  • Enabled with context:component-scan
  • @Configuration marks configuration clas
  • Use @Bean on method that provides instance of the bean
  • Method name is the id of the bean, eg participantService() – id = “participantService”
  • Java code can perform any initialization – you can invoke any other methods necessary to perform initialization
  • All @Bean annotated methods produce singletons by default – @Bean methods are proxied to add this behavior – this can be overridden with @Scope(“prototype”)
  • @Import allows to import other @Configuration classes
  • Alternate configuration: AnnotationConfigApplicationContext – instantiating this context allows a completely xml free configuration approach

 

Annotations vs XML based configuration

  • easier to make changes to annotated beans during development
  • could always move to xml config when beans become more mature, but no compelling reason to do this, could always just leave the annotations
  • xml config always overrides the annotation metadata

Spring JUnit Support
Integration testing support allows testing with Spring Bean dependencies

@ContextConfuguration("example-context.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class ExampleTest
{
    @Autowired
    private ExampleService exampleService;

    @Test
    public void eampleTest() { ... }
}

Using Spring with JPA and Hibernate

Spring + Hibernate

  • HibernateTemplate is now obsolete (Spring 3.x +) – create bean for SessionFactory and wire it into Hibernate-based Repository beans
  • Use the Hibernate Session api directly
  • This approach has zero dependency on Spring APIs

How to configure:

Configure beans for your datasource, transaction manager and the SessionFactory:

<jee:jndi-lookup id="myDataSource" jndi-name="java:comp/env/jdbc/myds"/>

<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager" />

<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="myDataSource"/>
    <property name="jtaTransactionManager" ref="txManager"/> 
    <property name="mappingResources">
      <list>
        <value>product.hbm.xml</value>
      </list>
    </property>
    <property name="hibernateProperties">
      <value>
        hibernate.dialect=org.hibernate.dialect.HSQLDialect
      </value>
    </property>
  </bean>

Configuring with xml files is optional if you’re using JPA annotations for your Entities instead.

Repositories using Hibernate follow same ‘new’ pattern as JDBC Template with Spring 3.x, no longer user the HibernateTemplate, inject a Hibernate SessionFactory and use this to get a Session directly. This approach doesn’t have any Spring code dependencies:

@Transactional
@Repository
public class ExampleRespositoryImpl implements ExampleRepository
{
  private SessionFactory sessionFactory;

  public ExampleRespositoryImpl(SessionFactory sessionFactory)
  {
    this.sessionFactory(sessionFactory);
  }

  public Example findExampleById(Long id)
  {
    this.sessionFactory.getCurrentSession().get(Example.class, id);
  }
}

Spring + JPA

How to configure:

Running in an EE container, configure your datasource, transaction manager and EntityManagerFactoryBean:

<jee:jndi-lookup id="dataSource" jndi-name="java:jboss/datasources/MysqlDS"/>

<bean id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>

<jee:jndi-lookup id="entityManagerFactory" jndi-name="persistence/persistenceUnit"/>

If you’re running outside of an EE container, instead of looking up your datasource and container provided EntityManagerFactory, define a LocalEntityMangerFactoryBean, referencing your persistence unit name:

<bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="persistenceUnit"/>
    <property name="dataSource" ref="dataSource"/>
 </bean>

Configure your persistence.xml to reference your datasource and JPA provider (which may also be Hibernate):

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="persistenceUnit" transaction-type="JTA"><!-- for local testing use: RESOURCE_LOCAL -->
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
         <!-- KH: look up DataSource from container -->
         <jta-data-source>java:jboss/datasources/MysqlDS</jta-data-source>

        <properties>
            <!-- KH: ask JBoss to publish the EntityManager so we can reference it in the Spring config -->
            <property name="jboss.entity.manager.factory.jndi.name" value="persistence/persistenceUnit"/>

            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
            <!-- value="create" to build a new database on each run; value="update" to modify an existing database; value="create-drop" means the same as "create" but also drops tables when Hibernate closes; value="validate" makes no changes to the database -->
            <property name="hibernate.hbm2ddl.auto" value="update"/>
            <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/>
            <property name="hibernate.connection.charSet" value="UTF-8"/>

        </properties>
    </persistence-unit>
</persistence>

If you’re running outside of an EE container, make the following changes:

  • transaction-type="RESOURCE_LOCAL"
  • remove the <jta-data-source> element

Write Repositories with @Repository and @Transactional, and use the @PuersistenceUnit annotation to inject the EntityManagerFactory

@Transactional
@Repository
public class ExampleRespositoryImpl implements ExampleRepository
{
  private EntityManagerFactory emf;

    @PersistenceUnit
    public void setEntityManagerFactory(EntityManagerFactory emf) {
        this.emf = emf;
    }

    public Collection loadProductsByCategory(String category) {
        EntityManager em = this.emf.createEntityManager();
        try {
             Query query = em.createQuery("from Product as p where p.category = ?1");
             query.setParameter(1, category);
             return query.getResultList();
        }
        finally {
            if (em != null) {
                em.close();
            }
        }
    }
}

This approach injects the EntityManagerFactory using @PersistenceUnit, from which you can get hold of the EntityManager. The normal approach with JPA would be to inject the EntityManager with @PersistenceContext and use the EntityManager directly.

Spring JDBC & Transaction Support

General

Spring data access uses concept of templates to:

  • provide consistent error handling approach
  • provide consistent api

In the past, your DAOs previously extended base Spring DAO classes – this approach is no longer used/recommended (Spring 3.x +) –  use plain annotated POJOs with @Repository annotation.

New Terminology:

  • Repository == DAO

Recommendations

  • one template instance per Repository – Template code is threadsafe, but shared usage (between DAOs/Repositories) would result in blocking calls and reduced performance
  • instead create Template from a Factory, or better still, configure with scope=”prototype”

Exception Handling (in Spring’s View)

  • Checked Exceptions – force developers to add additional code to handle exceptions, bad from the point of view of tight coupling
  • Unchecked Exceptions – can be passed up hierarchy to suitable place to handle, without unnecessary throws clauses
  • Spring framework always uses Unchecked/Runtime Exceptions

Spring Data Access Base Exception

  • DataAccessException -manly subtypes, for example, DataIntegrityViolationException

JDBC Namespace for xml Config

  • provides shortcut config for creating/defining jdbc data access
  • useful for development and testing, provides embedded database support (eg H2)
  • <jdbc:embedded-database…>
  • <jdbc:initialize-database …> – allows running f sql setup scripts

Verbocity of JDBC api approach together with Checked exceptions is simplified by using JDBCTemplate to handle the plumbing, allow using to focus on just what is important, eg the SQL itself and executing code

JDBC Repositories

  • Implement your business interface
  • Annotate with @Repository
  • Inject DataSource in Repository constructor
  • Constructor creates new JdbcTemplate instance from passed DataSource
@Transactional
@Repository
public class ExampleRespositoryImpl implements ExampleRepository
{
    private JdbcTemplate jdbcTemplate;

    public ExampleRespositoryImpl(DataSource datasource)
    {
        this.jdbcTemplate(new JndiTemplate(datasource));
    }
}

Config shortcuts

    • lookup Datasource using:
<jee:jndi-lookup id="datasource" jndi-name="java:/comp/env/jdbc/name"/>

JdbcTemplate.queryForMap()

  • returns single row with columns as keys in the map

JdbcTemplate.queryForList()

  • returns List of Maps (as above)

Spring Container Transaction Support

Configure PlatformTransactionManger according to container and/or persistence technology being used:

e.g:

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource"/>
</bean>
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/jpetstore"/> 

<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager" />

Other PlatformTransactionMangerImplementations (see here for full list):

  • JtaTransactionManager – if using container provided JTA implementation
  • WebLogicJtaTransactionManager – use Weblogic’s transaction manager
  • JpaTransactionManager – use with JPA
  • HibernateTransactionManager – use with Hibernate

Enable Annotation based transaction declarations:

<tx:annotation-driven/>

@Transactional annotation can be at class level or individual method level

AOP based transactional configuration

Add transaction behavior by matching beans/methods transactional based on patterns: (example config from Spring manual : http://static.springsource.org/spring/docs/3.1.2.RELEASE/spring-framework-reference/html/transaction.html)

<aop:config>
  <aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/>
  <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="txManager"> 
  <tx:attributes> 
    <!-- all methods starting with 'get' are read-only --> 
    <tx:method name="get*" read-only="true"/> 
    <!-- other methods use the default transaction settings --> 
    <tx:method name="*"/>
  </tx:attributes> 
</tx:advice>

Transaction Propagation: see http://static.springsource.org/spring/docs/3.1.x/javadoc-api/org/springframework/transaction/annotation/Propagation.html

eg

@Transactional(propagation=Propagation.REQUIRED)

  • REQUIRED – if no tx in progress oen is started. If in progress, tx is joined (THIS IS THE DEFAULT)
  • REQUIRES_NEW – new tx is started whether or not one already active. if previous tx active, it is suspended and new transaction started. if new transaction fails it does not have any impact on prior suspended tx
  • SUPPORTS – if tx active it’s used, it no transaction continues without a tx
  • NOT_SUPPORTED – no tx supported. if tx active, tx is suspended, code completes without tx. On completion returns to caller and previous tx is resumed
  • MANDATORY – tx must be active, and is joined when code called. if no tx active when code is called an exception is thrown
  • NESTED – if tx active, a new child transaction is created. if nested/child transaction fails, this forces parent transaction to also fail. if no tx active, creates a new one (no equivalent in EE?)
  • NEVER – rarely used. opposite of MANDATORY. if no tx active, continue. if tx active, throw exception

Rolling back a transaction

  • RuntimeExceptions always cause a transaction to rollback if not caught and consumed/handled
  • Exception to this is if default behavior is changed by using @Transactional(rollbackFor=ExceptionName.class) to indicate which specific exceptions will cause a rollback

Using @Transactional with JUnits

  • by default, an @Transactional @Test will always rollback db changes on test method completion to leave db intact/unchanged

Spring AOP

Solves problem of cross cutting concerns, like:

  • logging & tracing
  • transaction management
  • security
  • caching
  • error handling
  • performance metrics instrumentation

Goals of Spring AOP:

  • avoid mixing of unrelated concerns in the same code (‘tangling‘ – e.g. business logic and security code)
  • avoid duplication of same/boilerplate code throughout many locations (‘scattering‘, e.g. transaction management)

Spring AOP only works with Spring Beans – cannot be used for Java Classes not managed by Spring (unlike AspectJ)

Pointcut expression matching syntax:

  • designator(return_type package.classname.methodname(params))

designator: e.g. execute – match when method called

return_type: *=wildcard, void, or specific type

package and classname can use * anywhere in the pattern as a wildcard:

  • package and classname are optional and can be omitted, eg perform(*) would match perform method on any class in any package
  • packageA.*.packageC : one wildcard package name between packageA and packageC
  • packageA..packageC: any number of packages
  • classname+ : + indicates any subclass of this class type, eg execution(* *..SomeRepository+.*(*)) – matches any implementation (+) of SomeRepository in any package (*..), and any method with any parameters

methodname can also use wildcard

params

  • ‘..’ indicates any parameters
  • methodname(int, ..) : indicates one int param followed by any other params

Using Annotations to declare an Aspect

@Aspect
public class LoggerAspect
{
    @Before(execution(* *ServiceImpl.*(*))
    public void logMethodCall()
    {
    ....
    }

}

– this pointcut declares an aspect for any method with any params on any class with name ending *ServiceImpl

Equivalent Bean configuration:

<context:component-scan base-package="example"/>
<aop:aspectj-autoproxy/>

<aop:config>
    <aop:aspect ref="loggerAspect">
        <aop:before pointcut="execution(* *ServiceImpl.*(*)" method="logMethodCall"/>
    </aop:aspect>
</aop:config>

<bean id="loggerAspect" class="example.LoggerAspect"/>

Getting Context on matching join points

  • Use JoinPoint as param on Advice impl method
  • Allows access to matching method signature (eg package, name, params)

Advice Types:

@Before

  • before call is made to matching method

@AfterReturning

  • on return from call to matching method

@AfterThrowing

  • matches if target throws an exception
  • Can rethrow as a new exception, but if you do, wrap the original exception so the original context from the exception is preserved

@Around

  • executes before and after method call
  • allows you to either continue with the about-to-be-called method or skip the call ( proceed() )

Methods that call other public methods that are ‘under advice’ in the same class do not get matched with the pointcut. For example, if Class A has methods a1() and a2(), and if the pointcut pattern matches both a1() and a2(), if a1() calls a2() internally, a1() will get the advice, but a2() will not. (KH TODO: would be a nice example to demonstrate this, and the following part too)

If two methods ‘under advice’ are in different classes, and one calls the other, then both methods will get the advice.