【问题标题】:Spring DAO and immutable objectsSpring DAO 和不可变对象
【发布时间】:2015-04-28 07:01:44
【问题描述】:

根据不可变对象的定义 (see this question),我不太确定将 Spring DAO 的设置器作为唯一用途是否是确保不可变性的一种方法。例如(dataSource 属性):

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 只能被使用一次(当 IoC 初始化 Spring 上下文时),这样对象就不会被“其他”bean 或对象更改。
  • 你不能@Override,因为JdbcDaoSupport#setDataSource是最终的。

标签: java spring oop immutability


【解决方案1】:

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;
   }

【讨论】:

  • 实际上你不需要变量DataSource。看JdbcDaoSupport#getDataSource()
  • 不,你不需要 :) 我只是想解释一下,当你只想设置一次变量时,使用 final 可能是一个不错的选择。
  • 好的,我明白了。但是,如果我不提供 setter 方法,我不需要将其定为最终方法。对吗?
  • 是的,但是让它最终化你会鼓励编译器提醒你,这个属性还没有设置,这是这里唯一的要点:) 而且它不会编译。
  • 我很确定 Spring 只调用一次 @Autowiredannotated 方法。
【解决方案2】:

如果你查看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;

【讨论】:

    【解决方案3】:

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

    为了确保MySpringPojoDAO 的可变性首先使其成为最终的,这样它就不能被扩展,其次不要引入可以改变其内部状态的方法,如设置器。这就是我喜欢 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

    【讨论】:

      【解决方案4】:

      不可变对象

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

      不可变类 - 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 等。

      恕我直言,不变性是一个很好的考虑对象 - 同时定义对象的特定“类型”(实体 - Pojo 类型)。因此,尽管没有人会阻止您创建不可变的“MySpringPojoDAO”——如果您实现不可变的“MySpringPojo”并将 DAO 实现为可变的,那将更有意义。 (或可能是最终的)

      阅读 - https://stackoverflow.com/a/5124214/760393

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-10-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-27
        相关资源
        最近更新 更多