AOP(Aspect-Oriented Programming,面向切面編程),可以說是OOP(面向對象編程)的補充和完善。OOP引入封裝、繼承和多態性等概念來建立一種對象層次結構,用以模擬公共行為的一個集合。當我們需要為分散的對象引入公共行為的時候,OOP則顯得無能為力。也就是說,OOP允許你定義從上到下的關系,但并不適合定義從左到右的關系。例如日志功能。日志代碼往往水平地散布在所有對象層次中,而與它所散布到的對象的核心功能毫無關系。對于其他類型的代碼,如安全性、異常處理和透明的持續性也是如此。這種散布在各處的無關的代碼被稱為橫切(cross-cutting)代碼,在OOP設計中,它導致了大量代碼的重復,而不利于各個模塊的重用。
而AOP技術則恰恰相反,它利用一種稱為“橫切”的技術,剖解開封裝的對象內部,并將那些影響了多個類的公共行為封裝到一個可重用模塊,并將其名為“Aspect”,即方面。所謂“方面”,簡單地說,就是將那些與業務無關,卻為業務模塊所共同調用的邏輯或責任封裝起來,便于減少系統的重復代碼,降低模塊間的耦合度,并有利于未來的可操作性和可維護性。AOP代表的是一個橫向的關系,如果說“對象”是一個空心的圓柱體,其中封裝的是對象的屬性和行為;那么面向方面編程的方法,就仿佛一把利刃,將這些空心圓柱體剖開,以獲得其內部的消息。而剖開的切面,也就是所謂的“方面”了。然后它又以巧奪天功的妙手將這些剖開的切面復原,不留痕跡。
Spring支持四種攔截類型:目標方法調用前(before),目標方法調用后(after),目標方法調用前后(around),以及目標方法拋出異常(throw)。
前置攔截的類必須實現MethodBeforeAdvice接口,實現其中的before方法。
后置攔截的類必須實現AfterReturningAdvice接口,實現其中的afterReturning方法。
環繞攔截的類必須實現MethodInterceptor接口,實現其中的invoke方法。環繞攔截是唯一可以控制目標方法是否被真正調用的攔截類型,也可以控制返回對象。而前置攔截或后置攔截不能控制,它們不能印象目標方法的調用和返回。
但是以上的攔截的問題在于,不能對于特定方法進行攔截,而只能對某個類的全部方法作攔截。所以下面引入了兩個新概念:“切入點”和“引入通知”。
”切入點“的定義相當于更加細化地規定了哪些方法被哪些攔截器所攔截,而并非所有的方法都被所有的攔截器所攔截。在ProxyFactoryBean的屬性中,interceptorNames屬性的對象也由攔截(Advice)變成了引入通知(Advisor),正是在Advisor中詳細定義了切入點(PointCut)和攔截(Advice)的對應關系,比如常見的基于名字的切入點匹配(NameMatchMethodPointcutAdvisor類)和基于正則表達式的切入點匹配(RegExpPointcutAdvisor類)。這些切入點都屬于”靜態切入點“,因為他們只在代理創建的時候被創建一次,而不是每次運行都創建。
下面是spring的配置文件 當然aop的配置方式有許多種,這只是其中一種
<bean id="oaTaskInstanceService4Log" parent="transactionProxy">
<property name="target">
<bean
class="com.oa.task.service.impl.OaTaskInstanceServiceImpl">
<property name="oaTaskInstanceDao">
<ref local="oaTaskInstanceDao"/>
</property>
</bean>
</property>
</bean>
<!-- instance日志所需DAO -->
<bean id="oaTaskInstanceLogDao" class="com.oa.task.dao.OaTaskInstanceLogDao">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<!-- instance日志所需Service 此接口為 日志的業務操作接口-->
<bean id="oaTaskInstanceLogService" parent="transactionProxy">
<property name="target">
<bean
class="com.oa.task.service.impl.OaTaskInstanceLogServiceImpl">
<property name="oaTaskInstanceLogDao">
<ref local="oaTaskInstanceLogDao"/>
</property>
<property name="sysOperDao">
<ref bean="sysOperDao" />
</property>
<property name="ibatisBase">
<ref bean="ibatisBase" />
</property>
</bean>
</property>
</bean>
<!-- instance日志AOP攔截類 -->
<bean id="oaTaskInstanceLogOper" class="com.oa.task.log.OaTaskInstanceLogOper">
<property name="oaTaskInstanceLogService">
<ref local="oaTaskInstanceLogService" />
</property>
<property name="oaTaskInstanceService">
<ref local="oaTaskInstanceService4Log" />
</property>
</bean>
<!-- instance日志AOP配置綁定 -->
<bean id="oaTaskInstanceLogAutoProxy"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>oaTaskInstanceService</value> //攔截的業務接口 oaTaskInstanceService內所有方法都進行攔截
</list>
</property>
<property name="interceptorNames">
<list>
<value>oaTaskInstanceLogOper</value> //攔截器
</list>
</property>
</bean>
/**
* 當更新動作發生時的記錄
*/
public Object invoke(MethodInvocation invocation) throws Throwable {
String method = invocation.getMethod().getName();
Object result = null;
if(MODIFY_INSTANCE.equals(method)){//修改日志(業務邏輯 判斷方法)
......//業務操作,進行日志的記錄
result=invocation.proceed();
}else {//不做任何日志
result=invocation.proceed();//調用原來的方法
}
return result;
}
}