2017-07-03 1 views
5

J'essaie d'utiliser l'annotation @Transactional dans une méthode sur mon service pour charger un champ paresseusement. Cependant, en utilisant @Transactional sur ma classe d'implémentation, tous les champs autowired sont null.Spring boot 2 L'annotation @Transactional rend les champs Autowired null

Voici mon implémentation:

@Service 
public class UserServiceImpl implements UserService { 

/** 
    * DefaultMapper. 
    */ 
@Autowired 
private DefaultMapper defaultMapper; 

/** 
    * Resource service injection. 
    */ 
@Autowired 
private ResourceService resourceService; 

/** 
    * UserRepository. 
    */ 
@Autowired 
private UserRepository userRepository; 

/** 
    * Jwt Factory. 
    */ 
@Autowired 
private JwtService jwtService; 

@Override 
@Transactional 
public final UserDto findByLogin(final String login) throws ResourceNotFoundException { 
// user repository is null here when using @Transactional 
    User user = this.userRepository.findByLogin(login) 
    .orElseThrow(() -> new ResourceNotFoundException(
    resourceService.getMessage(MessageBundle.EXCEPTION, "resource.notfound.user.login") 
    )); 
    UserDto userDto = defaultMapper.asUserDtoWithRoles(user); 
    return userDto; 
} 

Merci à l'avance.

+3

Supprimez 'final' de votre méthode ou définissez' spring.aop.proxy-target-class = false' dans votre 'application.properties'. ** NOTE: ** Cela nécessite Spring Boot 1.5.3 ou plus pour fonctionner pleinement! –

+0

Le contexte transactionnel est-il activé dans votre application de printemps? – drgPP

+0

Faire une transaction est la plupart du temps inutile pendant une action de lecture, êtes-vous sûr que vous avez besoin d'une transaction de lecture? – Zorglube

Répondre

5

Les transactions, entre autres, sont appliquées en utilisant AOP, le mécanisme AOP par défaut au printemps est d'utiliser des proxies. Lors de l'utilisation de Spring Boot, le mode proxy définit les proxys basés sur les classes.

Vous pouvez résoudre ce problème de l'une des deux manières suivantes.

  1. Retirer final de votre méthode
  2. proxy à base de classe Désactiver en ajoutant spring.aop.proxy-target-class=false à votre application.properties

Maintenant, quand vous Aded @Transactional cela conduira à une procuration de votre UserServiceImpl à créer, une classe proxy à base de données pour être exact. Qu'est-ce qui se passe est qu'une sous-classe est créée pour votre UserServiceImpl et toutes les méthodes sont remplacées pour appliquer le TransactionInterceptor. Toutefois, comme votre méthode est marquée final, la classe créée dynamiquement ne peut pas remplacer cette méthode. Par conséquent, la méthode regarde les instances de champ dans la classe proxy créée dynamiquement qui sera toujours null.

Lors de la suppression final la méthode peut être substituée, le comportement appliqué et il regarde les instances de champ appropriées (du UserServiceImpl réel au lieu du proxy). Lorsque vous désactivez les proxies basés sur les classes, vous obtenez un proxy JDK Dynamic qui est essentiellement un wrapper fin qui implémente toutes les interfaces implémentées par votre service. Il applique le comportement ajouté (transactions) et appelle le service réel. Il n'y a pas d'extension de la classe réelle nécessaire et en tant que tel, vous pouvez utiliser des méthodes finales proxy (tant que cela fait partie de votre interface).