البرمجة الموجهة نحو الجوانب (AOP) هي نموذج برمجي يعد تطويرًا إضافيًا للبرمجة الإجرائية والموجهة للكائنات (OOP). فكرة AOP هي تسليط الضوء على ما يسمى وظيفة نهاية إلى نهاية. وهكذا كل شيء في محله ، هنا سأوضح كيفية القيام بذلك في Java - SpringAspectJ نمط التعليق التوضيحي (هناك أيضًا نمط xml قائم على المخطط ، والوظيفة متشابهة).
تسليط الضوء على وظائف نهاية إلى نهاية
إلى

وبعد ذلك

على سبيل المثال هناك وظائف تؤثر على عدة وحدات ، ولكنها لا تتعلق مباشرة برمز الأعمال ، وسيكون من الجيد وضعها في مكان منفصل ، وهذا موضح في الشكل أعلاه.
نقطة الالتحاق

نقطة الالتحاق - المفهوم التالي لـ AOP ، وهذه هي نقاط المراقبة ، والانضمام إلى الشفرة حيث يتم التخطيط لإدخال الوظائف.
النقطة

القطع هو شريحة ، استعلام عن نقاط المرفقات ، يمكن أن يكون نقطة واحدة أو أكثر. قواعد الاستعلام عن النقاط متنوعة للغاية ، في الشكل أعلاه ، طلب شرح على طريقة وطريقة محددة. يمكن دمج القواعد بواسطة && ، || ،!
النصيحة

نصيحة - مجموعة من التعليمات تنفذ على نقاط القطع (Pointcut). يمكن تنفيذ التعليمات في حالة أنواع مختلفة:
- قبل - قبل استدعاء الأسلوب
- بعد - بعد استدعاء الأسلوب
- بعد العودة - بعد إرجاع قيمة من دالة
- بعد الرمي - في حالة الاستثناء
- بعد النهاية - إذا تم تنفيذ الكتلة الأخيرة
- حول - يمكنك القيام بالمعالجة المسبقة ، والبريد ، والمعالجة قبل استدعاء الطريقة ، وكذلك تجاوز استدعاء الطريقة بشكل عام.
في نقطة واحدة يمكنك "تعليق" عدة نصائح من أنواع مختلفة.
الجانب

الجانب - وحدة تحتوي على أوصاف Pointcut و Tips.
الآن سأعطي مثالاً ، وأخيراً كل شيء سوف يقع (أو كل شيء تقريباً) في مكانه. نحن نعلم جميعًا عن كود التسجيل الذي يتخلل العديد من الوحدات ، غير المتعلقة برمز الأعمال ، ولكن مع ذلك فإنه مستحيل بدونه. ولذا أفصل هذه الوظيفة عن رمز الأعمال.
مثال - تسجيل الكود
الخدمة المستهدفة
@Service public class MyService { public void method1(List<String> list) { list.add("method1"); System.out.println("MyService method1 list.size=" + list.size()); } @AspectAnnotation public void method2() { System.out.println("MyService method2"); } public boolean check() { System.out.println("MyService check"); return true; } }
جانب مع وصف Pointcut والنصيحة.
@Aspect @Component public class MyAspect { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Pointcut("execution(public * com.example.demoAspects.MyService.*(..))") public void callAtMyServicePublic() { } @Before("callAtMyServicePublic()") public void beforeCallAtMethod1(JoinPoint jp) { String args = Arrays.stream(jp.getArgs()) .map(a -> a.toString()) .collect(Collectors.joining(",")); logger.info("before " + jp.toString() + ", args=[" + args + "]"); } @After("callAtMyServicePublic()") public void afterCallAt(JoinPoint jp) { logger.info("after " + jp.toString()); } }
ورمز اختبار الاتصال
@RunWith(SpringRunner.class) @SpringBootTest public class DemoAspectsApplicationTests { @Autowired private MyService service; @Test public void testLoggable() { List<String> list = new ArrayList(); list.add("test"); service.method1(list); service.method2(); Assert.assertTrue(service.check()); } }
تفسيرات في الخدمة الهدف لا يوجد ذكر للتسجيل ، في رمز الاتصال أكثر من ذلك ، يتركز كل التسجيل
في وحدة منفصلة@Aspect
class MyAspect ...
في النقطة
@Pointcut("execution(public * com.example.demoAspects.MyService.*(..))") public void callAtMyServicePublic() { }
لقد طلبت جميع أساليب MyService العامة مع أي نوع إرجاع
* وعدد الوسائط
(..)في
النصيحة قبل وبعد التي تشير إلى
Pointcut (callAtMyServicePublic) ، كتبت تعليمات للكتابة إلى السجل. JoinPoint ليست معلمة مطلوبة ، والتي توفر معلومات إضافية ، ولكن إذا تم استخدامها ، فيجب أن تكون الأولى.
كل شيء متباعد في وحدات مختلفة! رمز المتصل ، الهدف ، تسجيل الدخول.
النتيجة في وحدة التحكم

قد تختلف قواعد الاختصار
بعض الأمثلة على Pointcut والنصيحة:
طلب شرح على طريقة.
@Pointcut("@annotation(AspectAnnotation)") public void callAtMyServiceAnnotation() { }
نصيحة له
@Before("callAtMyServiceAnnotation()") public void beforeCallAt() { }
طلب طريقة محددة تشير إلى معلمات الطريقة المستهدفة
@Pointcut("execution(* com.example.demoAspects.MyService.method1(..)) && args(list,..))") public void callAtMyServiceMethod1(List<String> list) { }
نصيحة له
@Before("callAtMyServiceMethod1(list)") public void beforeCallAtMethod1(List<String> list) { }
الإشارة إلى نتيجة الإرجاع
@Pointcut("execution(* com.example.demoAspects.MyService.check())") public void callAtMyServiceAfterReturning() { }
نصيحة له
@AfterReturning(pointcut="callAtMyServiceAfterReturning()", returning="retVal") public void afterReturningCallAt(boolean retVal) { }
مثال لفحص الحقوق للحصول على نصيحة من النوع المحيط ، عبر التعليق التوضيحي
@Retention(RUNTIME) @Target(METHOD) public @interface SecurityAnnotation { }
الطرق التي يجب التحقق منها قبل المكالمة ، على اليمين ، يمكن أن تكتب عليها "SecurityAnnotation" ، ثم في Aspect سنحصل على شريحة منها ، وسيتم اعتراضها جميعًا قبل المكالمة وسيتم إجراء فحص الحقوق.
كود الهدف:
@Service public class MyService { @SecurityAnnotation public Balance getAccountBalance(User user) {
كود المتصل:
balance = myService.getAccountBalance(user); if (balance == null) { accessDenied(user); } else { displayBalance(balance); }
على سبيل المثال في رمز الاتصال والهدف ، لا يوجد تحقق من الحقوق ، فقط رمز العمل نفسه.
مثال على توصيف نفس الخدمة باستخدام نصيحة من نوع حول
@Aspect @Component public class MyAspect { @Pointcut("execution(public * com.example.demoAspects.MyService.*(..))") public void callAtMyServicePublic() { } @Around("callAtMyServicePublic()") public Object aroundCallAt(ProceedingJoinPoint call) throws Throwable { StopWatch clock = new StopWatch(call.toString()); try { clock.start(call.toShortString()); return call.proceed(); } finally { clock.stop(); System.out.println(clock.prettyPrint()); } } }
إذا قمنا بتشغيل رمز الاتصال مع المكالمات إلى طرق MyService ، نحصل على وقت الاتصال بكل طريقة. وهكذا ، دون تغيير رمز الاتصال والهدف ، أضفت ميزات جديدة: التسجيل والملف الشخصي والأمان.
مثال للاستخدام في نماذج واجهة المستخدم
يوجد كود من خلال تحديد اخفاء / إظهار الحقول في النموذج:
public class EditForm extends Form { @Override public void init(Form form) { formHelper.updateVisibility(form, settingsService.isVisible(COMP_NAME)); formHelper.updateVisibility(form, settingsService.isVisible(COMP_LAST_NAME)); formHelper.updateVisibility(form, settingsService.isVisible(COMP_BIRTH_DATE));
يمكنك أيضًا إزالة updateVisibility في نصيحة من نوع
حول @Aspect public class MyAspect { @Pointcut("execution(* com.example.demoAspects.EditForm.init() && args(form,..))") public void callAtInit(Form form) { }
الخ.
هيكل المشروع

ملف بوم <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>demoAspects</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>demoAspects</name> <description>Demo project for Spring Boot Aspects</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.6.RELEASE</version> <relativePath/> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
المواد
اسبرت البرمجة مع الربيع