切入點簡單的理解就是定義了咱們要切入的位置(在某些類 某些方法上切入)。所以Spring Aop的PointCut實現應該知足過濾獲得目標類目標方法的需求。
java
從PointCut接口定義咱們能夠看到ClassFilter和MethodMatcher,ClassFilter判斷那些類是要織入加強的,MethodMatcher是判斷哪些方法是知足織入加強的。spring
public interface Pointcut { ClassFilter getClassFilter(); MethodMatcher getMethodMatcher(); Pointcut TRUE = TruePointcut.INSTANCE; }
public interface ClassFilter { /** * 判斷給定的clazz是否知足織入條件,知足則返回true */ boolean matches(Class<?> clazz); /** * Canonical instance of a ClassFilter that matches all classes. * 這個默認的Filter是說全部的類都知足加強條件,都會返回true */ ClassFilter TRUE = TrueClassFilter.INSTANCE; }
public interface MethodMatcher { /** * Perform static checking whether the given method matches. 僅僅對方法的靜態匹配,不會檢驗方法具體參數值。 */ boolean matches(Method method, Class<?> targetClass); /** *是不是進行運行時方法匹配 */ boolean isRuntime(); /** 運行時 方法和方法參數同時都要進行匹配,知足則返回true */ boolean matches(Method method, Class<?> targetClass, Object... args); /** * Canonical instance that matches all methods. * 默認全部的方法都匹配 */ MethodMatcher TRUE = TrueMethodMatcher.INSTANCE; }
默認的pointcut實現有:NameMatchMethodPointcut,JdkRegexpMethodPointcut,AspectJExpressionPointcut等。這裏對NameMatchMethodPointcut與AspectJExpressionPointcut作下簡單介紹。編程
NameMatchMethodPointcut:僅僅經過對方法名字進行匹配織入位置。app
其中從其父類StaticMethodMatcherPointcut源碼能夠看到以下代碼,說明該pointcut會默認全部的類都知足要求,即不對類作過濾。ide
private ClassFilter classFilter = ClassFilter.TRUE; public void setClassFilter(ClassFilter classFilter) { this.classFilter = classFilter; } @Override public ClassFilter getClassFilter() { return this.classFilter; }
AspectJExpressionPointcut:自己實現了MethodMatcher和Pointcut接口。該pointcut主要特色是支持AspectJ Expression。用戶可使用該語法定義poincut ,知足一些通配需求。工具
Advice就是在上面咱們經過Pointcut定義好的位置織入的具體邏輯。Advice翻譯過來叫作通知或者加強,這裏咱們統一叫作加強。加強 按照與業務代碼執行順序的前後位置主要分爲三類:
post
BeforeAdvice:在業務代碼執行以前執行咱們織入的加強代碼。這裏BeforeAdvice接口去源碼中看其實沒有定義任何方法,是個空接口,咱們在寫具體的方法加強時是用的其子接口MethodBeforeAdvice。測試
AopAroundAdvice:在業務代碼執行的先後織入加強代碼。這種環繞加強spring藉助aop alliance的MethodInterceptor實現。咱們通常直接實現MethodInterceptor接口,實現咱們加強代碼便可。this
AfterAdvice:在業務代碼執行以後織入加強代碼。和BeforeAdvice同樣,它也是一個空接口。它具體又分爲AfterReturningAdvice,ThrowsAdvice。通常咱們實現直接實現AfterReturningAdvice接口便可。spa
spring 中的Aspect意思表明了一組poincut和advice,咱們常常利用aspect註解定義一個類,而後經過
<aop:aspectj-autoproxy/>自動去發現該aspect。advisor是指一個pointcut和對應的advice。從範圍上講aspect包含了advisor。
這裏介紹下默認的advisor DefaultPointcutAdvisor。
從類圖接口繼承上看 該默認的Advisor繼承了Advisor 和PoincutAdvisor。Advisor是爲了組裝advice(加強),PointcutAdvisor在Advisor 接口基礎上添加了Pointcut,定義了getPointcut接口。DefaultPointcutAdvisor能夠看出一個對advisor和pointcut實現了getter/setter接口的類。
AopProxy
這裏叫作AopProxy不是很好,由於AopProxy是產生proxy的工具類,後面沒有加Factory,也許Spring是爲了不與ProxyFactory衝突。AopProxy定義了getProxy方法。具體實現類有JdkDynamicAopProxy,ObjenesisCglibAopProxy(CglibAopProxy的擴展類)
這裏在介紹AopProxy產生proxy的原理以前先提下AdvisedSupport。AdvisedSupport類圖以下,它是AOP proxy配置管理的基類。
它裏面維護了AOP proxy代理生產所需的配置,好比Advisors,TargetSource,AdvisorChainFactory。它的子類ProxyCreatorSupport實現了對AopProxy(JdkDynamicAopProxy,ObjenesisCglibAopProxy)具體類裏的注入,實現代理建立功能。ProxyCreatorSupport是咱們下面要介紹的ProxyFactory與ProxyFactoryBean的父類。
JdkDynamicAopProxy:這裏咱們介紹下Jdk動態生產代理的原理。JdkDynamicAopProxy實現了JDK InvocationHandler接口。咱們先看下invoke方法具體代碼
//invocationHandler接口實現 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { MethodInvocation invocation; Object oldProxy = null; boolean setProxyContext = false; //獲取被代理的目標類實例 TargetSource targetSource = this.advised.targetSource; Class<?> targetClass = null; Object target = null; try { //對Object上的基本方法不處理。 if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { // The target does not implement the equals(Object) method itself. return equals(args[0]); } if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { // The target does not implement the hashCode() method itself. return hashCode(); } if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) { // Service invocations on ProxyConfig with the proxy config... return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); } Object retVal; //判斷是否把代理放到利用ThreadLocal實現的AOP上下文中 if (this.advised.exposeProxy) { // Make invocation available if necessary. oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } // 目標實例及目標類 target = targetSource.getTarget(); if (target != null) { targetClass = target.getClass(); } // 獲得咱們註冊的advice鏈,這一步很關鍵,它會根據咱們的註冊的pointcut來進行對目標類目標方法進行過濾, // 判斷方法是否知足定義的pointcut。下段代碼咱們具體分析 //若是chain爲空說明不須要任何加強, List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); // Check whether we have any advice. If we don't, we can fallback on direct // reflective invocation of the target, and avoid creating a MethodInvocation. if (chain.isEmpty()) { //沒有任何advice 直接對方法進行調用 Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } else { // We need to create a method invocation... //其中包含了代理類 目標對象 advice鏈 待調用方法。 invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // Proceed to the joinpoint through the interceptor chain. //對advice進行調用。 retVal = invocation.proceed(); } // Massage return value if necessary. Class<?> returnType = method.getReturnType(); if (retVal != null && retVal == target && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { retVal = proxy; } else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) { throw new AopInvocationException( "Null return value from advice does not match primitive return type for: " + method); } return retVal; } finally { if (target != null && !targetSource.isStatic()) { // Must have come from TargetSource. targetSource.releaseTarget(target); } if (setProxyContext) { // Restore old proxy. AopContext.setCurrentProxy(oldProxy); } } } //同Proxy生成代理 @Override public Object getProxy(ClassLoader classLoader) { Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); }
//類DefaultAdvisorChainFactory @Override public List<Object> getInterceptorsAndDynamicInterceptionAdvice( Advised config, Method method, Class<?> targetClass) { List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length); Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass()); boolean hasIntroductions = hasMatchingIntroductions(config, actualClass); AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); for (Advisor advisor : config.getAdvisors()) { if (advisor instanceof PointcutAdvisor) { // Add it conditionally. PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; //先根據ClassFilter來判斷目標類是否是知足Pointcut要求 if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) { //取得方法攔截器 MethodInterceptor[] interceptors = registry.getInterceptors(advisor); //得到pointcut上的MethodMatcher MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); //經過MethodMatcher來判斷方法是否符合poincut定義的需求。 if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) { //若是是運行時MethodMatcher則須要對方法參數值進行匹配。 if (mm.isRuntime()) { // Creating a new object instance in the getInterceptors() method // isn't a problem as we normally cache created chains. for (MethodInterceptor interceptor : interceptors) { interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm)); } } else { interceptorList.addAll(Arrays.asList(interceptors)); } } } } else if (advisor instanceof IntroductionAdvisor) { IntroductionAdvisor ia = (IntroductionAdvisor) advisor; if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } else { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } return interceptorList; }
由於JdkDynamicAopProxy採用JDK動態代理原理 它只能對實現相應接口的類進行代理,不能對沒有接口的實現類進行代理。
ObjenesisCglibAopProxy:CglibAOpProxy採用Cglib庫經過Enhancer來對類字節碼修改,實現AOP加強。CligbAopProxy能夠對沒有接口類進行代理,但不能對final類或方法繼續代理。
AOP proxies 代理工廠,主要是爲了編程( programmatic use)方式獲取proxy,而不是經過一個Bean Factory去獲取。ProxyFactory爲aop proxy提供了簡單的配置和獲取方法。
下面我看一個簡單的例子
//定義一個advice public class AopMethodBeforeAdvice implements MethodBeforeAdvice { @Override public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("before "+method.getName()+"-------"); } } // action public interface HelloAction { public String sayHello(String name); public String sayHelloA(String name); } //impl public class HelloActionImpl implements HelloAction { @Override public String sayHello(String name) { System.out.println("hello "+name); return "hello "+name; } @Override public String sayHelloA(String name) { System.out.println("helloA "+name); return "helloA "+name; } } // ProxyFactoryTest public class ProxyFactoryTest { @Test public void testGetProxy(){ ProxyFactory proxyFactory=new ProxyFactory(); //pointcut 匹配sayHello方法 NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut(); pointcut.setMappedNames(new String[] {"sayHello"}); //define advisor (pointcut + advice) DefaultPointcutAdvisor beforeAdvisor=new DefaultPointcutAdvisor(pointcut,new AopMethodBeforeAdvice()); HelloAction helloActionTarget=new HelloActionImpl(); //這樣就能夠採用JDK proxy生成方法 proxyFactory.setInterfaces(HelloAction.class); proxyFactory.setTarget(helloActionTarget); proxyFactory.addAdvisor(beforeAdvisor); HelloAction proxy=(HelloAction)proxyFactory.getProxy(); proxy.sayHello("yao"); proxy.sayHelloA("yaoA"); } }
咱們debug進去看看一個aop 代理是如何運行的
首先構造父類ProxyCreatorSupport,前面咱們介紹過,主要是增長屬性AopProxyFactory,生成一個AopPorxy(用來生產代理)
DefaultAopProxyFactory主要是根據有無接口來生產JDK or Cglib AopProxy
而後經過生成的AopProxy getProxy即獲取到代理對象。代理對象織入了advisor,具體執行就調用了咱們上面分析的JDK invoke 方法。(這裏假設採用JDK動態代理)
ProxyFactoryBean和ProxyFactory功能同樣,只不過ProxyFactoryBean實現了FactoryBean,與Spring IOC容器結合起來了。下面是其類圖,它並實現了BeanFactoryAware感知接口,實現BeanFactory的自動注入。與ProxyFactory同樣都是ProxyCreatorSupport子類。
咱們重點看下其getObject接口,
先判斷是不是產生單例代理仍是原型代理
產生單例代理就存下來,下次直接利用。具體過程都是先判處產生 createAopProxy(JDK or Cglib)而後getProxy便可。
原型的是每次連ProxyCreatorSupport都是新生成的,而後在createAopProxy,最後getProxy便可。
getProxy
總之 ProxyFactoryBean的主要目的就是把Aop 嵌入到IOC 容器中。
上面咱們講了這麼多都是針對一個目標一個目標配置的,若是目標不少怎麼辦呢?這裏Spring IOC容器經過BeanPostProcessor 來實現Aop 代理自動建立,BeanPostProcessor。常見的自動代理建立有BeanNameAutoProxyCreator,DefaultAdvisorAutoProxyCreator。咱們看看默認的DefaultAdvisorAutoProxyCreator的類圖
AbstractAutoProxyCreator實現了BeanPostProcessor的postProcessBeforeInstantiation
AbstractAutoProxyCreator的createProxy方法。採用ProxyFactory實現。
這裏測試用例就不寫了,文章還有不少介紹不全,慢慢修正補充。