具有特定注释的类的所有方法的@AspectJ 切入点

我想用指定的注释来监视所有类的所有公共方法(比如@Monitor)(注意: 注释是在类级别上的)。这有什么可能的切入点吗? 注意: 我使用的是@AspectJ 风格的 Spring AOP。

176734 次浏览

差不多是这样:

@Before("execution(* com.yourpackage..*.*(..))")
public void monitor(JoinPoint jp) {
if (jp.getTarget().getClass().isAnnotationPresent(Monitor.class)) {
// perform the monitoring actions
}
}

请注意,您在同一个类 之前上不能有任何其他通知,因为代理之后注释将丢失。

您应该将类型切入点与方法切入点组合起来。

这些切入点将完成在用@Monitor 注释标记的类中查找所有公共方法的工作:

@Pointcut("within(@org.rejeev.Monitor *)")
public void beanAnnotatedWithMonitor() {}


@Pointcut("execution(public * *(..))")
public void publicMethod() {}


@Pointcut("publicMethod() && beanAnnotatedWithMonitor()")
public void publicMethodInsideAClassMarkedWithAtMonitor() {}

通知结合前两个切入点的最后一个切入点,然后就完成了!

如果您感兴趣,我在这里用@AspectJ 样式编写了一个 小抄,在这里编写了一个相应的 示例文件

还可以将切入点定义为

public pointcut publicMethodInsideAClassMarkedWithAtMonitor() : execution(public * (@Monitor *).*(..));

最简单的方法似乎是:

@Around("execution(@MyHandling * com.exemple.YourService.*(..))")
public Object aroundServiceMethodAdvice(final ProceedingJoinPoint pjp)
throws Throwable {
// perform actions before


return pjp.proceed();


// perform actions after
}

它将拦截在“ YourService”类中用“@MyProcessing”专门注释的所有方法的执行。要无例外地拦截所有方法,只需将注释直接放在类上。

这里不管私有/公共作用域是什么,但是请记住,spring-aop 不能在同一个实例(通常是私有的)中使用方面进行方法调用,因为在这种情况下它不使用代理类。

我们在这里使用了@Around 通知,但它与@Before、@After 或任何通知的语法基本相同。

顺便说一下,@MyProcessing 注释必须像下面这样配置:

@Retention(RetentionPolicy.RUNTIME)
@Target( { ElementType.METHOD, ElementType.TYPE })
public @interface MyHandling {


}

使用注释,如问题中所述。

注释: @Monitor

课堂注解 app/PagesController.java:

package app;
@Controller
@Monitor
public class PagesController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public @ResponseBody String home() {
return "w00t!";
}
}

关于方法的注释,app/PagesController.java:

package app;
@Controller
public class PagesController {
@Monitor
@RequestMapping(value = "/", method = RequestMethod.GET)
public @ResponseBody String home() {
return "w00t!";
}
}

自定义注释,app/Monitor.java:

package app;
@Component
@Target(value = {ElementType.METHOD, ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Monitor {
}

注释方面,app/MonitorAspect.java:

package app;
@Component
@Aspect
public class MonitorAspect {
@Before(value = "@within(app.Monitor) || @annotation(app.Monitor)")
public void before(JoinPoint joinPoint) throws Throwable {
LogFactory.getLog(MonitorAspect.class).info("monitor.before, class: " + joinPoint.getSignature().getDeclaringType().getSimpleName() + ", method: " + joinPoint.getSignature().getName());
}


@After(value = "@within(app.Monitor) || @annotation(app.Monitor)")
public void after(JoinPoint joinPoint) throws Throwable {
LogFactory.getLog(MonitorAspect.class).info("monitor.after, class: " + joinPoint.getSignature().getDeclaringType().getSimpleName() + ", method: " + joinPoint.getSignature().getName());
}
}

启用 AspectJ,servlet-context.xml:

<aop:aspectj-autoproxy />

包括 AspectJ 库,pom.xml:

<artifactId>spring-aop</artifactId>
<artifactId>aspectjrt</artifactId>
<artifactId>aspectjweaver</artifactId>
<artifactId>cglib</artifactId>

您可以使用 Spring 的 PerformanceMonitor 拦截器,并使用 bean 后处理器以编程方式注册通知。

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Monitorable
{


}




public class PerformanceMonitorBeanPostProcessor extends ProxyConfig implements BeanPostProcessor, BeanClassLoaderAware, Ordered,
InitializingBean
{


private Class<? extends Annotation> annotationType = Monitorable.class;


private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();


private Advisor advisor;


public void setBeanClassLoader(ClassLoader classLoader)
{
this.beanClassLoader = classLoader;
}


public int getOrder()
{
return LOWEST_PRECEDENCE;
}


public void afterPropertiesSet()
{
Pointcut pointcut = new AnnotationMatchingPointcut(this.annotationType, true);
Advice advice = getInterceptor();
this.advisor = new DefaultPointcutAdvisor(pointcut, advice);
}


private Advice getInterceptor()
{
return new PerformanceMonitoringInterceptor();
}


public Object postProcessBeforeInitialization(Object bean, String beanName)
{
return bean;
}


public Object postProcessAfterInitialization(Object bean, String beanName)
{
if(bean instanceof AopInfrastructureBean)
{
return bean;
}
Class<?> targetClass = AopUtils.getTargetClass(bean);
if(AopUtils.canApply(this.advisor, targetClass))
{
if(bean instanceof Advised)
{
((Advised)bean).addAdvisor(this.advisor);
return bean;
}
else
{
ProxyFactory proxyFactory = new ProxyFactory(bean);
proxyFactory.copyFrom(this);
proxyFactory.addAdvisor(this.advisor);
return proxyFactory.getProxy(this.beanClassLoader);
}
}
else
{
return bean;
}
}
}

它应该足够标记你的方面方法如下:

@After("@annotation(com.marcot.CommitTransaction)")
public void after() {

看看 这个的一步一步的指导这一点。

来自 Spring 的 AnnotationTransactionAspect:

/**
* Matches the execution of any public method in a type with the Transactional
* annotation, or any subtype of a type with the Transactional annotation.
*/
private pointcut executionOfAnyPublicMethodInAtTransactionalType() :
execution(public * ((@Transactional *)+).*(..)) && within(@Transactional *);

使用

@Before("execution(* (@YourAnnotationAtClassLevel *).*(..))")
public void beforeYourAnnotation(JoinPoint proceedingJoinPoint) throws Throwable {
}

我和你们分享一个有用的代码,它是创建一个可以在类或方法中使用的注释。

@Target({TYPE, METHOD})
@Retention(RUNTIME)
@Documented
public @interface AnnotationLogger {
/**
* It is the parameter is to show arguments in the method or the class.
*/
boolean showArguments() default false;
}




@Aspect
@Component
public class AnnotationLoggerAspect {
    

@Autowired
private Logger logger;
    

private static final String METHOD_NAME   = "METHOD NAME: {} ";
private static final String ARGUMENTS     = "ARGS: {} ";
    

@Before(value = "@within(com.org.example.annotations.AnnotationLogger) || @annotation(com.org.example.annotations.AnnotationLogger)")
public void logAdviceExecutionBefore(JoinPoint joinPoint){
CodeSignature codeSignature = (CodeSignature) joinPoint.getSignature();
AnnotationLogger annotationLogger = getAnnotationLogger(joinPoint);
if(annotationLogger!= null) {
StringBuilder annotationLoggerFormat = new StringBuilder();
List<Object> annotationLoggerArguments = new ArrayList<>();
annotationLoggerFormat.append(METHOD_NAME);
annotationLoggerArguments.add(codeSignature.getName());
            

if (annotationLogger.showArguments()) {
annotationLoggerFormat.append(ARGUMENTS);
List<?> argumentList = Arrays.asList(joinPoint.getArgs());
annotationLoggerArguments.add(argumentList.toString());
}
logger.error(annotationLoggerFormat.toString(), annotationLoggerArguments.toArray());
}
}
    

private AnnotationLogger getAnnotationLogger(JoinPoint joinPoint) {
AnnotationLogger annotationLogger = null;
try {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = joinPoint.getTarget().getClass().
getMethod(signature.getMethod().getName(), signature.getMethod().getParameterTypes());
            

if (method.isAnnotationPresent(AnnotationLogger.class)){
annotationLogger = method.getAnnotation(AnnotationLoggerAspect.class);
}else if (joinPoint.getTarget().getClass().isAnnotationPresent(AnnotationLoggerAspect.class)){
annotationLogger = joinPoint.getTarget().getClass().getAnnotation(AnnotationLoggerAspect.class);
}
return annotationLogger;
}catch(Exception e) {
return annotationLogger;
}
}
}