切入点简单的理解就是定义了咱们要切入的位置(在某些类 某些方法上切入)。所以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实现。
这里测试用例就不写了,文章还有不少介绍不全,慢慢修正补充。