我正在尝试在我的服务的方法中使用@Transactional
注释来懒洋洋地加载字段。但是,在我的Implementation类上使用@Transactional
会生成所有自动连接的字段null
。
这是我的实施:
@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;
}
提前谢谢。
答案 0 :(得分:7)
交易等等都是使用AOP应用的,Spring中的默认AOP机制是使用代理。使用Spring Boot时,代理模式设置基于类的代理。
您可以通过2种方式之一解决此问题。
final
spring.aop.proxy-target-class=false
application.properties
来停用基于类的代理
醇>
现在当您获得@Transactional
时,这将导致您创建UserServiceImpl
的代理,确切地说是基于类的代理。会发生什么是为您的UserServiceImpl
创建了一个子类,并且所有方法都被覆盖以应用TransactionInterceptor
。但是,由于您的方法标记为final
,因此动态创建的类不能覆盖此方法。因此,该方法查看动态创建的代理类中的字段实例,该代理类始终为null
。
删除final
时,可以覆盖该方法,应用该行为,它将查看正确的字段实例(实际的UserServiceImpl
而不是代理)。
当禁用基于类的代理时,您将获得一个JDK动态代理,它基本上是一个瘦包装器,它实现了服务实现的所有接口。它应用添加的行为(事务)并调用实际服务。没有所需的实际类的扩展,因此您可以代理最终方法(只要它是您的接口的一部分)。
答案 1 :(得分:0)
注意 - 您执行的方法的最终结果会产生问题,而不必使用标记为@Transnational的方法。 @Transnational注释导致动态创建代理对象。拥有final方法时,它不会在代理对象上运行。
答案 2 :(得分:0)
与Kotlin合作时,我遇到了同样的问题。当我在服务内部的方法中添加@Transactional
批注时,收到一条消息,提示Methods annotated with '@Transactional' must be overridable
,因此我继续将类和方法都标记为open
。容易吧?好吧,不是。
尽管可以编译,但是在执行时我得到了所需的存储库为null。我可以通过两种方式解决问题:
open
:open class FooService(private val barRepository: BarRepository) {
open fun aMethod(): Bar {
...
}
@Transactional
open fun aTransactionalMethod(): Bar {
...
}
}
这可行,但是将所有方法都标记为open
的类可能看起来有些奇怪,所以我尝试了其他方法。
interface IFooService {
fun aMethod(): Bar
fun aTransactionalMethod(): Bar
}
open class FooService(private val barRepository: BarRepository) : IFooService {
override fun aMethod(): Bar {
...
}
@Transactional
override fun aTransactionalMethod(): Bar {
...
}
}
由于所有方法都是可重写的,因此您将无需使用open
。
希望这有帮助=)