Я хочу контролювати всі публічні методи всіх класів із заданою анотацією (скажімо @Monitor) (примітка: Анотація знаходиться на рівні класу). Що може бути можливим для цього? Примітка: я використовую Spring AOP у стилі @AspectJ.
Я хочу контролювати всі публічні методи всіх класів із заданою анотацією (скажімо @Monitor) (примітка: Анотація знаходиться на рівні класу). Що може бути можливим для цього? Примітка: я використовую Spring AOP у стилі @AspectJ.
Відповіді:
Ви повинні комбінувати тип пункту з методом.
Ці пункти будуть робити роботу з пошуку всіх публічних методів у класі, позначеному анотацією @Monitor:
@Pointcut("within(@org.rejeev.Monitor *)")
public void beanAnnotatedWithMonitor() {}
@Pointcut("execution(public * *(..))")
public void publicMethod() {}
@Pointcut("publicMethod() && beanAnnotatedWithMonitor()")
public void publicMethodInsideAClassMarkedWithAtMonitor() {}
Порадьте останню точку, яка поєднує перші дві, і ви закінчили!
Якщо вас цікавить, я тут написав шпаргалку зі стилем @AspectJ з відповідним прикладом документа .
Використання приміток, як описано в питанні.
Анотація: @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
повинна бути весною Component
?
Component
Анотацій використовується , щоб повідомити пружинний контейнер для застосування включають клас в AspectJ ткач речі. За замовчуванням Spring тільки дивиться на Controller
, Service
і інші спеціальні інструкції, але не Aspect
.
@Component
примітку до @interface
не Aspect
. Для чого це потрібно?
@Component
Анотацій робить це так Спрінг буде скомпілювати його з аспектно-орієнтованої системою AspectJ IoC / DI. Я не знаю, як це сказати інакше. docs.spring.io/spring/docs/3.2.x/spring-framework-reference/…
Щось схоже:
@Before("execution(* com.yourpackage..*.*(..))")
public void monitor(JoinPoint jp) {
if (jp.getTarget().getClass().isAnnotationPresent(Monitor.class)) {
// perform the monitoring actions
}
}
Зауважте, що перед цим класом ви не повинні мати жодних інших порад щодо того ж класу , оскільки анотації втрачаються після надання доступу.
Використовуйте
@Before("execution(* (@YourAnnotationAtClassLevel *).*(..))")
public void beforeYourAnnotation(JoinPoint proceedingJoinPoint) throws Throwable {
}
Здається, найпростіший спосіб:
@Around("execution(@MyHandling * com.exemple.YourService.*(..))")
public Object aroundServiceMethodAdvice(final ProceedingJoinPoint pjp)
throws Throwable {
// perform actions before
return pjp.proceed();
// perform actions after
}
Він перехопить виконання всіх методів, спеціально позначених за допомогою "@MyHandling" у класі "YourService". Щоб перехопити всі без винятку методи, просто покладіть анотацію безпосередньо на клас.
Незалежно від сфери приватного / загального користування тут, але майте на увазі, що spring-aop не може використовувати аспект для викликів методів у тому самому екземплярі (як правило, приватних), оскільки він не використовує клас проксі в цьому випадку.
Тут ми використовуємо поради @Around, але це в основному той самий синтаксис з @Before, @After або будь-якою порадою.
До речі, анотація @MyHandling має бути налаштована так:
@Retention(RetentionPolicy.RUNTIME)
@Target( { ElementType.METHOD, ElementType.TYPE })
public @interface MyHandling {
}
// perform actions after
Ніколи не додзвонилися , так як ми повертаємо значення в рядку перед.
Ви можете використовувати Spring's 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;
}
}
}
З весни 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 *);