Spring AOP 切入点与接口上的注释匹配
我有一个在 Java 6 / Spring 3 中实现的服务类,需要一个注释来限制按角色的访问。
我定义了一个名为RequiredPermission的注释,它的值属性来自一个名为OperationType的枚举:
public @interface RequiredPermission {
/**
* One or more {@link OperationType}s that map to the permissions required
* to execute this method.
*
* @return
*/
OperationType[] value();}
public enum OperationType {
TYPE1,
TYPE2;
}
package com.mycompany.myservice;
public interface MyService{
@RequiredPermission(OperationType.TYPE1)
void myMethod( MyParameterObject obj );
}
package com.mycompany.myserviceimpl;
public class MyServiceImpl implements MyService{
public myMethod( MyParameterObject obj ){
// do stuff here
}
}
我还有以下方面定义:
/**
* Security advice around methods that are annotated with
* {@link RequiredPermission}.
*
* @param pjp
* @param param
* @param requiredPermission
* @return
* @throws Throwable
*/
@Around(value = "execution(public *"
+ " com.mycompany.myserviceimpl.*(..))"
+ " && args(param)" + // parameter object
" && @annotation( requiredPermission )" // permission annotation
, argNames = "param,requiredPermission")
public Object processRequest(final ProceedingJoinPoint pjp,
final MyParameterObject param,
final RequiredPermission requiredPermission) throws Throwable {
if(userService.userHasRoles(param.getUsername(),requiredPermission.values()){
return pjp.proceed();
}else{
throw new SorryButYouAreNotAllowedToDoThatException(
param.getUsername(),requiredPermission.value());
}
}
参数对象包含一个用户名,我想查找该用户所需的角色在允许访问该方法之前。
当我将注释放在 MyServiceImpl 中的方法上时,一切正常,切入点匹配并且方面启动。但是,我相信注释是服务契约的一部分,应该与单独的 API 包中的接口一起发布。显然,我不想在服务定义和实现上都添加注释(DRY)。
我知道在 Spring AOP 中有些情况是通过注释一个接口方法(例如事务)来触发方面的。这里是否有特殊的语法,或者它是根本不可能开箱即用的。
PS:我还没有发布我的 spring 配置,因为它似乎工作得很好。不,这些既不是我原来的类名也不是方法名。
PPS:实际上,这是我的 spring 配置的相关部分:
<aop:aspectj-autoproxy proxy-target-class="false" />
<bean class="com.mycompany.aspect.MyAspect">
<property name="userService" ref="userService" />
</bean>
I have a service class implemented in Java 6 / Spring 3 that needs an annotation to restrict access by role.
I have defined an annotation called RequiredPermission that has as its value attribute one or more values from an enum called OperationType:
public @interface RequiredPermission {
/**
* One or more {@link OperationType}s that map to the permissions required
* to execute this method.
*
* @return
*/
OperationType[] value();}
public enum OperationType {
TYPE1,
TYPE2;
}
package com.mycompany.myservice;
public interface MyService{
@RequiredPermission(OperationType.TYPE1)
void myMethod( MyParameterObject obj );
}
package com.mycompany.myserviceimpl;
public class MyServiceImpl implements MyService{
public myMethod( MyParameterObject obj ){
// do stuff here
}
}
I also have the following aspect definition:
/**
* Security advice around methods that are annotated with
* {@link RequiredPermission}.
*
* @param pjp
* @param param
* @param requiredPermission
* @return
* @throws Throwable
*/
@Around(value = "execution(public *"
+ " com.mycompany.myserviceimpl.*(..))"
+ " && args(param)" + // parameter object
" && @annotation( requiredPermission )" // permission annotation
, argNames = "param,requiredPermission")
public Object processRequest(final ProceedingJoinPoint pjp,
final MyParameterObject param,
final RequiredPermission requiredPermission) throws Throwable {
if(userService.userHasRoles(param.getUsername(),requiredPermission.values()){
return pjp.proceed();
}else{
throw new SorryButYouAreNotAllowedToDoThatException(
param.getUsername(),requiredPermission.value());
}
}
The parameter object contains a user name and I want to look up the required role for the user before allowing access to the method.
When I put the annotation on the method in MyServiceImpl, everything works just fine, the pointcut is matched and the aspect kicks in. However, I believe the annotation is part of the service contract and should be published with the interface in a separate API package. And obviously, I would not like to put the annotation on both service definition and implementation (DRY).
I know there are cases in Spring AOP where aspects are triggered by annotations one interface methods (e.g. Transactional). Is there a special syntax here or is it just plain impossible out of the box.
PS: I have not posted my spring config, as it seems to be working just fine. And no, those are neither my original class nor method names.
PPS: Actually, here is the relevant part of my spring config:
<aop:aspectj-autoproxy proxy-target-class="false" />
<bean class="com.mycompany.aspect.MyAspect">
<property name="userService" ref="userService" />
</bean>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果我理解正确,您需要一个切入点来查找扩展 MyService 的类中的所有方法,并带有注释和首选参数。
我建议您将: 替换
为:
如果您希望连接点与 MyService 类或扩展它的类匹配,则使用加号。
我希望它有帮助!
If I understand you correct, you want a pointcut that finds all methods in classes that extends MyService and is annotated and with the preferred arguments.
I propose that you replace:
with:
The plus sign is used if you want a joinpoint to match the MyService class or a class that extends it.
I hope it helps!
Espen,您的代码仅适用于一个类:
但是如果我希望 *com.mycompany.services.** 包中的所有服务都具有这种行为,该怎么办?
Espen, your code works only for one class:
but what if I want this behaviour for all services in *com.mycompany.services.** package?