Vaihdoin äskettäin Windowsista Mac OS X: ään ja olen innoissaan tuloksista. Mutta taas kerran vietin vain lyhyen viiden vuoden jakson Windows NT: ssä ja XP: ssä; ennen sitä olin tiukasti Unix-kehittäjä 15 vuotta, enimmäkseen Sun Microsystemsin koneilla. Minulla oli myös onni kehittää ohjelmistoja Nextstepin alla, joka on rehevä Unix-pohjainen edeltäjä Mac OS X: ssä, joten olen hieman puolueellinen.
Kauniin Aqua-käyttöliittymän lisäksi Mac OS X on Unix, epäilemättä paras olemassa oleva käyttöjärjestelmä. Unixilla on monia hienoja ominaisuuksia; yksi tunnetuimmista on putki, jonka avulla voit luoda komentojen yhdistelmiä vetämällä yhden komennon lähdön toisen syötteeseen. Oletetaan esimerkiksi, että haluat luetella lähdekoodit Struts-lähdejakelusta, jotka kutsuvat tai määrittelevät nimetyn menetelmän suorittaa()
. Tässä on yksi tapa tehdä se putken kanssa:
grep "execute (" `etsi $ STRUTS_SRC_DIR -name" * .java "" | awk -F: '{print}'
grep
komento etsii tiedostoista säännöllisiä lausekkeita; täällä käytän sitä etsimään merkkijonon esiintymät suorittaa(
tiedostoissa, jotka löytö
komento. grep
tuotos putkistoon awk
, joka tulostaa ensimmäisen merkin - erotettuna kaksoispisteellä - kullekin riville grep
tuotos (pystysuora palkki tarkoittaa putkea). Tämä tunniste on tiedostonimi, joten pääsen luetteloon tiedostonimistä, jotka sisältävät merkkijonon suorittaa(
.
Nyt kun minulla on luettelo tiedostonimistä, voin lajitella luettelon toisella putkella:
grep "execute (" `etsi $ STRUTS_SRC_DIR -name" * .java "` | awk -F: '{print}' | järjestellä
Tällä kertaa olen lähettänyt luettelon tiedostonimistä osoitteeseen järjestellä
. Entä jos haluat tietää, kuinka monessa tiedostossa merkkijono on suorittaa(
? Toisella putkella on helppoa:
grep "execute (" `etsi $ STRUTS_SRC_DIR -name" * .java "` | awk -F: '{print}' | lajittelu -u | wc -l
WC
komento laskee sanat, rivit ja tavut. Tässä tapauksessa määritin -
vaihtoehto laskea rivejä, yksi rivi kullekin tiedostolle. Lisäsin myös a -u
vaihtoehto järjestellä
varmistaa jokaisen tiedostonimen ainutlaatuisuus ( -u
suodattaa kaksoiskappaleet).
Putket ovat tehokkaita, koska niiden avulla voit säveltää dynaamisesti toimintaketjun. Ohjelmistojärjestelmissä käytetään usein vastaavia putkia (esim. Sähköpostisuodattimet tai suodinsarja servletille). Putkien ja suodattimien sydämessä on suunnittelukuvio: Vastuuketju (CoR).
merkintä: Voit ladata tämän artikkelin lähdekoodin Resursseista.
Alueiden komitean esittely
Vastuuketju-malli käyttää objektiketjua pyynnön käsittelemiseen, joka on tyypillisesti tapahtuma. Ketjun objektit välittävät pyynnön ketjussa, kunnes yksi esineistä käsittelee tapahtumaa. Käsittely loppuu tapahtuman käsittelyn jälkeen.
Kuva 1 kuvaa, miten AK: n malli käsittelee pyynnöt.
Sisään Suunnittelumalleja, kirjoittajat kuvaavat vastuullisuusketjun mallia näin:
Vältä pyynnön lähettäjän liittämistä vastaanottimeen antamalla useammalle kohteelle mahdollisuus käsitellä pyyntöä. Ketjua vastaanottavat esineet ja välitä pyyntö ketjua pitkin, kunnes esine käsittelee sitä.Vastuuketjumalli on sovellettavissa, jos:
- Haluat irrottaa pyynnön lähettäjän ja vastaanottajan
- Useat ajon aikana määritetyt objektit ovat ehdokkaita, jotka käsittelevät pyyntöä
- Et halua määrittää käsittelijöitä erikseen koodissasi
Jos käytät AK: n mallia, muista:
- Vain yksi ketjun esine käsittelee pyynnön
- Joitakin pyyntöjä ei ehkä käsitellä
Nämä rajoitukset koskevat tietysti AK: n klassista täytäntöönpanoa. Käytännössä nämä säännöt ovat taipuneet; esimerkiksi servlet-suodattimet ovat CoR-toteutus, jonka avulla useat suodattimet voivat käsitellä HTTP-pyyntöä.
Kuvassa 2 on esitetty AK: n malliluokka.
Tyypillisesti pyynnön käsittelijät ovat perusluokan laajennuksia, jotka ylläpitävät viittausta ketjun seuraavaan käsittelijään, joka tunnetaan nimellä seuraaja
. Perusluokka saattaa toteuttaa kahvaRequest ()
kuten tämä:
julkinen abstrakti luokka HandlerBase {... public void handleRequest (SomeRequestObject sro) {if (seuraaja! = null) seuraaja.handleRequest (sro); }}
Joten käsittelijät välittävät pyynnön oletusarvoisesti ketjun seuraavalle käsittelijälle. Konkreettinen jatko HandlerBase
saattaa näyttää tältä:
public class SpamFilter laajentaa HandlerBase {public void handleRequest (SomeRequestObject mailMessage) {if (isSpam (mailMessage)) {// Jos viesti on roskapostia // tee roskapostiin liittyviä toimintoja. Älä lähetä viestiä eteenpäin. } else {// Viesti ei ole roskapostia. super.handleRequest (mailMessage); // Lähetä viesti ketjun seuraavaan suodattimeen. }}}
Roskapostisuodatin
käsittelee pyynnön (oletettavasti uuden sähköpostin vastaanottamisen), jos viesti on roskapostia, joten pyyntö ei mene pidemmälle; muuten luotettavat viestit välitetään seuraavalle käsittelijälle, oletettavasti toiselle sähköpostisuodattimelle, joka pyrkii poistamaan ne. Lopulta ketjun viimeinen suodatin saattaa tallentaa viestin sen jälkeen, kun se on läpäissyt kokoontumispaikan siirtymällä useiden suodattimien läpi.
Huomaa, että edellä käsitellyt hypoteettiset sähköpostisuodattimet sulkevat toisensa pois: Viime kädessä vain yksi suodatin käsittelee pyynnön. Voit halutessasi kääntää tämän ylösalaisin antamalla usean suodattimen käsitellä yhtä pyyntöä, mikä on parempi analogia Unix-putkiin. Joko niin, taustalla oleva moottori on AK: n malli.
Tässä artikkelissa käsittelen kahta vastuullisuusketjumallin toteutusta: servlet-suodattimet, suosittu AK-toteutus, joka sallii useiden suodattimien käsittelevän pyyntöä, ja alkuperäinen Abstract Window Toolkit (AWT) -tapahtumamalli. .
Servlet-suodattimet
Java 2 Platform, Enterprise Editionin (J2EE) alkuaikoina jotkut servlet-kontit tarjosivat kätevän ominaisuuden, joka tunnetaan nimellä servlet-ketjutus, jolloin olennaisesti voitiin käyttää suodatinluetteloa servlet-sovellukseen. Servlet-suodattimet ovat suosittuja, koska ne ovat hyödyllisiä tietoturvan, pakkaamisen, lokien kirjaamisen ja muun suhteen. Ja tietysti voit laatia suodatinketjun tehdäksesi kaikki tai kaikki näistä ajonaikaisista olosuhteista riippuen.
Java Servlet Specification -ohjelman version 2.3 myötä suodattimista tuli vakiokomponentteja. Toisin kuin perinteinen CoR, servlet-suodattimet sallivat ketjussa olevien useiden objektien (suodattimien) käsitellä pyyntöä.
Servlet-suodattimet ovat tehokas lisäys J2EE: hen. Suunnittelumallien näkökulmasta ne tarjoavat mielenkiintoisen käänteen: Jos haluat muokata pyyntöä tai vastausta, käytä AK: n lisäksi Decorator-mallia. Kuva 3 näyttää, kuinka servlet-suodattimet toimivat.
Yksinkertainen servlet-suodatin
Sinun on tehtävä kolme asiaa servletin suodattamiseksi:
- Ota käyttöön servlet
- Ota suodatin käyttöön
- Yhdistä suodatin ja servlet
Esimerkit 1-3 suorittavat kaikki kolme vaihetta peräkkäin:
Esimerkki 1. Servlet
tuo java.io.PrintWriter; tuo javax.servlet. *; tuo javax.servlet.http. *; public class FilteredServlet laajentaa HttpServlet {public void doGet (HttpServletRequest-pyyntö, HttpServletResponse vastaus) heittää ServletException, java.io.IOException {PrintWriter out = response.getWriter (); out.println ("Suodatettu palvelinsovellus käynnistetty"); }}
Esimerkki 2. Suodatin
tuo java.io.PrintWriter; tuo javax.servlet. *; tuo javax.servlet.http.HttpServletRequest; public class AuditFilter toteuttaa suodattimen {private ServletContext app = null; public void init (FilterConfig config) {app = config.getServletContext (); } julkinen mitätöinti doFilter(ServletRequest-pyyntö, ServletResponse-vastaus, FilterChain-ketju) heittää java.io.IOException, javax.servlet.ServletException {app.log ((((HttpServletRequest) pyyntö) .getServletPath ()); chain.doFilter(pyyntö, vastaus); } julkinen mitätöinti () {}}
Esimerkki 3. Käyttöönoton kuvaaja
auditFilter AuditFilter <suodatinkartoitus>auditFilter/ filteredServlet</ suodatinkartoitus> filteredServlet FilteredServlet suodatettuServlet / suodatettuServlet ...
Jos käytät servletiä URL-osoitteella / filteredServlet
, auditFilter
saa halkeaman pyynnöstä ennen servletiä. AuditFilter.doFilter
kirjoittaa servlet-säilön lokitiedostoon ja kutsuu chain.doFilter ()
välittää pyyntö. Servlet-suodattimia ei vaadita soittamiseen chain.doFilter ()
; jos he eivät, pyyntöä ei välitetä eteenpäin. Voin lisätä lisää suodattimia, jotka kutsutaan siinä järjestyksessä kuin ne on ilmoitettu edellisessä XML-tiedostossa.
Nyt kun olet nähnyt yksinkertaisen suodattimen, katsotaan toinen suodatin, joka muuttaa HTTP-vastausta.
Suodata vastaus Decorator-kuviolla
Toisin kuin edellinen suodatin, joidenkin servlet-suodattimien on muokattava HTTP-pyyntöä tai vastausta. Mielenkiintoista on, että tämä tehtävä liittyy Decorator-kuvioon. Keskustelin Decorator-kuviosta kahdessa edellisessä Java-suunnittelumallit artikkelit: "Hämmästytä kehittäjäystäviäsi suunnittelumalleilla" ja "Koristele Java-koodisi".
Esimerkissä 4 on luettelo suodattimesta, joka suorittaa yksinkertaisen haun ja vaihdon vastauksen rungossa. Tämä suodatin koristaa servlet-vastausta ja välittää sisustajan servletille. Kun servlet pienenee kirjoittamaan koristeltuun vastaukseen, suodatin suorittaa haun ja korvauksen vastauksen sisällössä.
Esimerkki 4. Etsi ja korvaa suodatin
tuo java.io. *; tuo javax.servlet. *; tuo javax.servlet.http. *; public class SearchAndReplaceFilter toteuttaa suodattimen {private FilterConfig config; public void init (FilterConfig config) {this.config = config; } public FilterConfig getFilterConfig () {return config; } public void doFilter (ServletRequest-pyyntö, ServletResponse-vastaus, FilterChain-ketju) heittää java.io.IOException, javax.servlet.ServletException {StringWrapper kääre = uusi StringWrapper((HttpServletResponse) vastaus); chain.doFilter(pyyntö, kääre); Merkkijono responseString = wrapper.toString(); Merkkijono haku = config.getInitParameter ("haku"); Merkkijono korvaa = config.getInitParameter ("korvaa"); if (haku == null || korvaa == null) return; // Parametreja ei ole asetettu oikein int index = responseString.indexOf (haku); if (indeksi! = -1) {String beforeReplace = responseString.substring (0, indeksi); Merkkijono afterReplace = responseString.substring (hakemisto + haku.pituus ()); response.getWriter (). tulosta(beforeReplace + vaihda + afterReplace); }} public void hävitä () {config = null; }}
Edellinen suodatin etsii nimettyjä suodattimen init-parametreja Hae
ja korvata
; jos ne on määritelty, suodatin korvaa ensimmäisen esiintymisen Hae
parametrin arvo korvata
parametrin arvo.
SearchAndReplaceFilter.doFilter ()
kääri (tai koristaa) vastausobjektin kääreellä (koristelija), joka seisoo vastauksen edessä. Kun SearchAndReplaceFilter.doFilter ()
puhelut chain.doFilter ()
välittää pyyntö, se ohittaa kääreen alkuperäisen vastauksen sijaan. Pyyntö välitetään servletille, joka tuottaa vastauksen.
Kun chain.doFilter ()
palaa, servlet on tehty pyynnön kanssa, joten menen töihin. Ensin tarkistan Hae
ja korvata
suodatinparametrit; jos on, saan vastauksen kääreeseen liittyvän merkkijonon, joka on vastauksen sisältö. Sitten teen korvauksen ja tulostan sen takaisin vastaukseen.
Esimerkissä 5 luetellaan StringWrapper
luokassa.
Esimerkki 5. Sisustaja
tuo java.io. *; tuo javax.servlet. *; tuo javax.servlet.http. *; public class StringWrapper laajentaa HttpServletResponseWrapper {StringWriter-kirjoittaja = new StringWriter (); public StringWrapper (HttpServletResponse response) {super (vastaus); } public PrintWriter getWriter () {palauta uusi PrintWriter (kirjoittaja); } public String toString () {return kirjoittaja.String (); }}
StringWrapper
, joka koristaa HTTP-vastausta esimerkissä 4, on laajennus HttpServletResponseWrapper
, mikä säästää meitä siitä, miten luodaan sisustajan perusluokka HTTP-vastausten koristeluun. HttpServletResponseWrapper
lopulta toteuttaa Servlet-vastaus
käyttöliittymä, joten HttpServletResponseWrapper
voidaan siirtää mihin tahansa menetelmään odottaen a Servlet-vastaus
esine. Siksi SearchAndReplaceFilter.doFilter ()
voi soittaa chain.doFilter (pyyntö, kääre)
sijasta chain.doFilter (pyyntö, vastaus)
.
Nyt kun meillä on suodatin ja vastausten kääre, yhdistetään suodatin URL-malliin ja määritetään haku ja korvaavat mallit: