标签 - spring

spring    2016-04-29 12:29:25    1539    0    0

问题描述

项目中有一个接口ConfigService,该接口有一个实现类RedisDBConfigService,实现类中有个方法使用了Spring的事务注解@Transactional,代码大致如下:

  1. @Service
  2. public class RedisDBConfigService implements ConfigService {
  3. @Autowired
  4. private DataMapper mapper;
  5. //为了做单元测试,提供一个set方法
  6. public void setDataMapper(DataMapper dataMapper) {
  7. this.mapper = dataMapper;
  8. }
  9. //基于Spring事务控制
  10. @Transactional(rollbackFor = Exception.class)
  11. @Override
  12. public void updateConfig(Data data) throws Exception {
  13. doSomething();
  14. }
  15. }

Spring的事务配置如下:

  1. <!-- 注解方式配置事物 -->
  2. <tx:annotation-driven transaction-manager="transactionManager"/>

这种方式有一个隐含条件就是:Spring为需要事务控制的类创建代理的时候,默认使用JDKProxy来创建。

以上是前提条件。这里要说明一下,程序并没有任何问题,上面的设置也是正确的,可以正确无误运行。那么这样的设置出现了什么问题呢?

问题回放

问题出在单元测试上。如果仅仅测试一下updateConfig方法能否正确运行,是很简单的,也不会有问题。但是单元测试的意义不仅于此,有时候我们需要测试一些异常情况。
比如这个例子中,我需要测试一下DataMapper执行出错抛异常的时候程序的运行结果。为了让程序抛异常,我的思路是自己实现一个DataMapper,然后在方法中直接抛出异常,然后将该DataMapper赋值给RedisDBConfigServ

spring 设计模式    2016-03-17 19:11:57    724    0    0

本文将会不断总结更新

工厂方法模式

Spring中提供了FactoryBean接口,用于创建各种不同的Bean。
title
开发人员也可以自己实现该接口,常用于框架集成。比如mybatis-spring-1.1.0.jar包中的SqlSessionFactoryBean就是如此。

模板方法模式

Spring针对JDBC,JMS,JPA等规范,都提供了相应的模板方法类,如JdbcTemplate,JmsTemplate, JpaTemplate
例如JdbcTemplate,它提供了很多常用的增加,删除,查询,修改方法模板。而JMSTemplate则提供了对于消息的发送,接收方法等。下面是JMSTemplate的部分方法图:
title

代理模式

Spring中AOP,事务等都大量运用了代理模式。

观察者模式

Spring中提供了一种事件监听机制,即ApplicationListener,可以实现Spring容器内的事件监听。可以参考这里
主要是以下两个接口:
发布消息
title
监听消息
title

单例模式

Spring默认的创建Bean的作用域就是单例,即每个Spring容器中只存在一个该类的实例。可以通过@Scope(“prototype”)来修改成prototype模式,prototype在设计模式中叫做原型模式,实际上,Spring中对于@Scope(“prototype”)标记的Bean的处理的确是原型模式。

原型模式

原型模式是创建型模式的一种,其特点在于通过“复制”一个已经存在的实例来返回新的实例,而不是新建实例。被复制的实例就是我们所称的“原型”,这个原型是可定制的。
原型模式多用于创建复杂的或者耗时的实例,因为这种情况下,复制一个已经存在的实例使程序运行更高效;或者创建值相等,只是命名不一样的同类数据。

Spring中,如果一个类被标记为”prototype”,每一次请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)都会产生一个新的bean实例。
但是,Spring不能对一个prototype Bean的整个生命周期负责,容器在初始化、配置、装饰或者

spring 事务 BUG    2016-02-19 14:02:33    301    0    0

问题描述:

在Spring事务控制中,如果某个类的方法A和方法B都进行了事务控制(比如都加上了@Transactional注解),当在A方法中调用B方法的时候,实际运行过程中,B方法是不会被Spring事务控制的,而是仅仅对A方法进行了事务控制。

上述问题出现的典型代码如下:

public class SayHelloImpl implements SayHello {

    @Override
    @Transactional
    public void sayHi() {
        this.sayHello();
    }

    @Override
    @Transactional
    public void sayHello() {
        // do something..
    }

}

上面的方法,如果SayHello的sayHi方法被调用,sayHi方法在调用sayHello方法的时候,虽然sayHello方法也有Transactional控制,但实际上spring不会为该方法进行事务管理。
解决办法可参考:
http://www.iteye.com/topic/1122740

原理解释及模拟

由于Spring的事务控制本质上也是通过代理来实现,所以我们来看一下通过JDK动态代理实现会是什么样子:

假设有一个接口:

public interface SayHello {

    void sayHi();

    void sayHello();
}

接口实现类,注意sayHello方法里面调用了sayHi方法:

new SayHello() {

            @Override
            public void sayHi() {
                System.out.println("hi");
            }

            @Override
            public void sayHello() {
                this.sayHi(