1

我开发网络应用程序,需要存储重量级文件并为此目的使用 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 类的方法不会调用。你能解释一下原因吗。提前感谢您的帮助。

4

1 回答 1

3

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

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

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

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

要解决做这些事情之一

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

重写切入点

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

使用基于类的代理

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

使用编译或加载时编织

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

或者,如果您使用最近的 servlet 容器,则@EnableAspectJAutoProxy可以添加@EnableLoadTimeWeaving哪个,而不是在加载类时立即编织方面。

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

于 2016-02-09T06:52:58.673 回答