Rumah Java javaTutorial Membongkar Kerja Dalaman Spring AOP

Membongkar Kerja Dalaman Spring AOP

Sep 07, 2024 am 06:34 AM

Unveiling the Inner Workings of Spring AOP

Dalam siaran ini, kami akan menyahmistifikasi mekanik dalaman Pengaturcaraan Berorientasikan Aspek (AOP) pada Musim Bunga. Tumpuan akan diberikan pada memahami cara AOP mencapai kefungsian seperti pengelogan, sering dianggap sebagai satu bentuk "ajaib". Dengan menelusuri pelaksanaan teras Java, kita akan melihat bagaimana semuanya tentang pantulan Java, corak proksi dan anotasi dan bukannya apa-apa yang benar-benar ajaib.

Prasyarat

  • API Proksi Teras Java
  • API Refleksi
  • API Anotasi

Ini semua adalah sebahagian daripada pakej java.lang.reflect, java.lang.annotation dan javassist.util.proxy.

Mekanisme Teras

Di tengah-tengah Spring AOP terletak konsep objek proksi, pemintas kaedah dan pantulan. Pemain utama dalam corak ini ialah MethodHandler (atau pengendali invocation). Pengendali ini mengawal kelakuan objek proksi dengan memintas panggilan kaedah. Apabila kaedah digunakan pada proksi, ia akan dihantar melalui pengendali, di mana anotasi boleh disemak melalui refleksi. Berdasarkan anotasi yang digunakan, logik yang diperlukan (cth., pengelogan) boleh dilaksanakan sebelum, selepas, atau kecuali.

Memecahkannya

  1. Objek Proksi: Ini ialah objek yang dicipta secara dinamik yang sesuai untuk objek perniagaan sebenar anda, menghalakan panggilan kaedah melalui pengendali kaedah.
  2. Pengendali Invocation: Di sinilah keajaiban pemintasan berlaku. Menggunakan refleksi, pengendali boleh memeriksa anotasi yang terdapat pada kaedah sasaran dan mengubah tingkah laku sewajarnya.
  3. Anotasi Tersuai: Anda boleh menentukan anotasi tersuai, yang berfungsi sebagai penanda untuk mencetuskan fungsi tambahan seperti pengelogan, semakan keselamatan atau pengurusan transaksi.

Contoh: Katakan kita ingin menambah pengelogan sebelum dan selepas pelaksanaan kaedah tertentu. Daripada pengelogan pengekodan keras di mana-mana, kami boleh menganotasi kaedah dengan @BeforeMethod dan @AfterMethod. Pengendali kami memeriksa kaedah untuk anotasi ini dan menambahkan logik pengelogan yang sesuai secara dinamik.

Di bawah ialah kelas bagaimana Pengawal dan Perkhidmatan kelihatan seperti contoh kami.

WorkerController.java

package edu.pk.poc.aop.controller;

import edu.pk.poc.aop.annotation.AfterMethod;
import edu.pk.poc.aop.annotation.All;
import edu.pk.poc.aop.annotation.BeforeMethod;
import edu.pk.poc.aop.helper.ProxyFactory;
import edu.pk.poc.aop.service.Worker;
import edu.pk.poc.aop.service.WorkerService;
import edu.pk.poc.aop.service.WorkerServiceImpl;

public class WorkerController {
    WorkerService workerService = ProxyFactory.createProxy(WorkerServiceImpl.class);
    /**
     * This Method 1s annotated with @BeforeMethod and @AfterMethod, So the log statements
     * will be generated before and after method call.
     */
    @BeforeMethod
    @AfterMethod
    public void engageFullTimeWorker() throws Exception {
        Worker fullTimeWorker = new Worker();
        fullTimeWorker.setName("FullTime-Worker");
        fullTimeWorker.setPartTime(false);
        fullTimeWorker.setDuration(9);
        workerService.doWork(fullTimeWorker);
    }
    /**
     * This Method is annotated with @All, So the log statements will be generated before and after method call
     * along with exception if raised.
     */
    @All
    public void engagePartTimeWorker() throws Exception {
        Worker partTimeWorker = new Worker();
        partTimeWorker.setName("PartTime-Worker");
        partTimeWorker.setPartTime(true);
        partTimeWorker.setDuration(4);
        workerService.doWork(partTimeWorker);
    }
}
Salin selepas log masuk

WorkerServiceImpl.java

package edu.pk.poc.aop.service;

import edu.pk.poc.aop.annotation.AfterMethod;

public class WorkerServiceImpl implements WorkerService {
    /**
     * Here this method is annotated with only @AfterMethod, So only log statement
     * will be generated after method call
     */
    @AfterMethod
    @Override
    public void doWork(Worker worker) throws Exception {
        if (worker.isPartTime()) {
            throw new Exception("Part time workers are not permitted to work.");
        }
        System.out.print("A full time worker is working for " + worker.getDuration() + " hours :: ");
        for (int i = 1; i < worker.getDuration(); i++) {
            System.out.print("* ");
        }
        System.out.println();
    }
}
Salin selepas log masuk

Kelas ujian Main.java

package edu.pk.poc.aop.test;

import edu.pk.poc.aop.controller.WorkerController;
import edu.pk.poc.aop.helper.ProxyFactory;
import edu.pk.util.Logger;

public class Main {
    public static void main(String[] args) {
        WorkerController controller = ProxyFactory.createProxy(WorkerController.class);
        Logger logger = new Logger();
        try {
            System.out.println("Testing @BeforeMethod and @AfterMethod");
            System.out.println("-----------------------------------------");
            controller.engageFullTimeWorker();
            System.out.println("Testing @All");
            System.out.println("-----------------------------------------");
            controller.engagePartTimeWorker();
        } catch (Exception e) {
            logger.error("Exception caught in Main class");
        }
    }
}
Salin selepas log masuk

Output

Testing @BeforeMethod and @AfterMethod
-----------------------------------------
>>> Entering into edu.pk.poc.aop.controller.WorkerController.engageFullTimeWorker()
A full time worker is working for 9 hours :: * * * * * * * * 
>>> Exiting from edu.pk.poc.aop.service.WorkerServiceImpl.doWork()
>>> Exiting from edu.pk.poc.aop.controller.WorkerController.engageFullTimeWorker()
Testing @All
-----------------------------------------
>>> Entering into edu.pk.poc.aop.controller.WorkerController.engagePartTimeWorker()
>>> Exception in edu.pk.poc.aop.controller.WorkerController.engagePartTimeWorker()
Exception caught in Main class
Salin selepas log masuk

Bagaimana Ia Berfungsi

Apabila kaedah digunakan pada objek proksi, panggilan dipintas oleh pengendali, yang menggunakan pantulan untuk memeriksa semua anotasi pada kaedah sasaran. Berdasarkan anotasi tersebut, pengendali memutuskan sama ada untuk log masuk/keluar kaedah, log pengecualian atau langkau pengelogan sama sekali.

Begini cara anda boleh memvisualisasikannya:

  • Sebelum Pelaksanaan: Log masukan kaedah.
  • Selepas Pelaksanaan: Log keluar kaedah atau kejayaan.
  • Semua: Log masukan kaedah, kemasukan kaedah dan pengecualian jika dinaikkan. Tingkah laku dinamik ini menunjukkan bahawa Spring AOP memanfaatkan teras Java API daripada menggunakan beberapa helah ajaib.

Tentukan Anotasi

package edu.pk.poc.aop.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AfterMethod {

}
Salin selepas log masuk
package edu.pk.poc.aop.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface BeforeMethod {

}
Salin selepas log masuk
package edu.pk.poc.aop.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface All {

}
Salin selepas log masuk

Tentukan Kilang Proksi

package edu.pk.poc.aop.helper;

/**
 * The {@code ProxyFactory} class is responsible for creating proxy objects using the Javassist library.
 * It allows for dynamic generation of proxies for classes or interfaces, with support for method interception.
 */
public class ProxyFactory {

    /**
     * A Javassist ProxyFactory instance used to generate proxy classes.
     */
    private static final javassist.util.proxy.ProxyFactory factory = new javassist.util.proxy.ProxyFactory();

    /**
     * Creates a proxy object for the given class or interface.
     * If the class is an interface, the proxy implements the interface.
     * If it's a concrete class, the proxy extends the class.
     *
     * @param <T>   the type of the class or interface for which the proxy is to be created
     * @param klass the {@code Class} object representing the class or interface to proxy
     * @return a proxy instance of the specified class or interface, or {@code null} if proxy creation fails
     */
    public static <T> T createProxy(Class<T> klass) {
        if (klass.isInterface())
            factory.setInterfaces(new Class[]{klass});
        else
            factory.setSuperclass(klass);
        try {
            return (T) factory.create(new Class<?>[0], new Object[0], new AOPLoggingMethodHandler());
        } catch (Exception e) {
            System.err.println(e.getMessage());
        }
        return null;
    }
}
Salin selepas log masuk

Tentukan MethodHandler

package edu.pk.poc.aop.helper;

import edu.pk.poc.aop.annotation.AfterMethod;
import edu.pk.poc.aop.annotation.All;
import edu.pk.poc.aop.annotation.BeforeMethod;
import edu.pk.poc.aop.annotation.OnException;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import edu.pk.util.Logger;
import javassist.util.proxy.MethodHandler;

public class AOPLoggingMethodHandler implements MethodHandler {

    private static final Logger logger = new Logger();

    public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
        if (proceed != null) { // Concrete Method
            Object result = null;
            String className = resolveClassName(self);
            try {
                if (isAnnotationPresent(thisMethod, BeforeMethod.class) || isAnnotationPresent(thisMethod, All.class)) {
                    logger.info(">>> Entering into " + className + "." + thisMethod.getName() + "()");
                }
                result = proceed.invoke(self, args);
                if (isAnnotationPresent(thisMethod, AfterMethod.class) || isAnnotationPresent(thisMethod, All.class)) {
                    logger.info(">>> Exiting from " + className + "." + thisMethod.getName() + "()");
                }
            } catch (Throwable t) {
                if (isAnnotationPresent(thisMethod, OnException.class) || isAnnotationPresent(thisMethod, All.class)) {
                    logger.error(">>> Exception in " + className + "." + thisMethod.getName() + "()");
                }
                throw t;
            }
            return result;
        }
        throw new RuntimeException("Method is Abstract");
    }

    private boolean isAnnotationPresent(Method method, Class klass) {
        Annotation[] declaredAnnotationsByType = method.getAnnotationsByType(klass);
        return declaredAnnotationsByType != null && declaredAnnotationsByType.length > 0;
    }

    private String resolveClassName(Object self) {
        String className = self.getClass().getName();
        if (className.contains("_$$")) {
            className = className.substring(0, className.indexOf("_$$"));
        }
        return className;
    }
}
Salin selepas log masuk

Kesimpulan

Spring AOP ialah alat yang berkuasa untuk merentasi kebimbangan, tetapi ia tidak melakukan sesuatu yang revolusioner. Ia dibina di atas konsep teras Java seperti refleksi dan proksi, yang tersedia dalam bahasa itu sendiri. Dengan memahami perkara ini, anda boleh lebih menghargai cara Spring memudahkan mekanik peringkat rendah ini untuk kemudahan pembangun.

Atas ialah kandungan terperinci Membongkar Kerja Dalaman Spring AOP. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

Video Face Swap

Video Face Swap

Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Artikel Panas

<🎜>: Bubble Gum Simulator Infinity - Cara Mendapatkan dan Menggunakan Kekunci Diraja
4 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌
Nordhold: Sistem Fusion, dijelaskan
4 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌
Mandragora: Whispers of the Witch Tree - Cara Membuka Kunci Cangkuk Bergelut
3 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌

Alat panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas

Tutorial Java
1671
14
Tutorial PHP
1276
29
Tutorial C#
1256
24
Adakah perisian keselamatan syarikat menyebabkan aplikasi gagal dijalankan? Bagaimana cara menyelesaikan masalah dan menyelesaikannya? Adakah perisian keselamatan syarikat menyebabkan aplikasi gagal dijalankan? Bagaimana cara menyelesaikan masalah dan menyelesaikannya? Apr 19, 2025 pm 04:51 PM

Penyelesaian masalah dan penyelesaian kepada perisian keselamatan syarikat yang menyebabkan beberapa aplikasi tidak berfungsi dengan baik. Banyak syarikat akan menggunakan perisian keselamatan untuk memastikan keselamatan rangkaian dalaman. …

Bagaimanakah saya menukar nama kepada nombor untuk melaksanakan penyortiran dan mengekalkan konsistensi dalam kumpulan? Bagaimanakah saya menukar nama kepada nombor untuk melaksanakan penyortiran dan mengekalkan konsistensi dalam kumpulan? Apr 19, 2025 pm 11:30 PM

Penyelesaian untuk menukar nama kepada nombor untuk melaksanakan penyortiran dalam banyak senario aplikasi, pengguna mungkin perlu menyusun kumpulan, terutama dalam satu ...

Bagaimana untuk memudahkan isu pemetaan medan dalam dok sistem menggunakan mapstruct? Bagaimana untuk memudahkan isu pemetaan medan dalam dok sistem menggunakan mapstruct? Apr 19, 2025 pm 06:21 PM

Pemprosesan pemetaan medan dalam dok sistem sering menemui masalah yang sukar ketika melaksanakan sistem dok: bagaimana untuk memetakan medan antara muka sistem dengan berkesan ...

Bagaimanakah Idea IntelliJ mengenal pasti nombor port projek boot musim bunga tanpa mengeluarkan log? Bagaimanakah Idea IntelliJ mengenal pasti nombor port projek boot musim bunga tanpa mengeluarkan log? Apr 19, 2025 pm 11:45 PM

Mula musim bunga menggunakan versi IntelliJideaultimate ...

Bagaimana dengan elegan mendapatkan nama pemboleh ubah kelas entiti untuk membina keadaan pertanyaan pangkalan data? Bagaimana dengan elegan mendapatkan nama pemboleh ubah kelas entiti untuk membina keadaan pertanyaan pangkalan data? Apr 19, 2025 pm 11:42 PM

Apabila menggunakan Mybatis-Plus atau Rangka Kerja ORM yang lain untuk operasi pangkalan data, sering diperlukan untuk membina syarat pertanyaan berdasarkan nama atribut kelas entiti. Sekiranya anda secara manual setiap kali ...

Bagaimana cara menukar objek Java dengan selamat ke array? Bagaimana cara menukar objek Java dengan selamat ke array? Apr 19, 2025 pm 11:33 PM

Penukaran objek dan tatasusunan Java: Perbincangan mendalam tentang risiko dan kaedah penukaran jenis cast yang betul Banyak pemula Java akan menemui penukaran objek ke dalam array ...

Platform e-dagang SKU dan Reka Bentuk Pangkalan Data SPU: Bagaimana untuk mengambil kira kedua-dua atribut yang ditakrifkan oleh pengguna dan produk yang tidak berkesudahan? Platform e-dagang SKU dan Reka Bentuk Pangkalan Data SPU: Bagaimana untuk mengambil kira kedua-dua atribut yang ditakrifkan oleh pengguna dan produk yang tidak berkesudahan? Apr 19, 2025 pm 11:27 PM

Penjelasan terperinci mengenai reka bentuk jadual SKU dan SPU di platform e-dagang Artikel ini akan membincangkan isu reka bentuk pangkalan data SKU dan SPU dalam platform e-dagang, terutamanya bagaimana menangani jualan yang ditentukan pengguna ...

Bagaimana menggunakan penyelesaian cache Redis untuk merealisasikan keperluan senarai kedudukan produk dengan cekap? Bagaimana menggunakan penyelesaian cache Redis untuk merealisasikan keperluan senarai kedudukan produk dengan cekap? Apr 19, 2025 pm 11:36 PM

Bagaimanakah penyelesaian caching Redis menyedari keperluan senarai kedudukan produk? Semasa proses pembangunan, kita sering perlu menangani keperluan kedudukan, seperti memaparkan ...

See all articles