Салам балдар! Негизги түшүнүктөрдү түшүнбөстөн, функцияларды куруунун алHowтарына жана ыкмаларына киришүү абдан кыйын. Ошентип, бүгүн биз бул түшүнүктөрдүн бири жөнүндө сүйлөшөбүз - AOP, же аспект-багытталган программалоо . Бул оңой тема эмес жана көп учурда түздөн-түз колдонулbyte, бирок көптөгөн алHowтар жана технологиялар аны капчыктын астында колдонушат. Анан, албетте, кээде интервью учурунда сизден бул кандай жаныбар экенин жана аны кайда колдонууга болорун жалпысынан айтып берүүнү суранышы мүмкүн. Келгиле, негизги түшүнүктөрдү жана Javaдагы AOPтин кээ бир жөнөкөй мисалдарын карап көрөлү . Ошентип, AOP - аспект-багытталган программалоо - бул кайчылаш түйшүктөрдү бөлүп, колдонмонун ар кандай бөлүктөрүнүн модулдуулугун жогорулатууга багытталган парадигма. Бул үчүн, баштапкы codeду өзгөртпөстөн, учурдагы codeго кошумча жүрүм-турум кошулат. Башкача айтканда, биз өзгөртүлгөн codeго түзөтүүлөрдү киргизбестен, методдор менен класстардын үстүнө кошумча функцияларды orп койгондойбуз. Бул эмне үчүн керек? Эртеби-кечпи биз кадимки an objectиге багытталган мамиле ар дайым эле белгилүү бир маселелерди натыйжалуу чече алbyte деген тыянакка келебиз. Мындай учурда, AOP жардамга келет жана бизге тиркемени куруу үчүн кошумча куралдарды берет. Ал эми кошумча инструменттер өнүгүүдө ийкемдүүлүктүн жогорулашын билдирет, анын аркасында белгилүү бир маселени чечүү үчүн көбүрөөк мүмкүнчүлүктөр бар.
AOP колдонуу
Аспектке багытталган программалоо ар кандай жолдор менен көп жолу кайталануучу ар кандай code болушу мүмкүн болгон кайчылаш маселелерди чечүү үчүн иштелип чыккан, аны өзүнчө модулга толугу менен түзүүгө болбойт. Демек, AOP менен биз муну негизги codeдон тышкары калтырып, вертикалдуу аныктай алабыз. Мисал тиркемеде коопсуздук саясатын колдонуу. Адатта, коопсуздук колдонмонун көптөгөн элементтерин кесип. Мындан тышкары, колдонмонун коопсуздук саясаты колдонмонун бардык болгон жана жаңы бөлүктөрүнө бирдей колдонулушу керек. Ошол эле учурда колдонулган коопсуздук саясаты да өзгөрүшү мүмкүн. Бул жерде AOP колдонуу пайдалуу болушу мүмкүн . Ошондой эле дагы бир мисал журнал жазуу болуп саналат . Каттоо үчүн AOP ыкмасын колдонуунун кол менен киргизүүгө салыштырмалуу бир нече артыкчылыктары бар:- Каттоо codeун ишке ашыруу жана алып салуу оңой: сиз жөн гана кандайдыр бир аспекттин бир нече конфигурациясын кошуп же алып салышыңыз керек.
- Каттоо үчүн бардык булак codeу бир жерде сакталат жана бардык колдонуу жерлерин кол менен табуу зарылчылыгы жок.
- Каттоо үчүн арналган codeду каалаган жерден кошууга болот, ал буга чейин жазылган ыкмалар жана класстар же жаңы функциялар болсун. Бул иштеп чыгуучулардын каталарынын санын азайтат.
Ошондой эле, сиз дизайн конфигурациясынан аспектти алып салганыңызда, бардык трек codeу алынып салынганына жана эч нерсе жок экендигине толук ишене аласыз. - Аспекттер кайра-кайра колдонууга жана өркүндөтүүгө мүмкүн болгон өз алдынча code.
АОПтун негизги түшүнүктөрү
Теманы андан ары талдоо үчүн алгач АОПтун негизги түшүнүктөрү менен таанышалы. Кеңеш - бул туташуу чекитинен чакырылган кошумча логика, code. Кеңешти туташуу чекитинин алдында, кийин же анын ордуна аткарса болот (алар жөнүндө төмөндө). Кеңештердин мүмкүн болгон түрлөрү :- Мурун (Алга) - бул типтеги кеңеш максаттуу ыкмаларды - туташуу пункттарын аткаруудан мурун ишке киргизилет. Аспекттерди класстар катары колдонгондо, кеңеш түрүн мурунку катары белгилөө үчүн @Before annotationсын алабыз. Аспекттерди .aj файлдары катары колдонгондо , бул before() ыкмасы болот .
- Кийин (Кийинчерээк) - методдордун аткарылышы аяктагандан кийин аткарылуучу кеңеш - кадимки учурларда да, өзгөчөлүктү таштаганда да кошулуу пункттары.
Аспекттерди класстар катары колдонууда, биз @After annotationсын колдонуп, бул кийин келген кеңеш экенин көрсөтө алабыз. Аспекттерди .aj
файлдары катары колдонгондо , бул after() ыкмасы болот . - Кайтуудан кийин - бул кеңештер максаттуу ыкма катасыз, нормалдуу иштегенде гана аткарылат.
Аспекттер класстар катары берилгенде, биз @AfterReturning annotationсын кеңешти ийгorктүү аяктагандан кийин аткарылды деп белгилей алабыз.
Аспекттерди .aj файлдары катары колдонгондо, бул кайтаруучу (Object obj) after() ыкмасы болот . - Ыргыткандан кийин - кеңештердин бул түрү ыкма, башкача айтканда, туташуу чекити өзгөчө учурду таштаган учурларга арналган. Биз бул кеңешти ишке ашпай калган аткарууну (мисалы, бүткүл транзакцияны артка жылдыруу же талап кылынган из деңгээли менен каттоо) үчүн колдоно алабыз.
Аспект класстары үчүн @AfterThrowing annotationсы бул кеңеш өзгөчөлүк ташталгандан кийин колдонулаарын көрсөтүү үчүн колдонулат. .aj
файлдары түрүндөгү аспектилерди колдонууда , бул ыкмасы болот - after() ыргытуу (Exception e) . - Around бул, балким, методду курчап турган кеңештердин эң маанилүү түрлөрүнүн бири, башкача айтканда, байланыш чекити, анын жардамы менен биз, мисалы, берилген туташуу чекитинин ыкмасын аткарууну же аткарбоону тандай алабыз.
Сиз кошулуу чекити ыкмасы аткарылганга чейин жана кийин иштеген кеңеш codeун жаза аласыз. Кеңештин
милдеттерине кошулуу чекитинин ыкмасын чакыруу жана метод бир нерсе кайтарса, баалуулуктарды кайтаруу кирет. Башкача айтканда, бул кеңеште сиз максаттуу ыкманын иштешин аны чакырбай эле туурап, натыйжада өзүңүздүн бир нерсеңизди кайтара аласыз. Класстар түрүндөгү аспектилер үчүн биз @Around annotationсын туташуу чекитин орогон кеңештерди түзүү үчүн колдонобуз. Аспекттерди .aj файлдары катары колдонгондо , бул around() ыкмасы болот .
- Compile-time weaving - Эгер сизде аспекттин баштапкы codeу жана аспекттерди колдонгон codeуңуз болсо, сиз AspectJ компиляторун колдонуу менен баштапкы codeду жана аспектти түзө аласыз;
- компиляциядан кийинки токуу (экorк токуу) - эгер сиз codeуңузга аспектилерди өрүү үчүн баштапкы codeдун трансформациясын колдоно албасаңыз же колдонгуңуз келбесе, анда сиз буга чейин түзүлгөн класстарды же банкаларды алып, аспекттерди сайсаңыз болот;
- жүктөө убактысында токуу класс жүктөгүч класс файлын жүктөгөнгө жана JVM үчүн классты аныктамайынча кийинкиге калтырылган экorк токуу.
Муну колдоо үчүн бир же бир нече "токуу классындагы жүктөгүчтөр" талап кылынат. Алар же ачык түрдө иштөө убактысы тарабынан берилет же "токуу агенти" тарабынан иштетилет.
Java тorндеги мисалдар
Кийинки, AOP жакшыраак түшүнүү үчүн , биз Hello World деңгээлиндеги кичинекей мисалдарды карап чыгабыз. Дароо белгилеп кетейин, биздин мисалдарыбызда биз компиляция убактысын токууну колдонобуз . Алгач биздин pom.xml үчүн төмөнкү көз карандылыкты кошуу керек :<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.5</version>
</dependency>
Эреже катары, аспектилерди колдонуу үчүн атайын Ajs компилятору колдонулат . IntelliJ IDEA демейки боюнча ага ээ эмес, андыктан аны тиркеме компилятору катары тандоодо AspectJ бөлүштүрүүчү жолду көрсөтүшүңүз керек . Ajsти компилятор катары тандоо ыкмасы тууралуу кененирээк бул баракчадан окуй аласыз. Бул биринчи ыкма, ал эми экинчиси (мен колдонгон) pom.xml үчүн төмөнкү плагинди кошуу болду :
<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>
Андан кийин, Mavenден кайра импорттоо жана mvn clean compile иштетүү сунушталат . Эми мисалдарга өтөлү.
Мисал №1
Келгиле, негизги класс түзөлү . Анда бизде ишке киргизүү чекити жана консолдо ага берилген аттарды басып чыгаруучу ыкма болот:public class Main {
public static void main(String[] args) {
printName("Толя");
printName("Вова");
printName("Sasha");
}
public static void printName(String name) {
System.out.println(name);
}
}
Эч нерсе татаал эмес: алар атын өткөрүп, аны консолдо көрсөтүштү. Эгер биз аны азыр иштетсек, консол төмөнкүнү көрсөтөт:
Толя Вова Саша
Ооба, AOP күчүн пайдаланууга убакыт жетти. Эми биз файлдык аспект түзүшүбүз керек . Алар эки түрдүү болот: биринчиси .aj кеңейтүүсү бар файл , экинчиси annotationларды колдонуу менен AOP мүмкүнчүлүктөрүн ишке ашырган кадимки класс . Алгач .aj кеңейтүүсү бар файлды карап көрөлү :
public aspect GreetingAspect {
pointcut greeting() : execution(* Main.printName(..));
before() : greeting() {
System.out.print("Привет ");
}
}
Бул файл класска бир аз окшош. Келгиле, бул жерде эмне болуп жатканын аныктап көрөлү: чекит - кесүү же байланыш чекиттеринин жыйындысы; саламдашуу() — бул кесимдин аты; : аткаруу - аткарууда * - бардыгы, чакыруу - Main.printName(..) - бул ыкма. Андан кийин конкреттүү кеңеш келет - before() - ал максаттуу ыкма чакырылганга чейин аткарылат, : greeting() - бул кеңеш жооп бере турган тилке, ал эми төмөндө биз Java тorнде жазылган методдун өзөгүн көрөбүз. биз түшүнгөн тил. Бул аспект менен негизги иштеткенде , консолго төмөнкү натыйжаны алабыз:
Салам Толя Салам Вова Салам Саша
printName ыкмасына ар бир чалуу аспект менен өзгөртүлгөнүн көрө алабыз . Эми аспект кандай болорун карап көрөлү, бирок annotationлары бар Java классы катары:
@Aspect
public class GreetingAspect{
@Pointcut("execution(* Main.printName(String))")
public void greeting() {
}
@Before("greeting()")
public void beforeAdvice() {
System.out.print("Привет ");
}
}
.aj aspect файлынан кийин баары айкыныраак болот:
- @Aspect берилген класс аспект экенин билдирет; @Pointcut("execution(* Main.printName(String))") бул String түрүндөгү кириш аргументи менен Main.printNameге бардык чалууларда күйүүчү кесүү чекити ;
- @Before("саламдашуу()") - саламдашуу() кесүү чекитинде сүрөттөлгөн codeду чакыруудан мурун колдонулуучу кеңеш .
Салам Толя Салам Вова Салам Саша
Мисал №2
Келгиле, бизде кардарлар үчүн кээ бир операцияларды аткарган бир нече ыкма бар дейли жана бул ыкманы mainден чакырабыз :public class Main {
public static void main(String[] args) {
makeSomeOperation("Толя");
}
public static void makeSomeOperation(String clientName) {
System.out.println("Выполнение некоторых операций для клиента - " + clientName);
}
}
@Around annotationсын колдонуп , келгиле, "псевдо-транзакция" сыяктуу бир нерсе жасайлы:
@Aspect
public class TransactionAspect{
@Pointcut("execution(* Main.makeSomeOperation(String))")
public void executeOperation() {
}
@Around(value = "executeOperation()")
public void beforeAdvice(ProceedingJoinPoint joinPoint) {
System.out.println("Открытие транзакции...");
try {
joinPoint.proceed();
System.out.println("Закрытие транзакции....");
}
catch (Throwable throwable) {
System.out.println("Операция не удалась, откат транзакции...");
}
}
}
ProceedingJoinPoint an objectинин улантуу ыкмасын колдонуп , анын тактадагы ордун аныктоо үчүн орогучтун ыкмасын жана ошого жараша жогорудагы ыкмадагы joinPoint.proceed(); - бул мурун , ал төмөндө - кийин . Эгерде биз негизги иштетсек , биз консолду алабыз:
Транзакцияны ачуу... Кардар үчүн кээ бир операцияларды жасоо - Толя Транзакцияны жабуу....
Эгерде биз ыкмабызга өзгөчө учурду кошсок (капысынан операция ишке ашпай калат):
public static void makeSomeOperation(String clientName)throws Exception {
System.out.println("Выполнение некоторых операций для клиента - " + clientName);
throw new Exception();
}
Андан кийин биз консолдо жыйынтыкты алабыз:
Транзакция ачылууда... Кардар үчүн кээ бир операциялар аткарылууда - Толя Операция ишке ашпай калды, транзакция артка кайтарылды...
Бул ийгorксиздиктин псевдопроцесси болуп чыкты.
Мисал №3
Кийинки мисал катары, консолго кирүү сыяктуу бир нерсе кылалы. Биринчиден, келгиле, Mainды карап көрөлү , бул жерде биздин псевдобизнес логикасы ишке ашат:public class Main {
private String value;
public static void main(String[] args) throws Exception {
Main main = new Main();
main.setValue("<некоторое meaning>");
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 ичинде setValue колдонуп , биз ички өзгөрмөнүн маанисин коебуз - value , андан кийин getValue аркылуу бул маанини алабыз жана checkValue ичинде бул маани 10 символдон узунураак экенин текшеребиз. Эгер ооба болсо, анда өзгөчөлүк ыргытылат. Эми биз методдордун иштешин журналга ала турган аспектти карап көрөлү:
@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("Успешно выполнен метод - %s, класса- %s, с результатом выполнения - %s\n",
joinPoint.getSignature().getName(),
joinPoint.getSourceLocation().getWithinType().getName(),
returningValue);
}
else {
System.out.printf("Успешно выполнен метод - %s, класса- %s\n",
joinPoint.getSignature().getName(),
joinPoint.getSourceLocation().getWithinType().getName());
}
}
@AfterThrowing(value = "methodExecuting()", throwing = "exception")
public void recordFailedExecution(JoinPoint joinPoint, Exception exception) {
System.out.printf("Метод - %s, класса- %s, был аварийно завершен с исключением - %s\n",
joinPoint.getSignature().getName(),
joinPoint.getSourceLocation().getWithinType().getName(),
exception);
}
}
Бул жерде эмне болуп жатат? @Pointcut("execution(* *(..))") - бардык ыкмаларга бардык чалууларга кошулат; @AfterReturning(value = "methodExecuting()", returning = "returningValue") - максаттуу ыкма ийгorктүү аяктагандан кийин аткарыла турган кеңеш. Бул жерде бизде эки учур бар:
- Метод кайтаруу маанисине ээ болгондо if (returningValue != null) {
- Башка эч кандай кайтаруу мааниси жок болгондо {
методу - setValue, класстын - Main ийгorктүү аткарылды.. методу - getValue, класстын - Main, ийгorктүү аткарылды, аткаруунун жыйынтыгы менен - <кээ бир маани> Метод - checkValue, класстын - Main, өзгөчө менен анормалдуу түрдө токтотулду - java.lang.Exception Метод - негизги, класс-Негизги, бир өзгөчөлүк менен бузулду - java.lang.Exception
Ооба, биз өзгөчө жагдайды чечпегендиктен, биз анын стектрегин да алабыз: Сиз бул макалалардан өзгөчө кырдаалдар жана аларды иштетүү жөнүндө окуй аласыз: Java жана Exceptions жана аларды иштетүү . Мен үчүн бүгүн баары ушул. Бүгүн биз AOP менен тааныштык , жана сиз бул жырткычтын боёлгондой коркунучтуу эмес экенин көрдүңүз. Баарыңарга салам!
GO TO FULL VERSION