【问题标题】:Generifying Service layer classes生成服务层类
【发布时间】:2016-10-12 11:13:24
【问题描述】:

我正在尝试遵循代码重用最佳实践。 我有一些通用方法的通用 DAO 接口:

    public interface DaoInterface<T> {
        T findById(int id);
        //...more methods...
    }

及其实现类:

    public class GenericDao<T> implements DaoInterface<T> {

        @SuppressWarnings("unchecked")
        private final Class<T> persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];

        @Autowired
        protected SessionFactory sessionFactory;

        @Override
        @SuppressWarnings("unchecked")
        public T findById(int id) {
            Session session = sessionFactory.getCurrentSession();
            return (T) session.get(persistentClass, id);
        }

        //...more methods...
    }

然后我的每个具体实现类都扩展GenericDao 并实现它的接口。

我的应用程序中也有服务层。一些服务的方法完全将它们的工作委托给 DAO 类。因此,在每个具体的服务实现中,我都会自动装配适当的 DAO 类并调用它的方法。 所以现在看起来:

public interface CustomerService {
    Customer findById(int id);
}

和实施:

@Service
@Transactional(readOnly = true, rollbackFor = Exception.class)
public class CustomerServiceImpl implements CustomerService {

    @Autowired
    private CustomerDao customerDao;

    @Override
    public Customer findById(int id) {
        return customerDao.findById(id);
    }
}

我的问题是 - 如何以与 DAO 相同的方式生成服务类?这样我的具体类就会看起来:

public class CustomerServiceImpl extends GenericService<Customer> implements CustomerService {
.....
}

问题是我无法在通用服务中自动装配 DAO 类:

@Autowired
private GenericDao<T> dao;

这样我就可以调用dao 的方法。 我应该在构造函数中这样做吗?

还有一个问题 - 在泛型类或每个实现类中使用 @Transactional 注释方法的正确位置在哪里?

【问题讨论】:

  • 可能的答案太多,或者对于这种格式来说,好的答案太长了。请添加详细信息以缩小答案范围或隔离可以在几段中回答的问题。
  • 主要问题是如何在GenericService&lt;T&gt;类中自动装配&lt;T&gt;类型的GenericDao

标签: java spring generics service dao


【解决方案1】:

您必须创建一个通用 Dao 的实例并在服务层中做出一些决定:

 @Repository
 public class GenericDao implements DaoInterface<T> {
 //The type must be aquired at runtime,otherwise it may not be thread safe

    @Autowired
    protected SessionFactory sessionFactory;

    @Override
    @SuppressWarnings("unchecked")
    public T findById(int id,Class<?> persistenceClass) {
        Session session = sessionFactory.getCurrentSession();
        return (T) session.get(persistenceClass, id);
    }

    //...more methods...
}

此外,如果您需要一个好的通用存储库层,请查看 Spring Data Jpa

这将使 只有一个 GenericDao 的实例。

接下来你有两个选择:

  1. 为您的所有需求创建单例服务
  2. 为每个实体创建一个类服务

    abstract class GenericService<T> {
        @Autowired
        protected GenericDao dao;
        @SuppressWarnings("unchecked")
        protected final Class<T> persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    
        @Override
        public T  findById(int id) {
            return dao.findById(id,persistenceClass);
        }   
    }
    

    现在,您的每一项服务都必须使用提供的持久性类型扩展 GenericService,然后工作就完成了。

【讨论】:

  • 感谢您的详细解答!这就是解决方案。还有一个问题 - 我应该用 @Repository 注释标记子 DAO 类,还是它们会从 GenericDao 继承它?
  • 不,您必须在要实例化的每个实现上指定 @Repository(或任何其他 Spring Bean 注释)。
  • 我明白了,但是没有必要在GenericDao类上指定这个注解,因为我不会直接使用它。我说的对吗?
  • 仅当您想直接在 GenericService 中注入 genericDao 实现时才需要。
猜你喜欢
  • 1970-01-01
  • 2010-12-30
  • 2016-09-19
  • 1970-01-01
  • 2021-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多