@Autowire странная проблема

У меня есть странное поведение при автопроводном соединении

У меня есть подобный код как этот, и он работает

@Controller
public class Class1 {
    @Autowired
    private Class2 object2;
    ...
}

@Service
@Transactional
public class Class2{
   ...
}

Проблема состоит в том, что мне нужно это, Class2 реализует интерфейс, таким образом, я только изменил Class2, таким образом, он теперь похож:

@Controller
public class Class1 {
    @Autowired
    private Class2 object2;
    ...
}

@Service
@Transactional
public class Class2 implements IServiceReference<Class3, Long>{
   ...
}

public interface IServiceReference<T, PK extends Serializable> {
    public T reference(PK id);
}

с этим кодом я получаю a org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type for Class2. Это кажется этим @Transitional аннотация не совместима с интерфейсом потому что, если я удаляю @Transitional аннотация или яmplements IServiceReference<Class3, Long> проблема исчезает, и боб введен (хотя у меня должны быть оба в этом классе). Это также происходит, если я поместил аннотацию @Transitional в методах вместо в Классе.

Я использую Spring 3.0.2, если это помогает.

Разве интерфейс с транзакционным методом не совместим? Это может быть ошибка Spring?

23
задан skaffman 26 April 2010 в 11:46
поделиться

2 ответа

Проблема в том, что вашему Class1 нужна ссылка на IServiceReference, а не конкретная ссылка на Class2

@Controller
public class Class1 {
@Autowired
private IServiceReference object2;
    ...
}

Причина в том, что Spring создает динамический прокси для классов, которые вы отметили @Transactional. Таким образом, когда создается Class2, он оборачивается объектом Proxy, который явно не относится к типу Class2, а к типу IServiceReference.

Если вы хотите использовать Class2 с поддержкой прокси, вам нужно будет включить CGLIB Прочтите ниже:

Из Springs Doc:

Spring AOP по умолчанию использует стандартный Динамические прокси J2SE для прокси AOP. Это позволяет проксировать любой интерфейс (или набор интерфейсов ).

Spring AOP также может использовать прокси CGLIB. Это необходимо для прокси-классов, , а не интерфейсов. CGLIB используется по умолчанию, если бизнес-объект не реализует интерфейс.Поскольку хорошей практикой является программирование интерфейсов , а не классов, бизнес-классы обычно реализуют один или несколько бизнес-интерфейсов. Можно принудительно использовать CGLIB в тех (надеюсь, редких) случаях, когда вам нужно рекомендовать метод, который не объявлен в интерфейс, или где вам нужно передать проксируемый объект методу как конкретный тип.

Важно понимать тот факт, что Spring AOP основан на прокси. См. Раздел , озаглавленный Раздел 6.6.1, «Понимание прокси AOP» для тщательного изучения того, что именно эта деталь реализации на самом деле средства.

28
ответ дан 29 November 2019 в 01:58
поделиться

Аннотация Transactional инструктирует Spring генерировать прокси-объекты вокруг аннотированных bean-компонентов для реализации семантики транзакций. Сгенерированный прокси будет реализовывать те же интерфейсы, что и целевой компонент. Итак, если ваш целевой bean-компонент реализует IServiceReference , то сгенерированный прокси будет таким же.

Если целевой bean-компонент не имеет реализованных интерфейсов, то вместо этого сгенерированный прокси будет подклассом типа целевого bean-компонента.

В вашем исходном примере транзакционный прокси будет подклассом Class2 , потому что Class2 не реализовал интерфейсы. Когда вы изменили Class2 для реализации IServiceReference , сгенерированный прокси больше не расширял Class2 , а вместо этого реализовал IServiceReference . Это вызвало ваше исключение ClassCastException .

Наилучший подход к этой ситуации - удалить ссылку с Class1 на Class2 и вместо этого поговорить с Class2 исключительно через его интерфейсы. Class2 может реализовывать сколько угодно интерфейсов, прокси будет реализовывать их все.

Вы можете заставить Spring генерировать прокси подкласса независимо от интерфейсов, но это дополнительная сложность, и я бы не рекомендовал это делать.

13
ответ дан 29 November 2019 в 01:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: