Denny's profileJava DreamsBlogLists Tools Help

Blog


    April 15

    Spring之事务管理

    Spring之事务管理

    EJB被人骂的够多了,除了SLSB(无状态Session Bean)CMT(Container-Managed Transaction, 容器管理事务)外,但是CMT依然需要以来Application ServerSpring提供了比CMT更加轻量的,好用易用的事务管理。

    org.springframework.transaction. PlatformTransactionManager:是Spring事务管理的核心接口,正如类名,他分离了平台独立性。配合Springbean definition,他可以让我们在不同的事务平台上切换(jta->jdbc, etc)。

    package org.springframework.transaction;
    public interface PlatformTransactionManager {
      TransactionStatus getTransaction(TransactionDefinition definition)
          throws TransactionException;
      void commit(TransactionStatus status) throws TransactionException;
      void rollback(TransactionStatus status) throws TransactionException;

    }

    PlatformTransactionManager接口只有三个方法。Spring中使用AOP配合PlatformTransactionManager,可以使你感觉不到这个接口和他所依赖的类的存在。你需要做的只是在bean definition中做写配置。你的代码不需要写一行关于事务的代码(特殊情况除外,如果你想在代码中控制事务的commitrollback)。当然你也可以使用编程式事务处理(这里不做介绍,可以参数Spring document)


    申明式事务管理

    一种是使用AOP ProxyFactoryBean TransactionInterceptor

    <beans>

    ...

    <bean id="myTxManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">

    <property name="sessionFactory" ref="mySessionFactory"/>

    </bean>

    <bean id="myTxInterceptor"

    class="org.springframework.transaction.interceptor.TransactionInterceptor">

    <property name="transactionManager" ref="myTxManager"/>

    <property name="transactionAttributes">

    <props>

    <prop key="store*">PROPAGATION_REQUIRED</prop>

    <prop key="create*">PROPAGATION_REQUIRED</prop>

    <prop key="put*">PROPAGATION_REQUIRED</prop>

    <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>

    </props>

    </property>

    </bean>

    <bean id="myProductServiceTarget" class="product.ProductServiceImpl">

    <property name="productDao" ref="myProductDao"/>

    </bean>

    <bean id="myProductService" class="org.springframework.aop.framework.ProxyFactoryBean">

    <property name="proxyInterfaces">

    <value>product.ProductService</value>

    </property>

    <property name="target" ref="myProductServiceTarget"/>

    <property name="interceptorNames">

    <list>

    <value>myTxInterceptor</value>

    <value><!—add more interceptors here --></value>

    </list>

    </property>

    </bean>

    </beans>

    这种配置更加灵活, 你可以加更多的interceptor ProductService中, 如securityInterceptor.


    二使用易用的,便利的TransactionProxyFactoryBean

    <beans>

    ...

    <bean id="myTxManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">

    <property name="sessionFactory" ref="mySessionFactory"/>

    </bean>

    <bean id="myProductServiceTarget" class="product.ProductServiceImpl">

    <property name="productDao" ref="myProductDao"/>

    </bean>

    <bean id="myProductService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">

    <property name="transactionManager" ref="myTxManager"/>

    <property name="target" ref="myProductServiceTarget"/>

    <property name="transactionAttributes">

    <props>

    <prop key="store*">PROPAGATION_REQUIRED</prop>

    <prop key="create*">PROPAGATION_REQUIRED</prop>

    <prop key="put*">PROPAGATION_REQUIRED</prop>

    <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>

    </props>

    </property>

    </bean>

    </beans>

    相比上面的代码, 现在的代码少多了。我觉得Spring的类层次设计的非常合理,你可以使用其中的几个接口合并成另外一些大接口。如: Resource BeanFactory

    http://www.writely.com/View.aspx?docid=bdd75sqmr39x8

    Spring之FactoryBean(工厂Bean)

    SpringFactoryBean(工厂Bean

    org.springframework.beans.factory.FactoryBean是一个接口,是Spring中用于定义自定义服务的核心接口,他本身是在bean工厂中定义的一个bean,同时又是用于创建另一个Spring服务对象的工厂。

    FactoryBean.java

    package org.springframework.beans.factory;
    public interface FactoryBean {

      /**
       * Return an instance (possibly shared or independent) of the object
       * managed by this factory. As with a BeanFactory, this allows
       * support for both the Singleton and Prototype design pattern.
       <p>If this method returns null, the factory will consider the
       * FactoryBean as not fully initialized and throw a corresponding
       * FactoryBeanNotInitializedException.
       @return an instance of the bean (should not be <code>null</code>; a null value
       * will be considered as an indication of incomplete initialization)
       @throws Exception in case of creation errors
       @see FactoryBeanNotInitializedException
       */
      Object getObject() throws Exception;
      Class getObjectType();
      boolean isSingleton();

    }

    下面是FactoryBeangetObject方法的调用层次。

    我们可以看出,当我们用BeanFactoryApplicationContext去那getBean()时,如果这个Bean是被一个BeanFactory,那么BeanFactory得到的会是FactoryBean.getObject()的对象。

    下面是AbstractBeanFactorygetObjectForSharedInstance(String, Object)方法。

        // Now we have the bean instance, which may be a normal bean or a FactoryBean.
        // If it's a FactoryBean, we use it to create a bean instance, unless the
        // caller actually wants a reference to the factory.
        if (beanInstance instanceof FactoryBean) {
          if (!isFactoryDereference(name)) {
            // Return bean instance from factory.
            FactoryBean factory = (FactoryBean) beanInstance; //Cast to FactoryBean.
            if (logger.isDebugEnabled()) {
              logger.debug("Bean with name '" + beanName + "' is a factory bean");
            }
            try {
              beanInstance = factory.getObject(); // Get the real Object
            }
            catch (Exception ex) {
              throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
            }
            if (beanInstance == null) {
              throw new FactoryBeanNotInitializedException(
                  beanName, "FactoryBean returned null object: " +
                  "probably not fully initialized (maybe due to circular bean reference)");
            }
          }
          else {
             // The user wants the factory itself.
            if (logger.isDebugEnabled()) {
              logger.debug("Calling code asked for FactoryBean instance for name '" + beanName + "'");
            }
          }
        }

    Spring 通过FactoryBean来提供内置的许多有用的核心服务。当然你也可以实现自己的FactoryBean,但是你大不可以不必这样做,Spring已经提供了大量的。

    • org.springframework.jndi JndiObjectFactoryBeanJNDI LookUp

    • org.springframework.orm.hibernate3. LocalSessionFactoryBean:配置本地的Hibernate SessionFactory的工厂bean

    • org.springframework.aop.framework ProxyFactoryBean:通用的用于获得AOP代理的工厂bean

    • org.springframework.transaction.interceptor.TransactionProxyFactoryBean:用于为对象创建事务代理,用于实现简介易用申明性事务管理。

    • …………etc

    http://www.writely.com/View.aspx?docid=bdd75r9hmc98j

    November 02

    Spring AOP

    对AOP的概念一直是蒙蒙融融的。而且看Spring的文档上面对AOP的叙述还是不够清楚。 甚至看了文档还是不知道怎样使用Spring AOP, 直到我看了这篇文章。http://www.javalobby.com/forums/thread.jspa?messageID=91951283&#91951283
     
    AOP重要的两个概念, Advice和PointCut。
    Advice --> what       你做的事情。
    PointCut --> where   你想在什么地方做事情。 也就是类中的那些方法(注意:现在Spring AOP还只支持Method  Interceptor)。
     
    看看Spring中Advice的类的层次。

    看看Pointcut的层次

    Spring 提供了整合Advice和Pointcut的接口。

     这样我们只要提供PointcutAdvisor, 就能够知道在那个类的那些方法里面做什么事情了。

    现在我们还需要另外一个类帮助我们实现AOP。( org.springframework.aop.framework.ProxyFactoryBean)

     

    <!-- A simple MethodInterceptor style advice object (InterceptorA implements MethodInterceptor) -->
    <bean name="interceptorA" class="com.javalobby.tnt.spring.aop.InterceptorA" />
    <!-- A simple MethodBeforeAdvice style advice object (BeforeAdviceA implements MethodBeforeAdvice) -->
    <bean name="beforeAdviceA" class="com.javalobby.tnt.spring.aop.BeforeAdviceA"/>
    
    <!-- Create our controller bean -->
    <bean name="myRawController" class="com.javalobby.tnt.spring.aop.ExampleController" />
    
    

    <!-- Create the proxy bean that returns AOP'd varieties of our controller -->
    <bean name="myController" class="org.springframework.aop.framework.ProxyFactoryBean">
    	<property name="target" ref="myRawController"/>
    	<property name="interceptorNames">
    		<list>
    			<value>beforeAdviceA</value>
    			<value>beforeAdviceA</value>
    		</list>
    	</property>
    </bean>
    这样我们就对所有方法上面实现了beforeAdviceA,beforeAdviceA拦截。如果我们需要对这个类的特定方法进行拦截,如下
     
    <!-- A simple MethodInterceptor style advice object (InterceptorA implements MethodInterceptor) -->
    <bean name="interceptorA" class="com.javalobby.tnt.spring.aop.InterceptorA" />
    <!-- A simple MethodBeforeAdvice style advice object (BeforeAdviceA implements MethodBeforeAdvice) -->
    <bean name="beforeAdviceA" class="com.javalobby.tnt.spring.aop.BeforeAdviceA"/>
    
    <!-- 
    Use the NameMatchMethod pointcut advisor to make things a little simpler.
    -->
    <bean name="pointcut.advisor1" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
     <property name="advice" ref="interceptorA"/>
     <property name="mappedName" value="handleRequestInternal"/>
    </bean>
    
    <!-- 
    Use the NameMatchMethod pointcut advisor to make things a little simpler.
    -->
    <bean name="pointcut.advisor2" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
     <property name="advice" ref="beforeAdviceA"/>
     <property name="mappedName" value="handleRequestInternal"/>
    </bean>
    
    <!-- Create our controller bean -->
    <bean name="myRawController" class="com.javalobby.tnt.spring.aop.ExampleController" />
     
    <!-- Create the proxy bean that returns AOP'd varieties of our controller -->
    <bean name="myController" class="org.springframework.aop.framework.ProxyFactoryBean">
    	<property name="target" ref="myRawController"/>
    	<property name="interceptorNames">
    		<list>
    			<value>pointcut.advisor1</value>
    			<value>pointcut.advisor2</value>
    		</list>
    	</property>
    </bean>
    我们就实现了对myRawController的handleRequestInternal方法进行拦截。

    If you don't need direct (non-AOP'd) access to your bean, then it may be better for the simplicity of the file to just use an anonymous inner bean, rather than declaring the bean seperately to the proxy:

    <!-- Create the proxy bean that returns AOP'd varieties of our controller -->
    <bean name="myController" class="org.springframework.aop.framework.ProxyFactoryBean">
    	<property name="target"><bean class="com.javalobby.tnt.aop.ExampleController"/></property>
    	<property name="interceptorNames">
    		<list>
    			<value>beforeAdviceA</value>
    			<value>interceptorA</value>
    		</list>
    	</property>
    </bean>
    

     详情请参考那篇文章。