【问题标题】:Spring AOP doesn`t work with class comprising @Transactional methodSpring AOP 不适用于包含 @Transactional 方法的类
【发布时间】:2016-02-08 13:45:01
【问题描述】:

我开发网络应用程序,需要存储重量级文件并为此目的使用 Apache FTP 服务器。当新用户注册他的帐户时,必须在远程服务器上创建以他的用户名命名的文件夹。为了建立连接,在执行 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 方法添加到服务类:

@Transactional
public void checkIfUsernameExist(String username) {

}

现在不调用 Aspect 类的方法。你能解释一下原因吗。提前感谢您的帮助。

【问题讨论】:

  • 你定义了自动扫描吗?
  • 如果你的意思是 比是
  • 你的切入点是错误的,你不应该以类为目标,但接口将UserCreatingServiceImpl替换为UserCreatingService+(如果不在impl包中,也将其删除。跨度>
  • 是的,你是对的。我已经更改了切入点,现在一切正常。

标签: java spring spring-aop spring-aspects


【解决方案1】:

问题在于您的切入点表达式。

execution(* com.storehouse.business.services.impl.UserCreatingServiceImpl.createUser(..))

您正在拦截 createUser 方法在 UserCreatingServiceImpl 上的执行。当您不添加为您的实现创建代理的内容时,此方法有效。因为您将直接调用此方法。

但是,当您添加 @Transactional 时,会创建一个代理,并且现在在 UserCreatingService 上完成方法调用,因为这是创建的代理所需的接口。默认情况下,spring 使用基于接口的 JDK 动态代理。

要解决做这些事情之一

  1. 重写你的切入点来操作接口而不是实现类
  2. 使用基于类而不是基于接口的代理
  3. 使用编译或加载时编织

重写切入点

使用execution(* com.storehouse.business.services.UserCreatingService+.createUser(..)) 而不是您现在拥有的。这将使用接口而不是具体类。

使用基于类的代理

假设您使用@EnableAspectJAutoProxyproxyTargetClass=true 添加到它,导致@EnableAspectJAutoProxy(proxyTargetClass=true)。这将创建基于类的代理,并且应该使原始切入点起作用。

使用编译或加载时编织

除了使用代理之外,您还可以更改代码的构建/加载方式。对于编译时编织,您必须修改构建以使用 AspectJ 编译器在编译时应用方面,然后您就不再需要代理了。

或者您可以添加@EnableLoadTimeWeaving 来代替@EnableAspectJAutoProxy,如果您使用最近的servlet 容器,它会在加载类后立即编织方面。

两者都将消除对代理的需求(至少在这部分)并使原始切入点起作用。

【讨论】:

    猜你喜欢
    • 2021-07-03
    • 1970-01-01
    • 2021-12-27
    • 2015-02-26
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 2012-11-13
    相关资源
    最近更新 更多