У меня довольно странная проблема, я не могу понять.
У меня есть класс с именем CompanyAuthorization
, который является Spring @Service
и зависит от beans, реализующего CompanyAuthorizationStrategy
интерфейс, которые вводятся через конструктор, код выглядит следующим образом:
@Service
public class CompanyAuthorization
{
private final CompanyRepository companyRepository; // <-- JpaRepository
private final Set<CompanyAuthorizationStrategy> authorizationStrategies;
public CompanyAuthorization(CompanyRepository companyRepository,
Set<CompanyAuthorizationStrategy> authorizationStrategies)
{
this.companyRepository = companyRepository;
this.authorizationStrategies = authorizationStrategies;
}
// ...
@Transactional(readOnly = true)
public boolean authorizeUserToCompany(CompanyIdentity companyIdentity)
{
Company c = companyRepository.getOne(companyIdentity);
User u = SecurityUtils.getCurrentUserOrFail();
return authorizationStrategies.stream()
.anyMatch(strategy -> strategy.isAuthorized(c, u));
}
}
Эти CompanyAuthorizationStrategies также инициализируются Spring (помечены @Service
, сканирование компонентов включено).
Вот пример проблемы: c one:
@Service
public class OwnerCompanyAuthorizationStrategy implements CompanyAuthorizationStrategy
{
@Transactional(readOnly = true)
@Override
public boolean isAuthorized(Company company, User user)
{
return company.getOwner().equals(user);
}
}
В коде я могу использовать что-то вроде:
@PreAuthorize("isAuthenticated() && @companyAuthorization.authorizeUserToCompany(#companyIdentity)")
public void doSomething(CompanyIdentity companyIdentity) {
// ...
}
Проблема в том, что вызов doSomething
результатов в LazyInitializationException
, вызванный вызовом company.getOwner()
в методе OwnerCompanyAuthorizationStrategy
isAuthorized
- который IS @Transactional
(!).
Соответствующая часть трассировки стека:
org.hibernate.LazyInitializationException: could not initialize proxy [<MY_PROGRAM>.core.domain.entity.User#testuser] - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:170)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:310)
at org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor.intercept(ByteBuddyInterceptor.java:45)
at org.hibernate.proxy.ProxyConfiguration$InterceptorDispatcher.intercept(ProxyConfiguration.java:95)
at <MY_PROGRAM>.core.domain.entity.User$HibernateProxy$FNb1iLnl.equals(Unknown Source)
at <MY_PROGRAM>.retail.core.api.authorization.OwnerCompanyAuthorizationStrategy.isAuthorized(OwnerCompanyAuthorizationStrategy.java:16)
at <MY_PROGRAM>.retail.core.api.authorization.OwnerCompanyAuthorizationStrategy$$FastClassBySpringCGLIB$$9600d666.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:769)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:366)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:99)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)
at <MY_PROGRAM>.retail.core.api.authorization.OwnerCompanyAuthorizationStrategy$$EnhancerBySpringCGLIB$$3c84e20c.isAuthorized(<generated>)
at <MY_PROGRAM>.retail.core.api.authorization.CompanyAuthorization.lambda$authorizeUserToCompany$0(CompanyAuthorization.java:74)
Что мне не хватает? Почему недоступен сеанс для метода isAuthorized
, который равен @Transactional
, завернутый в прокси-сервер Spring и вызываемый извне? Я не могу понять этого.