一、AOP 概念
Joinpoint:它定義在哪裏加入你的邏輯功能,對於Spring AOP,Jointpoint指的就是Method。
Advice:特定的Jointpoint處運行的代碼,對於Spring AOP 來講,有Before advice、AfterreturningAdvice、ThrowAdvice、AroundAdvice(MethodInteceptor)等。
Pointcut:一組Joinpoint,就是說一個Advice可能在多個地方織入,
Aspect:這個我一直迷惑,它實際是Advice和Pointcut的組合,但是Spring AOP 中的Advisor也是這樣一個東西,但是Spring中爲什麼叫Advisor而不叫做Aspect。
Weaving:將Aspect加入到程序代碼的過程,對於Spring AOP,由ProxyFactory或者ProxyFactoryBean負責織入動作。
Target:這個很容易理解,就是需要Aspect功能的對象。
Introduction:引入,就是向對象中加入新的屬性或方法,一般是一個實例一個引用對象。當然如果不引入屬性或者引入的屬性做了線程安全性處理或者只讀屬性,則一個Class一個引用也是可以的(自己理解)。Per-class lifecycle or per-instance life cycle
二、AOP 種類
1、靜態織入:指在編譯時期就織入Aspect代碼,AspectJ好像是這樣做的。
2、動態織入:在運行時期織入,Spring AOP屬於動態織入,動態織入又分靜動兩種,靜則指織入過程只在第一次調用時執行;動則指根據代碼動態運行的中間狀態來決定如何操作,每次調用Target的時候都執行(性能較差)。
三、Spring AOP 代理原理
Spring AOP 是使用代理來完成的,Spring 會使用下面兩種方式的其中一種來創建代理:
1、JDK動態代理,特點只能代理接口,性能相對較差,需要設定一組代理接口。
2、CGLIB 代理,可代理接口和類(final method除外),性能較高(生成字節碼)。
四、Spring AOP 通知類型
1、BeforeAdvice:前置通知需實現MethodBeforeAdvice,但是該接口的Parent是BeforeAdvice,致於什麼用處我想可能是擴展性需求的設計吧。或者Spring未來也並不侷限於Method的JoinPoint(胡亂猜測)。BeforeAdvice可以修改目標的參數,也可以通過拋出異常來阻止目標運行。
2、AfterreturningAdvice:實現AfterreturningAdvice,我們無法修改方法的返回值,但是可以通過拋出異常阻止方法運行。
3、AroundAdvice:Spring 通過實現MethodInterceptor(aopalliance)來實現包圍通知,最大特點是可以修改返回值,當然它在方法前後都加入了自己的邏輯代碼,因此功能異常強大。通過MethodInvocation.proceed()來調用目標方法(甚至可以不調用)。
4、ThrowsAdvice:通過實現若干afterThrowing()來實現。
5、IntroductionInterceptor:Spring 的默認實現爲DelegatingIntroductionInterceptor
五、Spring AOP Pointcut
以上只是Advice,如果不指定切入點,Spring 則使用所有可能的Jointpoint進行織入(當然如果你在Advice中進行方法檢查除外)。因此切入點在AOP中扮演一個十分重要的角色。Spring 2.0 推薦使用AspectJ的Annocation的切入點表達式來定義切入點,或者使用<aop:xxx/>來定義AOP,這方面本篇不做考慮。
1、Pointcut:它是Spring AOP Pointcut的核心,定義了getClassFilter()和getMethodMatcher()兩個方法。
2、ClassFilter:定義了matches(Class cls)一個方法。
3、MethodMatcher() 定義了matches(Method,Class),isRuntime(),matches(Mathod,Class,Object[])三個方法,如果isRuntime()返回true則表示爲動態代理(實際是動態代理的動態代理),則調用第三個方法(每訪問一次調用一次),否則調用第一個方法(並且只調用一次)
4、Spring AOP 靜態切入點的幾個實現。
ComposablePointcut 太複雜一個切入點無法表達就用這個,union MethodMatcher和ClassFilter或者intersection MethodMatcher、ClassFilter和Pointcut。爲什麼不實現union Pointcut? 而只能通過Pointcuts類對Pointcut進行union操作。
ControlFlowPointcut 想對程序的運行過程進行追蹤就用這個
DynamicMatchMatcherPointcut 想用動態AOP 就用這個
JdkRegexpMethodPointcut 想使用正則表達式就用這個
Perl5RegexpMethodPointcut
NameMatchMethodPointcut 想用方法名字來匹配就用這個
StaticMethodMatcherPointcut 靜態切入點就用這個
沒有人反對你直接實現Pointcut:)。
六、Spring AOP 中的Advisor其實就是Aspect
1、 PointcutAdvisor
其實一般使用DefaultPointcutAdvisor就足夠了,給它Advice和Pointcut。
當然如果想少寫那麼幾行代碼也可以使用NameMatchMethodPointcutAdvisor,RegexpMethodPointcutAdvisor等。
更多Advisor可以查看API文檔。
2、 IntroductionAdvisor
默認實現爲DefaultIntroductionAdvisor。
七、AOP ProxyFactory
使用代碼實現AOP 可使用ProxyFactory
聲明式AOP 可使用ProxyFactoryBean
ProxyFactoryBean 需要設定 target,interceptorNames(可以是Advice或者Advisor,注意順序)
對接口代理需設置proxyInterfaces
八、自動代理
BeanNameAutoProxyCreator
- <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
- <property name="beanNames"><value>jdk*,onlyJdk</value></property>
- <property name="interceptorNames">
- <list>
- <value>myInterceptor</value>
- </list>
- </property>
- </bean>
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames"><value>jdk*,onlyJdk</value></property>
<property name="interceptorNames">
<list>
<value>myInterceptor</value>
</list>
</property>
</bean>
DefaultAdvisorAutoProxyCreator
- <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
- <bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
- <property name="transactionInterceptor" ref="transactionInterceptor"/>
- </bean>
- <bean id="customAdvisor" class="com.mycompany.MyAdvisor"/>
- <bean id="businessObject1" class="com.mycompany.BusinessObject1">
- <!-- Properties omitted -->
- </bean>
- <bean id="businessObject2" class="com.mycompany.BusinessObject2"/>
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
<property name="transactionInterceptor" ref="transactionInterceptor"/>
</bean>
<bean id="customAdvisor" class="com.mycompany.MyAdvisor"/>
<bean id="businessObject1" class="com.mycompany.BusinessObject1">
<!-- Properties omitted -->
</bean>
<bean id="businessObject2" class="com.mycompany.BusinessObject2"/>
AOP概念:
實現AOP有兩種方式:1、採用Annoation註解的方法.
1、接口的設計
package com.hejunfeng.spring;
public interface UserManager {
public void modifyUser(String id,String username,String password) ;
public void deleteUser(String id) ;
public void addUser(String username,String password) ;
}
2、接口的實現
package com.hejunfeng.spring.impl;
import com.hejunfeng.spring.UserManager;
public class UserManagerImpl implements UserManager {
public void addUser(String username, String password) {
System.out.println("----------UserManagerImpl.addUser()----------------");
}
public void deleteUser(String id) {
System.out.println("----------UserManagerImpl.deleteUser()----------------");
}
public void modifyUser(String id, String username, String password) {
System.out.println("----------UserManagerImpl.modifyUser()----------------");
}
}
3、定義一個切點
package com.hejunfeng.spring;
public interface MySecurityManager {
//抽出的一個切點
public void security();
}
4、實現此切點並進行相應的一些操作(annoation註解)
package com.hejunfeng.spring.impl;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import com.hejunfeng.spring.MySecurityManager;
//這裏採用註解方式
@Aspect
public class MySecurityManagerImpl implements MySecurityManager {
//定義切入點addMethod(),只負責用來描述切入那些方法.這裏是add方法.其它的可能很多
//接收所有的ADD方法是否有返回值是否有*無參數都接收
@Pointcut("execution(* add*(..))")
private void allAddMethod(){
}
//定義Advice方法用來標識在切入點的何處進行織入
//抽出一個切面就是安全性檢查security()
@Before("allAddMethod()")
public void security() {
System.out.println("---------作用就是進行安全性檢查---------");
}
}
5、applicationContext.xml文件的配置信息:
<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">
<aop:aspectj-autoproxy/>
<bean id="mySecurityManagerImpl" class="com.hejunfeng.spring.impl.MySecurityManagerImpl">
</bean>
<bean id="userManager" class="com.hejunfeng.spring.impl.UserManagerImpl"></bean>
</beans>
5、測試,和其它方法效果一致
package com.hejunfeng.test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.hejunfeng.spring.UserManager;
public class TestStatic {
public static void main(String[] args) {
BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");
UserManager userManager = (UserManager)factory.getBean("userManager");
userManager.addUser("何俊峯", "110") ;
}
}