Spring DAO 和不可变对象

Spring DAO and immutable objects

根据不可变对象的定义 (see this question),我不太确定将 Spring DAO 的 setter 作为唯一用途是否是一种确保不变性与否。例如(数据源属性):

public class MySpringPojoDAO extends JdbcDaoSupport implements IMySpringPojoDAO {

   private boolean dataSourceSet = false;


   @Override
   public void setDataSource(DataSource dataSource){

       if (dataSourceSet) {
             throw new IllegalStateException("...");
       }

       dataSourceSet = true;
       this.dataSource = dataSource;
       }
   }

}

在错误的情况下,使用 Spring Framework 或 IoC 确保不变性的方法是什么?

Setter 需要多次使用,而构造函数则不然。

当涉及到Spring时,最好通过constructor设置所有需要的bean:

final DataSource dataSource;// will force this property to be set only once

@Autowired(required=true)
public MySpringPojoDAO (DataSource dataSource){
   this.dataSource = dataSource;
}

其次,您可以简单地添加 required 属性,这将使您的代码更短。 Spring 将确保提供了 DataSource 的 bean。

更新: 如果您仍想使用 setter,则不需要另一个标志,只需检查 !=null 条件:

   @Override
   public void setDataSource(DataSource dataSource){
       if (this.dataSource != null) { // has been already set
             throw new IllegalStateException("...");
       }
       this.dataSource = dataSource;
   }

不可变对象只是其状态(对象的数据)在构建后无法更改的对象。 JDK 中的不可变对象示例包括 String 和 Integer。

为了确保 MySpringPojoDAO 的可变性,首先使它成为最终的,这样它就不能被扩展,其次不要引入可以改变其内部状态的方法,比如 setter。这就是我喜欢 Spring 和 Guice 依赖注入的原因,您可以注入构造函数。

final public class MySpringPojoDAO extends JdbcDaoSupport implements IMySpringPojoDAO {

   // private boolean dataSourceSet = false; 

@Autowired
public MySpringPojoDAO (DataSource dataSource){
this.dataSource= dataSource
}
   /* @Override
   public void setDataSource(DataSource dataSource){

       if (dataSourceSet) {
             throw new IllegalStateException("...");
       }

       dataSourceSet = true;
       this.dataSource = dataSource;
       } */ 
       //don't use setters you'll need synchronization!!! 
   }

} 

check this out

不可变对象

如果一个对象在构造后其状态不能改变,则该对象被认为是不可变的。最大限度地依赖不可变对象已被广泛接受为创建简单、可靠代码的合理策略。

不可变 类 - java.lang.String, java.lang.Integer, java.lang.Byte, java.lang.Character, java.lang.Short, java.lang.Boolean, java.lang.Long, java.lang.Double, java.lang.Float ...等

类 可能/可能不是最终的但不完全符合(im)可变性的要求 - java.util.Collections、java.util.Arrays 等

恕我直言,不变性是一个很好的考虑对象 - 在定义特定的 'type'(实体 - Pojo 类型)对象时。因此,虽然没有人会阻止您创建 'MySpringPojoDAO' 不可变 - 如果您实现 'MySpringPojo' 不可变并且 DAO 是可变的,这将更有意义。 (或者可能是最终的)

阅读 -

如果你查看 JdbcDaoSupport 的实现,你会发现这个:

public abstract class JdbcDaoSupport extends DaoSupport {

    private JdbcTemplate jdbcTemplate;


    /**
     * Set the JDBC DataSource to be used by this DAO.
     */
    public final void setDataSource(DataSource dataSource) {
        if (this.jdbcTemplate == null || dataSource != this.jdbcTemplate.getDataSource()) {
            this.jdbcTemplate = createJdbcTemplate(dataSource);
            initTemplateConfig();
        }
    }

    /**
    * Return the JDBC DataSource used by this DAO.
    */
    public final DataSource getDataSource() {
        return (this.jdbcTemplate != null ? this.jdbcTemplate.getDataSource() : null);
    }

    [...]

}

JdbcDaoSupport#setDataSource 是最终的。您不能覆盖此方法。这意味着你必须这样做:

public class MySpringPojoDAO extends JdbcDaoSupport implements IMySpringPojoDAO {

    @Autowired
    public MySpringPojoDAO (DataSource dataSource){
        setDataSource(dataSource); // JdbcDaoSupport#setDataSource(..)
    }

    [...]

 }

所以让 Spring 像 DataSource 一样为您处理 bean 的生命周期。 您永远不应该手动创建 MySpringPojoDAO 的实例。改用:

@Autowired
private MySpringPojoDAO _myDao;