CodeGym/Java Blogu/Rastgele/AOP nedir? En boy yönelimli programlamanın ilkeleri
John Squirrels
Seviye
San Francisco

AOP nedir? En boy yönelimli programlamanın ilkeleri

grupta yayınlandı
Merhaba, çocuklar ve kızlar! Temel kavramları anlamadan, işlevsellik oluşturmaya yönelik çerçeveleri ve yaklaşımları derinlemesine incelemek oldukça zordur. Bu yüzden bugün böyle bir kavramdan bahsedeceğiz - AOP, diğer adıyla en-boy yönelimli programlama . AOP nedir?  En-boy yönelimli programlamanın ilkeleri - 1Bu konu kolay değildir ve nadiren doğrudan kullanılır, ancak birçok çerçeve ve teknoloji bunu gizli kullanır. Ve elbette, bazen görüşmeler sırasında, bunun ne tür bir canavar olduğunu ve nerelerde uygulanabileceğini genel terimlerle açıklamanız istenebilir. Öyleyse, Java'daki AOP'nin temel kavramlarına ve bazı basit örneklerine bir göz atalım . Şimdi, AOP en boy yönelimli programlama anlamına gelirKesişen kaygıları ayırarak bir uygulamanın farklı bölümlerinin modülerliğini artırmayı amaçlayan bir paradigmadır. Bunu başarmak için, orijinal kodda değişiklik yapılmadan mevcut koda ek davranış eklenir. Başka bir deyişle, değiştirilen kodu değiştirmeden, yöntemlerin ve sınıfların üzerine ek işlevler asmak gibi düşünebiliriz. Bu neden gerekli? Er ya da geç, tipik nesne yönelimli yaklaşımın belirli sorunları her zaman etkili bir şekilde çözemeyeceği sonucuna varırız. Ve o an geldiğinde, AOP imdada yetişir ve uygulama oluşturmak için bize ek araçlar verir. Ve ek araçlar, yazılım geliştirmede daha fazla esneklik anlamına gelir, bu da belirli bir sorunu çözmek için daha fazla seçenek anlamına gelir.

AOP'yi uygulama

Görünüş yönelimli programlama, tamamen ayrı bir modülde yapılandırılamayan, farklı yöntemlerle birçok kez tekrarlanabilen herhangi bir kod olabilen, kesişen görevleri gerçekleştirmek için tasarlanmıştır. Buna göre AOP , bunu ana kodun dışında tutmamıza ve dikey olarak bildirmemize izin verir. Bir örnek, bir uygulamada bir güvenlik ilkesi kullanmaktır. Tipik olarak güvenlik, bir uygulamanın birçok öğesinden geçer. Ayrıca uygulamanın güvenlik politikası, uygulamanın mevcut ve yeni tüm bölümlerine eşit olarak uygulanmalıdır. Aynı zamanda, kullanımda olan bir güvenlik politikası da gelişebilir. Burası AOP kullanmak için mükemmel bir yer . Ayrıca başka bir örnek de günlük kaydıdır.. Günlüğe kaydetme işlevini manuel olarak eklemek yerine, günlüğe kaydetme için AOP yaklaşımını kullanmanın birkaç avantajı vardır:
  1. Günlüğe kaydetme kodunu eklemek ve kaldırmak kolaydır: yapmanız gereken tek şey, bazı açılardan birkaç yapılandırma eklemek veya kaldırmaktır.

  2. Günlüğe kaydetme için tüm kaynak kodu tek bir yerde tutulur, bu nedenle kullanıldığı tüm yerleri manuel olarak aramanıza gerek yoktur.

  3. Günlüğe kaydetme kodu, önceden yazılmış yöntemlerde ve sınıflarda veya yeni işlevlerde herhangi bir yere eklenebilir. Bu, kodlama hatalarının sayısını azaltır.

    Ayrıca, bir tasarım yapılandırmasından bir yönü kaldırırken, tüm izleme kodunun kaybolduğundan ve hiçbir şeyin gözden kaçmadığından emin olabilirsiniz.

  4. Yönler, geliştirilebilen ve tekrar tekrar kullanılabilen ayrı kodlardır.
AOP nedir?  En boy yönelimli programlamanın ilkeleri - 2AOP ayrıca istisna işleme, önbelleğe alma ve yeniden kullanılabilir hale getirmek için belirli işlevleri ayıklamak için kullanılır.

AOP'nin temel ilkeleri

Bu konuda daha fazla ilerlemek için önce AOP'nin ana kavramlarını tanıyalım. Tavsiye — Bir birleştirme noktasından çağrılan ek mantık veya kod. Tavsiye, bir birleştirme noktasından önce, sonra veya onun yerine yapılabilir (bunlar hakkında aşağıda daha fazla bilgi verilmektedir). Olası tavsiye türleri :
  1. Önce — bu tür tavsiyeler, hedef yöntemler, yani birleştirme noktaları yürütülmeden önce başlatılır. Yönleri sınıf olarak kullanırken, tavsiyeyi daha önce geliyor olarak işaretlemek için @Before ek açıklamasını kullanırız . Açıları .aj dosyaları olarak kullanırken , bu before() yöntemi olacaktır .

  2. After — hem normal yürütmede hem de bir istisna fırlatırken yöntemlerin yürütülmesi (birleştirme noktaları) tamamlandıktan sonra yürütülen tavsiye.

    Görünümleri sınıf olarak kullanırken, @After ek açıklamasını bunun ardından gelen bir tavsiye olduğunu belirtmek için kullanabiliriz .

    Açıları .aj dosyaları olarak kullanırken , bu after() yöntemidir.

  3. Döndükten Sonra — bu tavsiye yalnızca hedef yöntem hatasız ve normal şekilde bittiğinde gerçekleştirilir.

    Yönler sınıflar olarak temsil edildiğinde, tavsiyeyi başarılı bir şekilde tamamlandıktan sonra yürütülüyor olarak işaretlemek için @AfterReturning ek açıklamasını kullanabiliriz .

    Görünümleri .aj dosyaları olarak kullanırken , bu after() döndürme (Object obj) yöntemi olacaktır .

  4. Fırlattıktan Sonra — bu tavsiye, bir yöntemin, yani birleştirme noktasının bir istisna oluşturduğu durumlar için tasarlanmıştır. Bu tavsiyeyi, belirli türden başarısız yürütmeleri halletmek için kullanabiliriz (örneğin, tüm bir işlemi geri almak veya gerekli izleme düzeyiyle günlüğe kaydetmek için).

    Sınıf yönleri için, @AfterThrowing ek açıklaması, bu tavsiyenin bir istisna attıktan sonra kullanıldığını belirtmek için kullanılır.

    Görünümleri .aj dosyaları olarak kullanırken , bu after() fırlatma (Exception e) yöntemi olacaktır .

  5. Etrafında - belki de en önemli tavsiye türlerinden biri. Bir yöntemi, yani örneğin belirli bir birleştirme noktası yöntemini uygulayıp uygulamamayı seçmek için kullanabileceğimiz bir birleştirme noktasını çevreler.

    Birleştirme noktası yöntemi yürütülmeden önce ve sonra çalışan tavsiye kodu yazabilirsiniz.

    Çevre tavsiyesi, birleştirme noktası yöntemini ve yöntem bir şey döndürürse dönüş değerlerini çağırmaktan sorumludur. Başka bir deyişle, bu tavsiyede, bir hedef yöntemin çalışmasını çağırmadan basit bir şekilde simüle edebilir ve dönüş sonucu olarak istediğiniz şeyi döndürebilirsiniz.

    Sınıflar olarak verilen yönler, bir birleştirme noktasını saran tavsiyeler oluşturmak için @Around ek açıklamasını kullanırız . .aj dosyaları biçimindeki görünümleri kullanırken , bu yöntem around() yöntemi olacaktır .

Katılım Noktası — tavsiyenin uygulanması gereken çalışan bir programdaki nokta (yani yöntem çağrısı, nesne oluşturma, değişken erişimi). Başka bir deyişle, bu, kod enjeksiyonu için yerleri (tavsiyenin uygulanması gereken yerler) bulmak için kullanılan bir tür düzenli ifadedir. Pointcut — bir dizi birleştirme noktası . Pointcut, verilen tavsiyenin belirli bir birleştirme noktasına uygulanabilir olup olmadığını belirler. Aspect — kesişen işlevsellik uygulayan bir modül veya sınıf. Aspect, bazı pointcut tarafından tanımlanan birleştirme noktalarında tavsiye uygulayarak kalan kodun davranışını değiştirir . Başka bir deyişle, tavsiye ve katılma noktalarının birleşimidir. giriiş— bir sınıfın yapısını değiştirmek ve/veya yönün işlevselliğini yabancı koda eklemek için kalıtım hiyerarşisini değiştirmek. Hedef — tavsiyenin uygulanacağı nesne. Dokuma - önerilen proxy nesneleri oluşturmak için yönleri diğer nesnelere bağlama işlemi. Bu, derleme zamanında, yükleme zamanında veya çalışma zamanında yapılabilir. Üç çeşit dokuma vardır:
  • Derleme zamanı dokuması — yönün kaynak koduna ve yönü kullandığınız koda sahipseniz, kaynak kodunu ve yönü doğrudan AspectJ derleyicisini kullanarak derleyebilirsiniz;

  • Derleme sonrası dokuma (ikili dokuma) — yönleri koda örmek için kaynak kodu dönüşümlerini kullanamıyorsanız veya kullanmak istemiyorsanız, önceden derlenmiş sınıfları veya jar dosyalarını alabilir ve bunlara görünümler ekleyebilirsiniz;

  • Yükleme zamanı dokuması — bu yalnızca, sınıf yükleyici sınıf dosyasını yükleyene ve JVM için sınıfı tanımlayana kadar ertelenen ikili dokumadır.

    Bunu desteklemek için bir veya daha fazla dokuma sınıfı yükleyicisi gerekir. Bunlar ya açıkça çalışma zamanı tarafından sağlanır ya da bir "dokuma aracısı" tarafından etkinleştirilir.

AspectJ — Kesişen görevleri gerçekleştirme becerisini uygulayan AOP paradigmasının özel bir uygulaması . Dokümantasyon burada bulunabilir .

Java'daki örnekler

Ardından, AOP'yi daha iyi anlamak için "Merhaba Dünya" tarzı küçük örneklere bakacağız. En başta, örneklerimizin derleme zamanı dokumasını kullanacağını not edeceğim . Öncelikle pom.xml dosyamıza aşağıdaki bağımlılığı eklememiz gerekiyor :
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjrt</artifactId>
  <version>1.9.5</version>
</dependency>
Kural olarak, özel ajc derleyicisi, yönleri nasıl kullandığımızdır. IntelliJ IDEA bunu varsayılan olarak içermez, bu nedenle onu uygulama derleyicisi olarak seçerken 5168 75 AspectJ dağıtımına giden yolu belirtmeniz gerekir. Bu ilk yoldu. Kullandığım ikincisi, aşağıdaki eklentiyi pom.xml dosyasına kaydetmektir:
<build>
  <plugins>
     <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>aspectj-maven-plugin</artifactId>
        <version>1.7</version>
        <configuration>
           <complianceLevel>1.8</complianceLevel>
           <source>1.8</source>
           <target>1.8</target>
           <showWeaveInfo>true</showWeaveInfo>
           <<verbose>true<verbose>
           <Xlint>ignore</Xlint>
           <encoding>UTF-8</encoding>
        </configuration>
        <executions>
           <execution>
              <goals>
                 <goal>compile</goal>
                 <goal>test-compile</goal>
              </goals>
           </execution>
        </executions>
     </plugin>
  </plugins>
</build>
Bundan sonra, Maven'den yeniden içe aktarma yapmak ve mvn clean derlemesini çalıştırmak iyi bir fikirdir . Şimdi doğrudan örneklere geçelim.

Örnek 1

Bir Ana sınıf oluşturalım . İçinde, bir giriş noktamız ve konsolda geçirilen bir adı yazdıran bir yöntemimiz olacak:
public class Main {

  public static void main(String[] args) {
  printName("Tanner");
  printName("Victor");
  printName("Sasha");
  }

  public static void printName(String name) {
     System.out.println(name);
  }
}
Burada karmaşık bir şey yok. Bir isim geçtik ve onu konsolda gösterdik. Programı şimdi çalıştırırsak, konsolda aşağıdakileri görürüz:
Tanner Victor Sasha
Şimdi AOP'nin gücünden yararlanma zamanı. Şimdi bir görünüş dosyası oluşturmamız gerekiyor . İki türdendirler: ilki .aj dosya uzantısına sahiptir. İkincisi, AOP yeteneklerini uygulamak için açıklamaları kullanan sıradan bir sınıftır. Önce .aj uzantılı dosyaya bakalım :
public aspect GreetingAspect {

  pointcut greeting() : execution(* Main.printName(..));

  before() : greeting() {
     System.out.print("Hi, ");
  }
}
Bu dosya bir çeşit sınıf gibidir. Bakalım burada neler oluyor: pointcut, birleştirme noktaları kümesidir; tebrik() bu noktasal kesimin adıdır; : yürütme, Main.printName(...) yönteminin tüm ( * ) çağrılarının yürütülmesi sırasında uygulanmasını belirtir . Daha sonra , hedef yöntem çağrılmadan önce yürütülen özel bir tavsiye — before() — gelir. : tebrik(), bu tavsiyenin yanıt verdiği kesme noktasıdır. Aşağıda, anladığımız Java dilinde yazılmış yöntemin gövdesini görüyoruz. Bu özellik mevcutken main'i çalıştırdığımızda , şu konsol çıktısını alacağız:
Merhaba, Tanner Merhaba, Victor Merhaba, Sasha
printName yöntemine yapılan her çağrının bir özellik sayesinde değiştirildiğini görebiliriz . Şimdi, ek açıklamalar içeren bir Java sınıfı olarak yönün nasıl görüneceğine bir göz atalım:
@Aspect
public class GreetingAspect{

  @Pointcut("execution(* Main.printName(String))")
  public void greeting() {
  }

  @Before("greeting()")
  public void beforeAdvice() {
     System.out.print("Hi, ");
  }
}
.aj en boy dosyasından sonra , burada her şey daha belirgin hale gelir:
  • @Aspect, bu sınıfın bir özellik olduğunu belirtir;
  • @Pointcut("execution(* Main.printName(String))"), türü String olan bir giriş bağımsız değişkeni ile Main.printName'e yapılan tüm çağrılar için tetiklenen kesme noktasıdır ;
  • @Before("selamlama()"), tebrik() kesme noktasında belirtilen kodu çağırmadan önce uygulanan tavsiyedir .
Main'i bu yönüyle çalıştırmak , konsol çıktısını değiştirmez:
Merhaba, Tanner Merhaba, Victor Merhaba, Sasha

Örnek 2

Müşteriler için bazı işlemleri gerçekleştiren bir yöntemimiz olduğunu varsayalım ve bu yöntemi main'den çağırıyoruz :
public class Main {

  public static void main(String[] args) {
  performSomeOperation("Tanner");
  }

  public static void performSomeOperation(String clientName) {
     System.out.println("Performing some operations for Client " + clientName);
  }
}
Bir "sözde işlem" oluşturmak için @Around ek açıklamasını kullanalım :
@Aspect
public class TransactionAspect{

  @Pointcut("execution(* Main.performSomeOperation(String))")
  public void executeOperation() {
  }

  @Around(value = "executeOperation()")
  public void beforeAdvice(ProceedingJoinPoint joinPoint) {
     System.out.println("Opening a transaction...");
     try {
        joinPoint.proceed();
        System.out.println("Closing a transaction...");
     }
     catch (Throwable throwable) {
        System.out.println("The operation failed. Rolling back the transaction...");
     }
  }
  }
ProceedingJoinPoint nesnesinin devam yöntemi ile tavsiyedeki yerini belirlemek için sarma yöntemini çağırıyoruz. Bu nedenle, yukarıdaki yöntemdeki kod joinPoint.proceed(); Önce'dir , altındaki kod ise Sonra'dır . main komutunu çalıştırırsak , bunu konsolda alırız:
İşlem açılıyor... Müşteri Tanner için bazı işlemler yapılıyor İşlem kapatılıyor...
Ancak, yöntemimizde bir istisna atarsak (başarısız bir işlemi simüle etmek için):
public static void performSomeOperation(String clientName) throws Exception {
  System.out.println("Performing some operations for Client " + clientName);
  throw new Exception();
}
Sonra şu konsol çıktısını alırız:
İşlem açılıyor... Client Tanner için bazı işlemler yapılıyor İşlem başarısız oldu. İşlem geri alınıyor...
Yani burada elde ettiğimiz şey, bir tür hata işleme yeteneğidir.

Örnek 3

Bir sonraki örneğimizde, konsola giriş yapmak gibi bir şey yapalım. Önce, sözde iş mantığı eklediğimiz Main'e bir göz atın :
public class Main {
  private String value;

  public static void main(String[] args) throws Exception {
     Main main = new Main();
     main.setValue("<some value>");
     String valueForCheck = main.getValue();
     main.checkValue(valueForCheck);
  }

  public void setValue(String value) {
     this.value = value;
  }

  public String getValue() {
     return this.value;
  }

  public void checkValue(String value) throws Exception {
     if (value.length() > 10) {
        throw new Exception();
     }
  }
}
main içinde , değer örneği değişkenine bir değer atamak için setValue kullanırız . Sonra değeri almak için getValue'yu kullanırız ve ardından 10 karakterden uzun olup olmadığını görmek için checkValue'u çağırırız. Eğer öyleyse, o zaman bir istisna atılacaktır. Şimdi metotların çalışmasını loglamak için kullanacağımız yönüne bakalım:
@Aspect
public class LogAspect {

  @Pointcut("execution(* *(..))")
  public void methodExecuting() {
  }

  @AfterReturning(value = "methodExecuting()", returning = "returningValue")
  public void recordSuccessfulExecution(JoinPoint joinPoint, Object returningValue) {
     if (returningValue != null) {
        System.out.printf("Successful execution: method — %s method, class — %s class, return value — %s\n",
              joinPoint.getSignature().getName(),
              joinPoint.getSourceLocation().getWithinType().getName(),
              returningValue);
     }
     else {
        System.out.printf("Successful execution: method — %s, class — %s\n",
              joinPoint.getSignature().getName(),
              joinPoint.getSourceLocation().getWithinType().getName());
     }
  }

  @AfterThrowing(value = "methodExecuting()", throwing = "exception")
  public void recordFailedExecution(JoinPoint joinPoint, Exception exception) {
     System.out.printf("Exception thrown: method — %s, class — %s, exception — %s\n",
           joinPoint.getSignature().getName(),
           joinPoint.getSourceLocation().getWithinType().getName(),
           exception);
  }
}
Burada neler oluyor? @Pointcut("execution(* *(..))") tüm yöntemlerin tüm çağrılarına katılacak. @AfterReturning(value = "methodExecuting()", return = "returningValue"), hedef yöntemin başarıyla yürütülmesinden sonra yürütülecek tavsiyedir. Burada iki durumumuz var:
  1. Yöntemin bir dönüş değeri olduğunda — if (returningValue! = Null) {
  2. Dönen değer olmadığında — başka {
@AfterThrowing(value = "methodExecuting()", throw = "exception"), bir hata durumunda, yani yöntem bir istisna oluşturduğunda tetiklenecek bir tavsiyedir. Ve buna göre, main komutunu çalıştırarak , bir tür konsol tabanlı günlük kaydı elde edeceğiz:
Başarılı yürütme: method — setValue, class — Main Başarılı yürütme: method — getValue, class — Main, dönüş değeri — <bir değer> Oluşturulan istisna: yöntem — checkValue, class — Ana istisna — java.lang.Exception Oluşturulan İstisna: yöntem — main, class — Main, istisna — java.lang.Exception
İstisnaları işlemediğimiz için, yine de bir yığın izleme elde edeceğiz: AOP nedir?  En boy yönelimli programlamanın ilkeleri - 3İstisnalar ve istisna işleme hakkında şu makaleleri okuyabilirsiniz: Java'da İstisnalar ve İstisnalar: yakalama ve işleme . Bugün benim için hepsi bu. Bugün AOP ile tanıştık ve bu canavarın bazılarının sandığı kadar korkunç olmadığını görebildiniz. Hepiniz hoşçakalın!
Yorumlar
  • Popüler
  • Yeni
  • Eskimiş
Yorum bırakmak için giriş yapmalısınız
Bu sayfada henüz yorum yok