Tôi muốn theo dõi tất cả các phương thức công khai của tất cả các Lớp với chú thích được chỉ định (giả sử @Monitor) (lưu ý: Chú thích ở cấp lớp). Điều gì có thể là một điểm cắt có thể cho điều này? Lưu ý: Tôi đang sử dụng @AspectJ kiểu Spring AOP.
Tôi muốn theo dõi tất cả các phương thức công khai của tất cả các Lớp với chú thích được chỉ định (giả sử @Monitor) (lưu ý: Chú thích ở cấp lớp). Điều gì có thể là một điểm cắt có thể cho điều này? Lưu ý: Tôi đang sử dụng @AspectJ kiểu Spring AOP.
Câu trả lời:
Bạn nên kết hợp một kiểu cắt điểm với một phương pháp cắt điểm.
Các phím tắt này sẽ thực hiện công việc tìm tất cả các phương thức công khai trong một lớp được đánh dấu bằng chú thích @Monitor:
@Pointcut("within(@org.rejeev.Monitor *)")
public void beanAnnotatedWithMonitor() {}
@Pointcut("execution(public * *(..))")
public void publicMethod() {}
@Pointcut("publicMethod() && beanAnnotatedWithMonitor()")
public void publicMethodInsideAClassMarkedWithAtMonitor() {}
Tư vấn cho điểm cuối cùng kết hợp hai phần đầu và bạn đã hoàn tất!
Nếu bạn quan tâm, tôi đã viết một bảng cheat với kiểu @AspectJ ở đây với một tài liệu ví dụ tương ứng ở đây.
Sử dụng các chú thích, như được mô tả trong câu hỏi.
Chú thích: @Monitor
Chú thích trên lớp , app/PagesController.java
:
package app;
@Controller
@Monitor
public class PagesController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public @ResponseBody String home() {
return "w00t!";
}
}
Chú thích về phương pháp , app/PagesController.java
:
package app;
@Controller
public class PagesController {
@Monitor
@RequestMapping(value = "/", method = RequestMethod.GET)
public @ResponseBody String home() {
return "w00t!";
}
}
Chú thích tùy chỉnh , app/Monitor.java
:
package app;
@Component
@Target(value = {ElementType.METHOD, ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Monitor {
}
Các khía cạnh cho chú thích , 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());
}
}
Kích hoạt AspectJ , servlet-context.xml
:
<aop:aspectj-autoproxy />
Bao gồm các thư viện AspectJ , pom.xml
:
<artifactId>spring-aop</artifactId>
<artifactId>aspectjrt</artifactId>
<artifactId>aspectjweaver</artifactId>
<artifactId>cglib</artifactId>
Monitor
phải là một mùa xuân Component
?
Component
chú thích được sử dụng để nói container mùa xuân để áp dụng bao gồm các lớp trong AspectJ thợ dệt điều. Theo mặc định, mùa xuân chỉ nhìn Controller
, Service
và chú thích cụ thể khác, nhưng không phải Aspect
.
@Component
chú thích trên @interface
không Aspect
. Tại sao cần thiết?
@Component
chú thích làm cho nó nên mùa xuân sẽ biên dịch nó với hệ thống hướng khía cạnh AspectJ IoC / DI. Tôi không biết nói như thế nào. docs.spring.io/spring/docs/3.2.x/spring-framework-reference/iêu
Một cái gì đó như thế:
@Before("execution(* com.yourpackage..*.*(..))")
public void monitor(JoinPoint jp) {
if (jp.getTarget().getClass().isAnnotationPresent(Monitor.class)) {
// perform the monitoring actions
}
}
Lưu ý rằng bạn không được có bất kỳ lời khuyên nào khác trên cùng một lớp trước cái này, bởi vì các chú thích sẽ bị mất sau khi ủy quyền.
Sử dụng
@Before("execution(* (@YourAnnotationAtClassLevel *).*(..))")
public void beforeYourAnnotation(JoinPoint proceedingJoinPoint) throws Throwable {
}
Cách đơn giản nhất dường như là:
@Around("execution(@MyHandling * com.exemple.YourService.*(..))")
public Object aroundServiceMethodAdvice(final ProceedingJoinPoint pjp)
throws Throwable {
// perform actions before
return pjp.proceed();
// perform actions after
}
Nó sẽ chặn thực thi tất cả các phương thức được chú thích cụ thể với lớp '@MyHandling' trong lớp 'YourService'. Để chặn tất cả các phương thức mà không có ngoại lệ, chỉ cần đặt chú thích trực tiếp vào lớp.
Bất kể phạm vi riêng tư / công khai ở đây, nhưng hãy nhớ rằng spring-aop không thể sử dụng khía cạnh cho các cuộc gọi phương thức trong cùng một trường hợp (thường là riêng tư), bởi vì nó không sử dụng lớp proxy trong trường hợp này.
Chúng tôi sử dụng lời khuyên @Around ở đây, nhưng về cơ bản, đó là cùng một cú pháp với @B Before, @After hoặc bất kỳ lời khuyên nào.
Nhân tiện, chú thích @MyHandling phải được cấu hình như thế này:
@Retention(RetentionPolicy.RUNTIME)
@Target( { ElementType.METHOD, ElementType.TYPE })
public @interface MyHandling {
}
// perform actions after
sẽ không bao giờ được gọi là vì chúng ta đang trở về giá trị trong dòng trước đó.
Bạn có thể sử dụng PerformanceMonitoringInterceptor của Spring và đăng ký lời khuyên bằng cách sử dụng bộ xử lý beanpost.
@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;
}
}
}
Từ mùa xuân 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 *);