我想用指定的注释(例如@Monitor)监视所有类的所有公共方法(注意:注释在类级别)。可能的切入点是什么?注意:我正在使用@AspectJ样式的Spring AOP。
我想用指定的注释(例如@Monitor)监视所有类的所有公共方法(注意:注释在类级别)。可能的切入点是什么?注意:我正在使用@AspectJ样式的Spring AOP。
Answers:
您应该将类型切入点与方法切入点结合使用。
这些切入点将在标记为@Monitor的类中查找所有公共方法:
@Pointcut("within(@org.rejeev.Monitor *)")
public void beanAnnotatedWithMonitor() {}
@Pointcut("execution(public * *(..))")
public void publicMethod() {}
@Pointcut("publicMethod() && beanAnnotatedWithMonitor()")
public void publicMethodInsideAClassMarkedWithAtMonitor() {}
建议结合了前两个的最后一个切入点,您就完成了!
使用注释,如问题中所述。
注解: @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>
Monitor
必须是Spring Component
?
Component
注释是用来告诉Spring容器应用包括韦弗的事情在AspectJ的类。默认情况下,仅春季看着Controller
,Service
等具体说明,但不是Aspect
。
@Component
的@interface
不是上的注释Aspect
。为什么需要那?
@Component
注解使得它如此Spring会由AspectJ的IoC / DI面向方面的系统编译。我不知道该怎么说。docs.spring.io/spring/docs/3.2.x/spring-framework-reference/...
您也可以将切入点定义为
public pointcut publicMethodInsideAClassMarkedWithAtMonitor() : execution(public * (@Monitor *).*(..));
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”类中专门用“ @MyHandling”注释的所有方法的执行。要毫无例外地拦截所有方法,只需将注释直接放在类上即可。
无论此处的私有/公共范围如何,但请记住,spring-aop不能在同一实例(通常是私有实例)中对方法调用使用aspect,因为在这种情况下它不使用代理类。
我们在这里使用@Around建议,但它与@ Before,@ After或任何建议的语法基本相同。
顺便说一下,@MyHandling注释必须这样配置:
@Retention(RetentionPolicy.RUNTIME)
@Target( { ElementType.METHOD, ElementType.TYPE })
public @interface MyHandling {
}
// perform actions after
永远不会被调用,因为我们在返回前行的价值。
您可以使用Spring的PerformanceMonitoringInterceptor并使用beanpostprocessor以编程方式注册建议。
@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;
}
}
}
从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 *);