簡體   English   中英

Spring AOP不適用於包含@Transactional方法的類

[英]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動態代理。

要解決這些問題之一

  1. 重寫你的切入點以在界面上操作而不是實現類
  2. 使用基於類而不是基於接口的代理
  3. 使用編譯或加載時間編織

重寫切入點

使用execution(* com.storehouse.business.services.UserCreatingService+.createUser(..))而不是現在的執行。 這將使用接口而不是具體類。

使用基於類的代理

假設您使用@EnableAspectJAutoProxyproxyTargetClass=true添加到它,導致@EnableAspectJAutoProxy(proxyTargetClass=true) 這將創建基於類的代理,並應使原始切入點工作。

使用編譯或加載時間編織

您也可以更改代碼的構建/加載方式,而不是使用代理。 對於編譯時編織,您必須修改構建以使用AspectJ編譯器在編譯時應用方面,然后您不再需要代理。

或者代替@EnableAspectJAutoProxy您可以添加@EnableLoadTimeWeaving ,如果您使用最近的servlet容器,則會在加載類時立即編織方面。

兩者都不需要代理(至少對於這部分),並且會使原始切入點工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM