我开发了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的方法不会调用。你能解释一下原因吗?在此先感谢您的帮助。
答案 0 :(得分:3)
问题出在你的切入点表达中。
execution(* com.storehouse.business.services.impl.UserCreatingServiceImpl.createUser(..))
您正在拦截在createUser
上执行UserCreatingServiceImpl
方法。当您不添加为您的实现创建代理的内容时,此方法有效。因为你将直接调用这个方法。
但是,当您添加了@Transactional
时,会创建一个代理,现在在UserCreatingService
上完成方法调用,因为这是剩下的接口所做的创建代理。默认情况下,spring使用基于接口的JDK动态代理。
要解决这些问题之一
使用execution(* com.storehouse.business.services.UserCreatingService+.createUser(..))
代替您现在拥有的内容。这将使用接口而不是具体类。
假设您使用@EnableAspectJAutoProxy
添加proxyTargetClass=true
,导致@EnableAspectJAutoProxy(proxyTargetClass=true)
。这将创建基于类的代理,并应使原始切入点工作。
您也可以更改代码的构建/加载方式,而不是使用代理。对于编译时编织,您必须修改构建以使用AspectJ编译器在编译时应用方面,然后您不再需要代理。
或者代替@EnableAspectJAutoProxy
,您可以添加@EnableLoadTimeWeaving
,如果您使用最近的servlet容器,则会在加载类后立即编织方面。
两者都不需要代理(至少对于这部分),并且会使原始切入点工作。