2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Välityspalvelin viittaa tilaan, jossa objektilla A voi toimia samalla tavalla kuin B:llä pitämällä toista objektia B. Avatakseen protokollan ulkomaailmalle B toteuttaa usein rajapinnan ja A myös toteuttaa rajapinnan. Mutta B on "todellinen" toteutusluokka, kun taas A on enemmän "virtuaali". Se lainaa B:n menetelmiä käyttöliittymämenetelmien toteuttamiseen. Vaikka A on "pseudoarmeija", se voi parantaa B:tä ja tehdä muita asioita ennen B:n menetelmän kutsumista ja sen jälkeen. Spring AOP käyttää dynaamisia välityspalvelimia täydentämään koodin dynaamista "kudontaa".
Välityspalvelimen käytön edut menevät tätä pidemmälle, jos projekti perustuu toisen projektin tarjoamaan käyttöliittymään, mutta toisen projektin käyttöliittymä on epävakaa ja protokollaa muutetaan usein, voit käyttää välityspalvelinta tarvitsee vain muokata välityspalvelinta, ei yksitellen. Tässä mielessä voimme tehdä tämän kaikille rajapinnoille, jotka mukautuvat ulkomaailmaan estääksemme ulkopuolista koodia tunkeutumasta koodiimme. Tätä kutsutaan puolustusohjelmoimiseksi. Välityspalvelimelle voi olla monia muita sovelluksia.
Yllä olevassa esimerkissä luokka A on koodattu pitämään B:tä, joka on B:n staattinen välityspalvelin. Jos A-välityspalvelimen kohde on epävarma, se on dynaaminen välityspalvelin. Dynaamisesta välityspalvelimesta on tällä hetkellä kaksi yleistä toteutusta, jdk dynaaminen välityspalvelin ja cglib dynaaminen välityspalvelin.
Staattinen välityspalvelin on suunnittelukuvio ja välityspalvelimen tyyppi. Staattisessa välityspalvelimessa välityspalvelinluokka on määritetty ennen ohjelman suorittamista, ja välityspalvelinluokan ja välityspalvelinluokan välinen suhde määritetään käännöshetkellä. Tämä tarkoittaa, että sekä välityspalvelinluokka että välityspalvelinluokka toteuttavat saman rajapinnan tai perivät saman pääluokan. Välityspalvelinluokka pitää sisällään välityspalvelinluokan esiintymän ja kutsuu samalla välityspalvelinluokan menetelmiä , se voi lisätä joitain omia toimintojasi ennen puhelua ja sen jälkeen, kuten kirjaamisen, lupien tarkistuksen, tapahtumien käsittelyn jne.
Staattisella välityspalvelimella on kolme osaa: abstrakti käyttöliittymä, välityspalvelinluokka ja välityspalvelinluokka. Sen toteutusesimerkit ovat seuraavat:
- public interface TargetInteface {
- void method1();
- void method2();
- int method3(Integer i);
- }
- public class TargetProxy implements TargetInteface {
-
- private Target target =new Target();
- @Override
- public void method1() {
- System.out.println("执行方法前...");
- target.method1();
- System.out.println("执行方法后...");
- }
-
- @Override
- public void method2() {
- System.out.println("执行方法前...");
- target.method2();
- System.out.println("执行方法后...");
- }
-
- @Override
- public int method3(Integer i) {
- System.out.println("执行方法前...");
- int method3 = target.method3(i);
- System.out.println("执行方法后...");
- return method3;
- }
- }
- public class Target implements TargetInteface {
- @Override
- public void method1() {
- System.out.println(" Target method1 running ...");
- }
-
- @Override
- public void method2() {
- System.out.println("Target method2 running ...");
- }
-
- @Override
- public int method3(Integer i) {
- System.out.println("Target method3 running ...");
- return i;
- }
- }
- public class TargetUser {
-
- public static void main(String[] args) {
- TargetInteface target = new TargetProxy();
- target.method1();
- System.out.println("-----------------------------");
- target.method2();
- System.out.println("-----------------------------");
- System.out.println(target.method3(3));
- }
- }
Tulostulos:
Ennen menetelmän suorittamista...
Kohdemenetelmä1 käynnissä...
Menetelmän suorittamisen jälkeen...
-----------------------------
Ennen menetelmän suorittamista...
Kohdemenetelmä2 käynnissä...
Menetelmän suorittamisen jälkeen...
-----------------------------
Ennen menetelmän suorittamista...
Kohdemenetelmä3 käynnissä...
Menetelmän suorittamisen jälkeen...
3
Staattisten agenttien toteutuksesta ei ole vaikea nähdä, että staattisten aineiden edut ovat yksinkertainen toteutus ja helppo ymmärtää. Mutta sen puutteet ovat myös ilmeisiä, toisin sanoen aina kun sinun on lisättävä välityspalvelintoimintoa uuteen luokkaan, sinun on luotava manuaalisesti uusi välityspalvelinluokka, mikä johtaa luokkien määrän jyrkkään kasvuun ja ylläpitokustannusten nousuun. . Samanaikaisesti välityspalvelinluokan ja välityspalvelinluokan välinen kytkentäaste on liian korkea Kun menetelmiä lisätään, poistetaan tai muokataan välityspalvelinluokassa, vastaavia menetelmiä on lisättävä, poistettava tai muutettava myös välityspalvelinluokassa. , mikä parantaa koodin ylläpitokustannuksia. Toinen ongelma on, että kun välityspalvelinobjekti välittää useiden kohderajapintojen toteutusluokkia, useissa toteutusluokissa on oltava erilaisia menetelmiä. Koska välityspalvelinobjektin on toteutettava sama rajapinta kuin kohdeobjektin (itse asiassa sisällyttäminen suhde), sen on oltava kirjoitettava Lukuisat menetelmät voivat helposti johtaa paisuneeseen ja vaikeasti ylläpidettävään koodiin.
Dynaamisen välityspalvelimen ydinajatuksena on päästä epäsuorasti alkuperäiseen kohteeseen välityspalvelinobjektin kautta muuttamatta alkuperäistä kohdekoodia ja suorittaa lisätoimintoja ennen pääsyä ja sen jälkeen.
Dynaamisen välityspalvelimen toteutusperiaate perustuu pääosin Javan heijastusmekanismiin. Kun käytät dynaamisia välityspalvelimia, sinun on määritettävä liitäntä tai joukko rajapintoja, jotka määrittävät välityspalvelimen luokan (välityspalvelinobjektin) toiminnan.Sitten sinun on kirjoitettava toteutusInvocationHandler
Käyttöliittymäluokka, tämä luokka sisältää logiikan, joka suoritetaan ennen ja jälkeen välityspalvelinobjektin metodikutsuja.kun soitatProxy.newProxyInstance()
-menetelmä, välitä rajapinnan luokkalataaja, liitäntätaulukko jaInvocationHandler
Objekti, Java luo dynaamisesti välityspalvelinluokan, joka toteuttaa määritetyn rajapinnan ajon aikana ja delegoi menetelmäkutsutInvocationHandler
käsiteltävät esineet.Kun välityspalvelinobjektin menetelmää kutsutaan, se itse asiassa kutsuuInvocationHandler
Käyttöliittymäinvoke()
Method, jossa voit suorittaa esikäsittelylogiikkaa menetelmän nimen, parametrien ja muiden tietojen perusteella ja sitten kutsua välityspalvelinobjektin vastaavaa menetelmää heijastuksen kautta.
Seuraavaksi esittelemme kaksi dynaamista välityspalvelinta: JDK Proxy ja CGLib
JDK Proxy käyttää Javan heijastusmekanismia välityspalvelinluokkien dynaamiseen luomiseen. Erityisesti,Proxy
luokka käyttääProxyGenerator
luokka (vaikka tämä luokka ei ole julkinen API, se on avain dynaamisen välityspalvelimen toteuttamiseen JDK:n sisällä) välityspalvelinluokan tavukoodin luomiseksi ja sen lataamiseksi JVM:ään.Luotu välityspalvelinluokka perii osoitteestajava.lang.reflect.Proxy
luokkaan ja toteuttaa määritetty rajapinta.Välityspalvelinluokan menetelmässä sitä kutsutaanInvocationHandler
/invoke
Menetelmä, välitä menetelmäkutsu prosessorille käsittelyä varten.
Lisäksi suorituskyvyn parantamiseksi JDK-välityspalvelin tarjoaa myös välimuistimekanismin luodun välityspalvelinluokan Class-objektin välimuistiin tallentamiseksi. Tällä tavalla, kun sinun on luotava samantyyppinen välityspalvelinobjekti, voit saada välityspalvelimen luokan Class-objektin suoraan välimuistista ilman sitä uudelleen.Välimuisti tapahtuu kauttaWeakCache
Luokan toteuttama se käyttää heikkoja viittauksia välimuistiobjekteihin, jotta välimuistin kohteet, joita ei enää käytetä, voidaan puhdistaa automaattisesti, kun JVM suorittaa roskien keräämisen.
- public interface TargetInteface {
- void method1();
- void method2();
- int method3(Integer i);
- }
- public class Target implements TargetInteface {
- @Override
- public void method1() {
- System.out.println("method1 running ...");
- }
-
- @Override
- public void method2() {
- System.out.println("method2 running ...");
- }
-
- @Override
- public int method3(Integer i) {
- System.out.println("method3 running ...");
- return i;
- }
- }
InvocationHandler
käyttöliittymä ja kirjoittaa uudelleeninvoke
menetelmä.olla olemassainvoke
Metodissa voit lisätä mukautettua logiikkaa, kuten kirjaamista, käyttöoikeuksien tarkistusta jne., ja kutsua alkuperäistä luokkamenetelmää pohdinnan kautta.Proxy.newProxyInstance
menetelmä, luokkalataimen välitys, liitäntätaulukko jaInvocationHandler
Esiintymä välityspalvelinobjektien luomiseen dynaamisesti. Tämä menetelmä palauttaa välityspalvelinluokan ilmentymän, joka toteuttaa määritetyn rajapinnan.- public class TargetProxy {
- public static <T> Object getTarget(T t) {
- //新构建了一个 新的 代理类的对象
- return Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- // proxy就是目标对象t,method就是调用目标对象中方法,args就是调用目标对象中方法的参数。
- //比如说:代理对象.method1(),这时proxy就是目标类,method1就是method,args就是method1方法参数。
- System.out.println("执行方法前...");
- Object invoke = method.invoke(t, args);
- System.out.println("执行方法后...");
- return invoke;
- }
- });
- }
- }
InvocationHandler
/invoke
Menetelmä, kun olet suorittanut mukautetun logiikan tässä menetelmässä, kutsu alkuperäisen luokan menetelmää.- public class TargetUser {
-
- public static void main(String[] args) {
- TargetInteface target = (TargetInteface) TargetProxy.getTarget(new Target());
- target.method1();
- System.out.println("-----------------------------");
- target.method2();
- System.out.println("-----------------------------");
- System.out.println(target.method3(3));
- }
- }
Tulostulos:
Ennen menetelmän suorittamista...
menetelmä1 käynnissä...
Menetelmän suorittamisen jälkeen...
-----------------------------
Ennen menetelmän suorittamista...
menetelmä 2 käynnissä...
Menetelmän suorittamisen jälkeen...
-----------------------------
Ennen menetelmän suorittamista...
menetelmä3 käynnissä...
Menetelmän suorittamisen jälkeen...
3
MethodInterceptor
käyttöliittymä määrittääksesi menetelmän sieppaajan, joka suorittaa mukautetun logiikan ennen välityspalvelinobjektin menetelmäkutsua ja sen jälkeen, kuten esikäsittelyn, jälkikäsittelyn, poikkeusten käsittelyn jne.- import net.sf.cglib.proxy.Enhancer;
- import net.sf.cglib.proxy.MethodInterceptor;
- import net.sf.cglib.proxy.MethodProxy;
- import java.lang.reflect.Method;
- public class Target {
- public void method1() {
- System.out.println("method1 running ...");
- }
-
- public void method2() {
- System.out.println("method2 running ...");
- }
-
- public int method3(Integer i) {
- System.out.println("method3 running ...");
- return i;
- }
- }
MethodInterceptor
käyttöliittymäluokka ja ohitusintercept
menetelmä. Kirjoita välityspalvelinlogiikka tässä menetelmässä.Enhancer
luokkaa välityspalvelinobjektien luomiseen.Sinun on asetettava välityspalvelinluokka (viasetSuperclass
menetelmä) ja takaisinsoittoja (viasetCallback
Method asettaa MethodInterceptor-toteutusluokan).- public class TargetProxy {
- public static <T> Object getProxy(T t) {
- Enhancer en = new Enhancer(); //帮我们生成代理对象
- en.setSuperclass(t.getClass());//设置要代理的目标类
- en.setCallback(new MethodInterceptor() {//代理要做什么
- @Override
- public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
- System.out.println("执行方法前。。。");
- //调用原有方法
- Object invoke = methodProxy.invokeSuper(object, args);
- // Object invoke = method.invoke(t, args);// 作用等同与上面。
- System.out.println("执行方法后。。。");
- return invoke;
- }
- });
- return en.create();
- }
- }
intercept
Välityspalvelinlogiikka menetelmissä.- public class TargetUser {
-
- public static void main(String[] args) {
- Target target = (Target) TargetProxy.getProxy(new Target());
- System.out.println(target.getClass().getName());
- target.method1();
- }
-
- }
Tulostulos:
com.heaboy.aopdemo.cglibproxy.TargetEnhancerByCGLminäBf9f41fb8
ennen menetelmän suorittamista. . .
menetelmä1 käynnissä...
Menetelmän suorittamisen jälkeen. . .
etu:
puute:
Välityspalvelinobjektin tyyppi:JDK-välityspalvelin voi käyttää vain välitysluokkia, jotka toteuttavat rajapintoja, kun taas CGLib voi välityspalvelinta suoraan tavallisille luokille.
esitys: CGLib luo välityspalvelinluokkien alaluokkia ajon aikana, ja sen suorituskyky on yleensä hieman parempi kuin JDK-välityspalvelin. Mutta useimmissa skenaarioissa tämä suorituskyvyn ero ei ole merkittävä.
käytettävät kohtaukset: Jos kohdeobjekti jo toteuttaa käyttöliittymän, JDK-välityspalvelimen käyttö on yksinkertainen ja selkeä valinta. Jos sinun on välitettävä luokka, joka ei toteuta käyttöliittymää, sinun on käytettävä CGLibia.
luottaa:JDK-välityspalvelin ei vaadi ylimääräisiä riippuvuuksia, koska se on osa Java-ydinkirjastoa, kun taas CGLib vaatii CGLib-kirjaston lisäämisen projektiriippuvuutena.
JDK Proxy on Java-kielen mukana tuleva toiminto, jota ei tarvitse toteuttaa lataamalla kolmannen osapuolen luokkia;
Java tarjoaa vakaan tuen JDK-välityspalvelimelle ja jatkaa JDK-välityspalvelimen päivittämistä ja päivittämistä. Esimerkiksi Java 8 -version JDK-välityspalvelimen suorituskykyä on parannettu huomattavasti aiempiin versioihin verrattuna.
JDK Proxy toteutetaan sieppaajien ja heijastuksen avulla;
JDK-välityspalvelin voi vain välitysluokkia, jotka perivät liitännät;
JDK-välityspalvelin on suhteellisen yksinkertainen toteuttaa ja kutsua;
CGLib on kolmannen osapuolen tarjoama työkalu, joka on toteutettu ASM:n perusteella ja jolla on suhteellisen korkea suorituskyky;
CGLibia ei tarvitse toteuttaa rajapinnan kautta, sitä kutsutaan toteuttamalla alaluokka.
Staattinen välityspalvelin: Staattiset välityspalvelimet määritetään kääntämisen aikana. Välityspalvelinluokka ja välityspalvelinluokka toteuttavat saman rajapinnan tai perivät saman pääluokan.
Staattisen välityspalvelimen välityspalvelinluokka on olemassa käännöshetkellä, joten se voi välittää vain tiettyjä luokkia ohjelman ollessa käynnissä, eikä se voi dynaamisesti päättää, mitä luokkia välityspalvelimena käytetään.
Staattinen välityspalvelin kääri alkuperäisen objektin metodikutsun ja voi lisätä logiikkaa ennen ja jälkeen kutsun, mutta välityspalvelinluokka on kirjoitettava etukäteen, mikä lisää koodin määrää.
Staattinen välityspalvelin määrittää nimenomaisesti välityspalvelinobjektin koodissa ja on suhteellisen intuitiivinen käyttää, mutta uusien välityspalvelinluokkien lisääminen vaatii uudelleenkääntämisen.
Dynaaminen välityspalvelin: Dynaaminen välityspalvelin luo välityspalvelinobjekteja ajon aikana kirjoittamatta välityspalvelinluokkia etukäteen. Käytä Javan heijastusmekanismia välityspalvelinluokkien ja välityspalvelinobjektien dynaamiseen luomiseen.
Dynaamiset välityspalvelimet perustuvat rajapintoihin ja toteutetaan java.lang.reflect.Proxy-luokan ja java.lang.reflect.InvocationHandler-rajapinnan kautta.
Dynaaminen välityspalvelin voi välittää useiden liitäntöjen luokkia ja päättää dynaamisesti, mitkä luokat välityspalvelimena käytetään. Ajon aikana välityspalvelimia voidaan luoda eri kohteille tarpeen mukaan, mikä lisää joustavuutta.
Dynaamisen välityspalvelimen ei tarvitse kirjoittaa tiettyä välityspalvelinluokkaa jokaiselle välityspalvelinluokalle, mikä on joustavampaa ja säästää koodia.
Dynaamiset agentit voivat lisätä mukautettua logiikkaa ennen ja jälkeen menetelmäkutsuja välityspalvelinobjektiin, kuten lokiin kirjaamisen, tapahtumien hallinnan jne. Dynaamisen välityspalvelimen haittana on, että staattiseen välityspalvelimeen verrattuna välityspalvelinobjektin luominen suorituksen aikana vaatii tiettyä suorituskykyä.
Staattiset välityspalvelimet sopivat seuraaviin skenaarioihin:
Kun kohdeobjektien (välityspalvelinobjektien) lukumäärä on rajoitettu ja määritetty, staattinen välityspalvelin voidaan toteuttaa kirjoittamalla välityspalvelinluokat manuaalisesti. Staattiset välityspalvelimet luovat välityspalvelinluokkia käännöshetkellä, joten niillä on parempi suorituskyky ajon aikana.
Staattiset välityspalvelimet kapseloivat kohdeobjektin ja lisäävät lisätoimintoja muuttamatta alkuperäistä koodia. Tämän vuoksi staattisia välityspalvelimia käytetään usein monialaisiin asioihin, kuten kirjaamiseen ja tapahtumien hallintaan.
Dynaaminen välityspalvelin sopii seuraaviin skenaarioihin:
Kun kohdeobjektien lukumäärä on epävarma tai sitä ei voida määrittää etukäteen, dynaamiset välityspalvelimet voivat kätevämmin luoda välityspalvelinobjekteja. Se luo välityspalvelinluokkia ja välityspalvelinobjekteja ajon aikana välttäen monien välityspalvelinluokkien manuaalisen kirjoittamisen ikävän työn.
Dynaamiset välityspalvelimet tarjoavat joustavuutta lisätä, poistaa tai muuttaa välityspalvelimen käyttäytymistä kohdeobjekteille suorituksen aikana. Tämä tekee dynaamisista välityspalvelimista, joita käytetään usein sovellusskenaarioissa, kuten AOP (aspect-oriented programming) ja RPC (etäproseduurikutsu).
On huomattava, että koska dynaamiset välityspalvelimet luovat välityspalvelinluokkia ja välityspalvelinobjekteja heijastusmekanismin kautta ajon aikana, niiden suorituskyky voi olla hieman alhaisempi kuin staattisten välityspalvelinten. Lisäksi dynaamiset välityspalvelimet voivat välityspalvelimena kohdistaa vain rajapinnan toteuttaviin objekteihin, kun taas staattisilla välityspalvelimilla ei ole tätä rajoitusta.
Yhteenvetona voidaan todeta, että staattiset välityspalvelimet sopivat skenaarioihin, joissa kohdeobjektien määrä on rajoitettu ja varma, ja ne vaativat kapseloinnin ja lisätoimintoja, kun taas dynaamiset välityspalvelimet soveltuvat skenaarioihin, joissa kohdeobjektien lukumäärä on epävarma tai sitä ei voida määrittää etukäteen. ja välityspalvelimen toimintaa on joustavasti lisättävä, poistettava tai muutettava. Valitse sopiva toimistomenetelmä erityistarpeiden ja olosuhteiden perusteella.
Spring AOP on tärkeä moduuli Spring-kehyksessä, jota käytetään aspektisuuntautuneen ohjelmoinnin toteuttamiseen.
Ohjelmointi kasvokkain , tämä on ohjelmointimalli, jonka avulla ohjelmoijat voivat moduloida mukautettuja poikkileikkauspisteitä ja kapseloida useisiin luokkiin vaikuttavat käyttäytymiset uudelleenkäytettäviksi moduuleiksi. Esimerkki: Esimerkiksi lokitulostus, jos et käytä AOP:ta, sinun on asetettava lokitulostuslausekkeet kaikkiin luokkiin ja menetelmiin. AOP:lla voit kuitenkin kapseloida lokitulostuslauseet uudelleen käytettävään moduuliin ja sijoittaa ne moduuliin. deklaratiivisella tavalla Luokassa lokitulostus valmistuu automaattisesti aina, kun luokkaa käytetään.
Aspektisuuntautuneen ohjelmoinnin ideassa toiminnot on jaettu kahteen tyyppiin
Ydinliiketoiminta: Sisäänkirjautumista, rekisteröintiä, lisäämistä, poistamista, muokkaamista ja kyselyä kutsutaan ydinliiketoiminnaksi
Oheislaitteet: Lokit ja tapahtumien hallinta ovat toissijaisia oheispalveluita.
Aspektisuuntautuneessa ohjelmoinnissa ydinliiketoimintoja ja oheistoimintoja kehitetään itsenäisesti, eikä niitä ole kytketty toisiinsa. Sitten aspektifunktiot ja ydinliiketoiminnot "kudotaan" yhteen, jota kutsutaan AOP:ksi.
AOP voi muuntaa ne, jotka eivät liity liiketoimintaan,Mutta se on koteloitu logiikkaa tai vastuita varten (kuten tapahtumien käsittely, lokien hallinta, käyttöoikeuksien valvonta jne.), joita liiketoimintamoduulit yleisesti kutsuvat.,HelppoaVähennä kaksoiskoodia järjestelmässä,Vähennä moduulien välistä kytkentää,jaEdistää tulevaa skaalautuvuutta ja ylläpidettävyyttä。
AOP:ssa on seuraavat käsitteet:
AspectJ: Aspekti on vain käsite. Sitä vastaavaa rajapintaa tai luokkaa ei ole.
Liitoskohta : Yhteyspiste viittaa pisteeseen ohjelman suorituksen aikana, kuten menetelmän kutsumiseen, poikkeusten käsittelyyn jne. Spring AOP:ssa vain menetelmätason liitospisteitä tuetaan.
Neuvoja : Ilmoitus, eli poikkileikkaava logiikka määrittelemämme aspektin osalta, on kolme tyyppiä: "noin", "ennen" ja "jälkeen". Monissa AOP-toteutuskehyksissä neuvonta toimii yleensä sieppaajana, ja se voi myös sisältää monia sieppaajia linkkinä, jota käsitellään liitospisteen ympärillä.
Pointcut: Pointcut, jota käytetään yhdistämään liitospisteet AspectJ:n sisältämät liitospisteet on suodatettava Pointcutilla.
Johdanto : Johdanto, joka sallii aspektin ilmoittaa, että suositellut objektit toteuttavat lisärajapintoja, joita ne eivät todellisuudessa toteuta. Esimerkiksi välityspalvelinobjektia voidaan käyttää kahden kohdeluokan välityspalvelimena.
Kudonta : Kudonta, nyt kun meillä on liitospisteet, leikkauspisteet, ilmoitukset ja aspektit, kuinka soveltaa niitä ohjelmaan? Aivan oikein, se on kudonta Pointcuttien ohjauksessa ilmoituslogiikka lisätään kohdemetodiin, jotta ilmoituslogiikkamme voidaan suorittaa, kun menetelmää kutsutaan.
AOP-välityspalvelin : AOP-välityspalvelin viittaa objektiin, joka toteuttaa aspektiprotokollan AOP-toteutuskehyksessä. Spring AOP:ssa on kahdenlaisia välityspalvelimia, nimittäin JDK dynaaminen välityspalvelin ja CGLIB dynaaminen välityspalvelin.
Kohdeobjekti: Kohdeobjekti on välityspalvelimen kohteena oleva objekti.
Spring AOP on toteutettu JDK:n dynaamisen välityspalvelimen ja Cglib-promootioiden pohjalta. Molemmat välityspalvelimet ovat ajonaikaisia menetelmiä, joten niissä ei ole käännösaikaista käsittelyä, joten Spring toteutetaan Java-koodin kautta.
Joitakin yleisiä käyttäytymismalleja, jotka ovat hajallaan useiden luokkien tai objektien kesken (kuten lokikirjaus, tapahtumien hallinta, käyttöoikeuksien valvonta, liitäntävirran rajoitus, liitännän teho jne.), näitä käyttäytymismalleja kutsutaan yleensä nimellä monialaisia huolenaiheita . Jos toteutamme nämä käyttäytymiset toistuvasti jokaisessa luokassa tai objektissa, se johtaa redundanttiseen, monimutkaiseen ja vaikeasti ylläpidettävään koodiin.
AOP voi muuttaa monialaisia huolenaiheita (kuten lokikirjaus, tapahtumien hallinta, käyttöoikeuksien valvonta, liitännän virran rajoitus, liitännän teho jne.) Ydinliiketoiminnan logiikka (ydinhuolet, ydinhuolet) Erillään painopiste saavuttaaksesi huolenaiheiden erottamisen.
Kirjaaminen: Mukauta lokimerkintöjä ja käytä AOP:ta kirjaamiseen yhdellä koodirivillä.
Suorituskykytilastot: Laske AOP:lla menetelmän suoritusaika ennen kohdemenetelmän suorittamista ja sen jälkeen optimoinnin ja analyysin helpottamiseksi.
Tapahtuman hallinta:@Transactional
Huomautukset antavat Springille mahdollisuuden suorittaa tapahtumien hallintaa puolestamme, kuten peruuttaa poikkeusoperaatioita, mikä eliminoi toistuvan tapahtuman hallinnan logiikan.@Transactional
Annotaatiot toteutetaan AOP:n perusteella.
Käyttöoikeuksien valvonta: Määritä AOP:n avulla, onko käyttäjällä tarvittavat käyttöoikeudet ennen kohdemenetelmän suorittamista. Jos on, suorita kohdemenetelmä, muuten se ei suorita.Esimerkiksi SpringSecurity käyttää@PreAuthorize
Voit mukauttaa luvan vahvistusta kommentoimalla koodiriviä.
Liitäntävirran rajoitus: Käytä AOP:tä rajoittaaksesi pyyntöä tietyillä virtaa rajoittavilla algoritmeilla ja toteutuksilla ennen kuin kohdemenetelmä suoritetaan.
Välimuistin hallinta: Käytä AOP:ta välimuistin lukemiseen ja päivittämiseen ennen kohdemenetelmän suorittamista ja sen jälkeen.
AOP:n yleisiä toteutusmenetelmiä ovat dynaaminen välityspalvelin, tavukooditoiminto jne.
Spring AOP perustuu dynaamiseen välityspalvelimeen Jos välityspalvelin toteuttaa tietyn rajapinnan, Spring AOP käyttää sitä JDK-välityspalvelinVälityspalvelinobjektin luominen Objekteille, jotka eivät toteuta käyttöliittymää, et voi käyttää JDK-välityspalvelinta tällä hetkellä Cglib Luo välityspalvelimen kohteen alaluokka, joka toimii välityspalvelimena
olla olemassaspring-aop.xml
Määritä liittyvät pavut ja näkökohdat asetustiedostossa
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
-
- <bean id="target" class="com.xxhh.aopdemo.aop.Target"/>
-
- <bean id="targetAdvice" class="com.xxhh.aopdemo.aop.TargetAdvice"/>
-
- <bean id="targetProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
- <property name="target" ref="target"/> <!--被代理的类-->
- <property name="interceptorNames" value="targetAdvice"/> <!--如果用多种增强方式,value的值使用逗号(,)分割-->
- <property name="proxyTargetClass" value="false"/> <!--如果设置为true,则创建基于类的代理(使用CGLIB);如果设置为false,则创建基于接口的代理(使用JDK动态代理)。-->
- <property name="interfaces" value="com.xxhh.aopdemo.aop.TargetInteface"/> <!--target实现的接口-->
- </bean>
- </beans>
- public interface TargetInteface {
- void method1();
- void method2();
- int method3(Integer i);
- }
- public class Target implements TargetInteface{
-
- /*
- * 需要增强的方法,连接点JoinPoint
- **/
- @Override
- public void method1() {
- System.out.println("method1 running ...");
- }
-
- @Override
- public void method2() {
- System.out.println("method2 running ...");
- }
-
- @Override
- public int method3(Integer i) {
- System.out.println("method3 running ...");
- return i;
- }
- }
- public class TargetAdvice implements MethodInterceptor, MethodBeforeAdvice, AfterReturningAdvice {
-
- /*
- * 通知/增强
- **/
- @Override
- public Object invoke(MethodInvocation methodInvocation) throws Throwable {
- System.out.println("前置环绕通知");
- Object proceed = methodInvocation.proceed();
- System.out.println("后置环绕通知");
- return proceed;
- }
-
- @Override
- public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
- System.out.println("后置返回通知");
- }
-
- @Override
- public void before(Method method, Object[] args, Object target) throws Throwable {
- System.out.println("前置通知");
- }
- }
- public class AopTest {
- public static void main(String[] args) {
- ApplicationContext appCtx = new ClassPathXmlApplicationContext("spring-aop.xml");
- TargetInteface targetProxy = (TargetInteface) appCtx.getBean("targetProxy");
- targetProxy.method1();
- }
- }
Tulostustulos:
Surround edessä -ilmoitus
Ennakkoilmoitus
menetelmä1 käynnissä...
lähetä palautusilmoitus
Surround back -ilmoitus
olla olemassaspring-confaop.xml
Määritä liittyvät pavut ja näkökohdat asetustiedostossa
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
-
- <!--先开启cglib代理,开启 exposeProxy = true,暴露代理对象-->
- <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
- <!--扫包-->
- <context:component-scan base-package="com.xxhh.aopdemo.annotationaop"/>
-
- </beans>
- /*
- * 目标类
- **/
- public class Target {
-
- public void method1() {
- System.out.println("method1 running ...");
- }
-
- public void method2() {
- System.out.println("method2 running ...");
- }
-
- /*
- * 连接点JoinPoint
- **/
- public int method3(Integer i) {
- System.out.println("method3 running ...");
- // int i1 = 1 / i;
- return i;
- }
- }
- import org.aspectj.lang.ProceedingJoinPoint;
- /*
- * 切面类
- **/
- public class TargetAspect {
-
- /*
- * 前置通知
- **/
- public void before() {
- System.out.println("conf前置通知");
- }
-
- public void after() {
- System.out.println("conf后置通知");
- }
-
- public void afterReturning() {
- System.out.println("conf后置返回通知");
- }
-
- public void afterThrowing(Exception ex) throws Exception {
- // System.out.println("conf异常通知");
- // System.out.println(ex.getMessage());
- }
-
- public Object around(ProceedingJoinPoint pjp) throws Throwable {
- Object proceed = null;
- if (!"".equals("admin")) {
- System.out.println("conf环绕前置");
- proceed = pjp.proceed(pjp.getArgs());
- System.out.println("conf环绕后置");
- }
- return proceed;
- }
- }
- public class AopTest {
- public static void main(String[] args) {
- ApplicationContext appCtx = new ClassPathXmlApplicationContext("spring-confaop.xml");
- Target targetProxy = (Target) appCtx.getBean("target");
- System.out.println(targetProxy.method3(0));
- }
- }
Tulostustulos:
conf ennakkoilmoitus
conf surround-etuliite
menetelmä3 käynnissä...
conf palautuksen jälkeinen ilmoitus
conf surround viesti
conf-postitusilmoitus
0
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
-
- <!--先开启cglib代理,开启 exposeProxy = true,暴露代理对象-->
- <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
- <!--扫包-->
- <context:component-scan base-package="com.xxhh.aopdemo.annotationaop"/>
-
- </beans>
- @Target(ElementType.METHOD)
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- public @interface TestAnnotation{
- }
- /*
- * 切面类
- **/
- @Aspect
- @Component
- public class AnnotationAspect {
-
- // 定义一个切点:所有被RequestMapping注解修饰的方法会织入advice
- @Pointcut("@annotation(TestAnnotation)")
- private void advicePointcut() {}
-
- /*
- * 前置通知
- **/
- @Before("advicePointcut()")
- public void before() {
- System.out.println("annotation前置通知");
- }
-
- @After("advicePointcut()")
- public void after() {
- System.out.println("annotation后置通知");
- }
-
- @AfterReturning(pointcut = "advicePointcut()")
- public void afterReturning() {
- System.out.println("annotation后置返回通知");
- }
-
- @AfterThrowing(pointcut = "advicePointcut()", throwing = "ex")
- public void afterThrowing(Exception ex) throws Exception {
- System.out.println("annotation异常通知");
- System.out.println(ex.getMessage());
- }
-
- @Around("advicePointcut()")
- public Object around(ProceedingJoinPoint pjp) throws Throwable {
- Object proceed = null;
- if (!"".equals("admin")) {
- System.out.println("annotation环绕前置");
- proceed = pjp.proceed(pjp.getArgs());
- System.out.println("annotation环绕后置");
- }
- return proceed;
- }
- }
- @Controller
- public class TestController {
-
- @RequestMapping("/test.do")
- @ResponseBody
- public String testController() {
- TestController o = (TestController) AopContext.currentProxy();
- o.test();
- // System.out.println("tewt");
- return "ok";
- }
-
- @TestAnnotation
- public void test() {
- System.out.println("test running");
- }
-
- }