मैं निर्दिष्ट एनोटेशन के साथ सभी वर्गों के सभी सार्वजनिक तरीकों की निगरानी करना चाहता हूं (@Monitor कहते हैं) (ध्यान दें: एनोटेशन कक्षा में है)। इसके लिए एक संभावित बिंदु क्या हो सकता है? नोट: मैं @AspectJ शैली स्प्रिंग AOP का उपयोग कर रहा हूं।
मैं निर्दिष्ट एनोटेशन के साथ सभी वर्गों के सभी सार्वजनिक तरीकों की निगरानी करना चाहता हूं (@Monitor कहते हैं) (ध्यान दें: एनोटेशन कक्षा में है)। इसके लिए एक संभावित बिंदु क्या हो सकता है? नोट: मैं @AspectJ शैली स्प्रिंग AOP का उपयोग कर रहा हूं।
जवाबों:
आपको एक विधि बिंदु के साथ एक प्रकार के बिंदु को संयोजित करना चाहिए।
ये बिंदु एक @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 में वर्ग में शामिल हैं लागू करने के लिए स्प्रिंग कंटेनर बताने के लिए प्रयोग किया जाता है। डिफ़ॉल्ट रूप से, स्प्रिंग केवल पर लग रहा है Controller
, Service
और अन्य विशिष्ट एनोटेशन, लेकिन नहीं Aspect
।
@Component
एनोटेशन पर बात कर रहा था @interface
न कि नोट पर Aspect
। इसकी आवश्यकता क्यों है?
@Component
एनोटेशन यह बनाता है तो वसंत AspectJ आईओसी / डि पहलू उन्मुख प्रणाली के साथ यह संकलन होगा। मुझे नहीं पता कि इसे अलग तरीके से कैसे कहा जाए। 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
}
यह 'YourService' वर्ग में '@MyHandling' के साथ विशेष रूप से एनोटेट किए गए सभी तरीकों के निष्पादन को रोक देगा। अपवाद के बिना सभी तरीकों को बाधित करने के लिए, बस एनोटेशन को सीधे वर्ग पर रखें।
यहां निजी / सार्वजनिक दायरे की कोई बात नहीं है, लेकिन ध्यान रखें कि स्प्रिंग-एप एक ही उदाहरण (आमतौर पर निजी वाले) में विधि कॉल के लिए पहलू का उपयोग नहीं कर सकता है, क्योंकि यह इस मामले में प्रॉक्सी वर्ग का उपयोग नहीं करता है।
हम यहां @Around सलाह का उपयोग करते हैं, लेकिन यह मूल रूप से @Before, @After या किसी भी सलाह के साथ एक ही वाक्यविन्यास है।
वैसे, @MyHandling एनोटेशन को इस तरह कॉन्फ़िगर किया जाना चाहिए:
@Retention(RetentionPolicy.RUNTIME)
@Target( { ElementType.METHOD, ElementType.TYPE })
public @interface MyHandling {
}
// perform actions after
हम पहले लाइन में मूल्य वापस लौट रहे हैं के बाद से कभी नहीं कहा जाता हो जाएगा।
आप स्प्रिंग के परफॉरमेंसिंग इन्टरसेप्टर का उपयोग कर सकते हैं और प्रोग्राम को सेमपॉस्टप्रोसेसर का उपयोग करके सलाह को पंजीकृत कर सकते हैं।
@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 *);