[英]Spring AOP doesn`t work with class comprising @Transactional method
我開發了web-app,需要存儲重量級文件並使用Apache FTP Server來實現此目的。 當新用戶注冊其帳戶時,必須在遠程服務器上創建名為其用戶名的文件夾。 要建立連接,在執行UserCreatingServiceImpl.createUser()方法之前,我使用Spring AOP:
@Component
@Aspect
public class RemoteServerConnectionEstablisher {
private static boolean connectionEstablished = false;
@Autowired
private RemoteServerConnector serverConnector;
@Pointcut("execution(* com.storehouse.business.services.impl.UserCreatingServiceImpl.createUser(..)) ||"
+ " execution (* com.storehouse.business.services.impl.ItemCreatingServiceImpl.createItem(..)) ||"
+ "execution (* com.storehouse.business.services.impl.FileDownloadingServiceImpl.downloadFile(..))")
public void pointcut() {
}
@Before("pointcut()")
public void establishConnection(JoinPoint jp) {
if (!connectionEstablished) {
if (serverConnector.connectToRemoteServer()) {
connectionEstablished = true;
}
}
}
@After("pointcut()")
public void disconnect(JoinPoint jp) {
if (connectionEstablished) {
if (serverConnector.disconnect()) {
connectionEstablished = false;
}
}
}
}
這是使用createUser()方法的服務類:
@Service
public class UserCreatingServiceImpl implements UserCreatingService {
@Autowired
private UserService userService;
@Autowired
private FTPClient ftpClient;
@Override
public boolean createUser(UserDto userDto) {
try {
ftpClient.makeDirectory(userDto.getUsername());
UserMapper userMapper = new UserMapper();
userService.persistUser(userMapper.dtoToEntity(userDto));
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
@Transactional
public void checkIfUsernameExist(String username) {
}
}
一切都運行正常,直到我將@Transactional方法添加到service -class:
@Transactional
public void checkIfUsernameExist(String username) {
}
現在Aspect-class的方法不會調用。 你能解釋一下原因嗎? 在此先感謝您的幫助。
問題出在你的切入點表達中。
execution(* com.storehouse.business.services.impl.UserCreatingServiceImpl.createUser(..))
您正在攔截UserCreatingServiceImpl
上的createUser
方法的UserCreatingServiceImpl
。 當您不添加為您的實現創建代理的內容時,此方法有效。 因為你將直接調用這個方法。
但是,當您添加了@Transactional
會創建一個代理,並且現在在UserCreatingService
上完成方法調用,因為這是創建的代理所留下的接口。 默認情況下,spring使用基於接口的JDK動態代理。
要解決這些問題之一
使用execution(* com.storehouse.business.services.UserCreatingService+.createUser(..))
而不是現在的執行。 這將使用接口而不是具體類。
假設您使用@EnableAspectJAutoProxy
將proxyTargetClass=true
添加到它,導致@EnableAspectJAutoProxy(proxyTargetClass=true)
。 這將創建基於類的代理,並應使原始切入點工作。
您也可以更改代碼的構建/加載方式,而不是使用代理。 對於編譯時編織,您必須修改構建以使用AspectJ編譯器在編譯時應用方面,然后您不再需要代理。
或者代替@EnableAspectJAutoProxy
您可以添加@EnableLoadTimeWeaving
,如果您使用最近的servlet容器,則會在加載類時立即編織方面。
兩者都不需要代理(至少對於這部分),並且會使原始切入點工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.