27

したがって、Spring 3.2にはいくつかのジェネリックがあり、理想的には私のアーキテクチャは次のようになります。

class GenericDao<T>{}

class GenericService<T, T_DAO extends GenericDao<T>>
{
    // FAILS
    @Autowired
    T_DAO;
}

@Component
class Foo{}

@Repository
class FooDao extends GenericDao<Foo>{}

@Service
FooService extends GenericService<Foo, FooDao>{}

残念ながら、ジェネリックの複数の実装では、自動配線は複数の一致するBean定義に関するエラーをスローします。これは、@Autowired型消去の前に処理するためだと思います。私が見つけた、または思いついたすべての解決策は、私には醜いように見えるか、または単に不可解に機能することを拒否します。この問題を回避する最善の方法は何ですか?

4

7 に答える 7

26

GenericServiceにコンストラクターを追加し、自動配線を拡張クラスに移動するのはどうですか。

class GenericService<T, T_DAO extends GenericDao<T>> {
    private final T_DAO tDao;

    GenericService(T_DAO tDao) {
        this.tDao = tDao;
    }
}

@Service
FooService extends GenericService<Foo, FooDao> {

    @Autowired
    FooService(FooDao fooDao) {
        super(fooDao);
    }
}

アップデート:

Spring 4.0 RC1の時点で、ジェネリック型に基づいて自動配線することが可能です。つまり、次のようなジェネリック サービスを記述できます。

class GenericService<T, T_DAO extends GenericDao<T>> {

    @Autowired
    private T_DAO tDao;
}

次のように、複数の異なるSpring Beanを作成します。

@Service
class FooService extends GenericService<Foo, FooDao> {
}
于 2013-03-30T20:30:38.670 に答える
4

@PostConstruct と ServiceLocatorFactoryBean を使用して、@autowire アノテーションを削除し、遅延「autowire」を実行できます。
GenericService は次のようになります

    public class GenericService<T, T_DAO extends GenericDao<T>>{

        @Autowired
        private DaoLocator daoLocatorFactoryBean;

        //No need to autowried, autowireDao() will do this for you 
        T_DAO dao;


        @SuppressWarnings("unchecked")
        @PostConstruct
        protected void autowireDao(){
        //Read the actual class at run time
        final Type type; 
        type = ((ParameterizedType) getClass().getGenericSuperclass())
                                              .getActualTypeArguments()[1]; 
        //figure out the class of the fully qualified class name
        //this way you can know the bean name to look for
        final String typeClass = type.toString();      
        String daoName = typeClass.substring(typeClass.lastIndexOf('.')+1
                                            ,typeClass.length());
        daoName = Character.toLowerCase(daoName.charAt(0)) + daoName.substring(1);
        this.dao = (T_DAO) daoLocatorFactoryBean.lookup(daoName);
       }

daoLocatorFactoryBean が魔法をかけてくれます。
これを使用するには、以下のようなインターフェースを追加する必要があります。

 public interface DaoLocator {
        public GenericDao<?> lookup(String serviceName);           
 }    

次のスニペットを applicationContext.xml に追加する必要があります

  <bean id="daoLocatorFactoryBean" 
      class="org.springframework.beans.factory.config.ServiceLocatorFactoryBean">
      <property name="serviceLocatorInterface"
              value="org.haim.springframwork.stackoverflow.DaoLocator" />
    </bean>

これは素晴らしいトリックで、ボイラープレート クラスを少し節約できます。
ところで、私はこのボイラープレート コードを大きな問題とは考えておらず、私が取り組んでいるプロジェクトでは matsev アプローチを使用しています。

于 2013-04-02T11:20:30.440 に答える
3

なぜ一般的なサービスが必要なのですか? サービス クラスは、複数のエンティティが関与する特定の作業単位を対象としています。リポジトリをコントローラーに直接挿入するだけです。

コンストラクター引数を使用した汎用リポジトリの例を次に示します。代わりに各メソッドをジェネリックにし、コンストラクター引数を持たないようにすることもできます。ただし、各メソッド呼び出しには、パラメーターとしてクラスが必要です。

public class DomainRepository<T> {

   @Resource(name = "sessionFactory")
   protected SessionFactory sessionFactory;

   public DomainRepository(Class genericType) {
        this.genericType = genericType;
   }

   @Transactional(readOnly = true)
   public T get(final long id) {
       return (T) sessionFactory.getCurrentSession().get(genericType, id);
   }

汎用リポジトリの Bean 定義の例 - 異なるコンストラクター引数を使用して、複数の異なる Bean を持つことができます。

<bean id="tagRepository" class="com.yourcompnay.data.DomainRepository">
        <constructor-arg value="com.yourcompnay.domain.Tag"/>
</bean>

リソース アノテーションを使用した Bean の依存性注入

@Resource(name = "tagRepository")
private DomainRepository<Tag> tagRepository;

そして、これにより、Domainreposiroty を特定のエンティティ/メソッド用にサブクラス化することができます。

public class PersonRepository extends DomainRepository<Person> {
    public PersonRepository(){
        super(Person.class);
    }
    ...
于 2013-04-05T12:48:15.000 に答える
1

この質問では、オートワイヤーとは何かを理解する必要があります。一般的に言えば、Web アプリのデプロイ時に autowire を使用してオブジェクト インスタンス/Bean を作成すると言えます。同じ名前の複数の場所で自動配線を宣言している場合は、質問に進みます。次に、このエラーが発生します。自動配線は複数の方法で実行できるため、複数のタイプの自動配線手法を使用している場合、このエラーが発生する可能性もあります。

于 2013-04-05T12:38:38.503 に答える
1

これらのジェネリックを拡張するクラスではオートワイヤーを使用する必要があります

于 2013-04-06T20:12:06.627 に答える
1

Spring 4 を使用した完全な汎用ソリューション:


ドメイン クラス

@Component
class Foo{
}

@Component
class Bar{
}

DAOレイヤー

interface GenericDao<T>{
//list of methods
}

class GenericDaoImpl<T> implements GenericDao<T>{
 @Autowired
 SessionFactory factory;

 private Class<T> domainClass; // Get Class Type of <T>

 public Session getCurrentSession(){
    return factory.getCurrentSession();
 }

 public DaoImpl() {
    this.domainClass = (Class<T>) GenericTypeResolver.resolveTypeArgument(getClass(), DaoImpl.class);
 }
 //implementation of methods
}

interface FooDao extends GenericDao<Foo>{
//Define extra methods if required
}

interface BarDao extends GenericDao<Bar>{
//Define extra methods if required
}

@Repository
class FooDao extends GenericDaoImpl<Foo> implements FooDao{
 //implementation of extra methods
}

@Repository
class BarDao extends GenericDaoImpl<Bar> implements BarDao{
 //implementation of extra methods
}

サービス層

interface GenericService<T>{
//List of methods
}

class GenericServiceImpl<T> implements GenericService<T>{
 @Autowire
 protected GenericDao<T> dao; //used to access DAO layer
}

class FooService extends GenericService<Foo>{
//Add extra methods of required
}

class BarService extends GenericService<Bar>{
//Add extra methods of required
}

@Service
class FooServiceImpl extends GenericServiceImpl<Foo> implements GenericService<Foo>{
//implementation of extra methods
}

@Service
class BarServiceImpl extends GenericServiceImpl<Bar> implements GenericService<Bar>{
//implementation of extra methods
}
于 2015-05-20T20:12:18.537 に答える