интерес мой проснулся спонтанно, Виктор Ронин выложил пост про локализацию ошибок. я большой поклонник использования подробного логирования программы для этих целей. однако, код логов действительно "засоряет" код программы и возможность отделит одно от другого была бы очень кстати. и тут я вспомнил про АОП.
действительно, логирование или трассировка программы -- это одна из классических задач АОП. но часто кажется, что одних средств АОП тут недостаточно и все-равно необходимо использовать логи внутри функционала, а раз так, то зачем писать что-то еще? пусть все логи будут внтури, раз нельзя их полностью отделить. на самом деле это не так. рабочую систему логирования я опишу позже, когда создам и оттестирую таковую :) пока поговорим о практических принципах применения АОП в среде Java + Spring. в документации по Spring очень много написано про АОП, фактически есть два способа реализации аспектов --с помощью Spring AOP и через AspectJ. я пока пользуюсь AspectJ аспектами, но возможно посмотрю и реализацию Spring.
итак, первое что необходимо понимать при аспектном программировании -- мы работаем с вызовами функциональности. т.е. елементарная операция для аспекта -- это вызов. мы можем описать для вызова пред- и пост-условия, обернуть выполнение метода какой-то функциональностью, котролировать метод после выброса исключения или после точки возврата. мы не можем обратиться к функционалу метода напрямую, но любой метод нашего класса есть на 90% набор вызовов других методов, а эти методы в свою очредь доступны через АОП. небольшая иллюстрация в коде, чтобы было еще понятнее:
предположим нам необходимо заполнить некторую коллекцию, пусть реализацию java.util.Map внутри класса:
package org.corwin.samples;
public class AopSample {
private Map
public void fillMap() {
container.put("sample1", "something");
container.put("sample2", "another thing");
}
}
теперь опишем аспект, который будет контролировать AopSample класс:
package org.corwin.samples.aspects;
public class SampleAspect {
public void beforeFillMap() {
System.out.println("Call before Map fill with values");
}
public void afterFillMap() {
System.out.println("Call after Map fill with values");
}
}
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
">
<bean id="sampleClass" class="org.corwin.samples.AopSample"/>
<bean id="sampleAspect" class="org.corwin.samples.aspects.SampleAspect"/>
<aop:config>
<aop:aspect ref="sampleAspect">
<aop:pointcut id="mapPutCut" expression="execution(* java.util.Map.put(..))"/>
<aop:before method="beforeFillMap" pointcut-ref="mapPutCut"/>
<aop:after method="afterFillMap" pointcut-ref="mapPutCut"/>
</aop:aspect>
</aop:config>
</beans>