Spring 框架学习(四):AOP
2017-10-26 15:09
302 查看
Spring 框架学习四AOP
概述
与 IoC 容器的衔接
代理工厂 ProxyFactory
AopProxy 实现
JdkDynamicAopProxy 代理类
Cglib2AopProxy 代理类
Aspect 是一种新的模块化机制,用来描述分散在对象、类或函数中的横切关注点。从关注点中分离出横切关注点是面向切面的程序设计的核心概念。分离关注点使得解决特定领域问题的代码从业务逻辑中独立出来,业务逻辑代码中不再含有针对特定领域问题代码的调用,业务领域同特定领域问题的关系通过切面来封装、维护,这样原本分散在整个应用程序中的变动就可以很好地管理起来。
由 AOP 联盟定义的 AOP 体系结构如下图所示:
AOP 体系结构分为从上到下、从使用到实现的三层结构。最高层是语言和开发环境,可以看到几个重要的概念:
1. 基础,可以视为待增强对象,或者说目标对象。
2. 切面,是对基础的增强应用。
3. 配置,负责衔接基础和切面。把基础和切面结合起来,从而完成切面对目标对象的编织实现。
第二个层次是为语言和开发环境提供支持的,在这个层次可以看到 AOP 框架的高层实现,主要包括配置和编织实现两部分内容。
最底层是编织的具体实现模块,是为 AOP 提供技术支持的各种技术:反射、程序预处理、拦截器框架、元数据处理。
对于 Spring 平台来说,AOP 是 Spring 框架的核心功能模块之一。AOP 与 IoC 容器的结合使用,为应用开发和 Spring 自身功能的扩展都提供了许多便利。下面先简单介绍一下 Spring AOP 的几个概念:
1. Advice 通知:定义在连接点做什么,为切面增强提供织入接口,相当于 AOP 体系结构中的“切面”。
2. Pointcut 切点:决定 Advice 通知应该作用于哪个连接点,也就是通过 Pointcut 来定义需要增强的方法的集合,集合的选取按照一定规则来完成。这个待增强的方法集合相当于 AOP 体系结构中的“基础”。
3. Advisor 通知器:负责把 Advice 和 Pointcut 结合起来,相当于 AOP 体系结构中的“配置”。
AspectJAutoProxyBeanDefinitionParser 类实现了 BeanDefinitionParser 接口,在其 parse 方法中注册了 AnnotationAwareAspectJAutoProxyCreator 类。
AnnotationAwareAspectJAutoProxyCreator 类实现了 BeanPostProcessor 接口,当 Spring 加载 Bean 时,会在实例化后调用其 postProcessAfterInitialization 方法
getAdvicesAndAdvisorsForBean 方法获取用户定义的 Advice,createProxy 方法负责创建代理,createProxy 主要是由 ProxyFactory 类创建代理。
在 getProxy 方法中,首先要调用 createAopProxy 创建代理类,createAopProxy 最终调用 DefaultAopProxyFactory 来创建代理:
createAopProxy 中根据一些信息来决定使用 JDK 代理 JdkDynamicAopProxy,还是 Cglib 代理 Cglib2AopProxy?
1. 如果目标类是接口,则使用 JDK 动态代理。
2. 如果配置了 < aop:aspectj-autoproxy proxy-target-class=”true”> 则优先使用 Cglib 代理。
3. 如果采用激进优化策略,则使用 Cglib 代理。
4. 如果目标类没有实现接口,则是以 Cglib 代理。
Proxy.newProxyInstance 有三个参数:classLoader、代理接口集合、InvocationHandler。第三个参数的值为 this,因为 JdkDynamicAopProxy 同时也是实现了 InvocationHandler 接口,该接口有一个 invoke 方法,负责调用增强方法和目标方法。具体 Proxy.newProxyInstance 是如何生成代理的,可以看看这篇文章:深度剖析JDK动态代理机制。
概述
与 IoC 容器的衔接
代理工厂 ProxyFactory
AopProxy 实现
JdkDynamicAopProxy 代理类
Cglib2AopProxy 代理类
Spring 框架学习(四):AOP
概述
AOP 是 Aspect Oriented Programming (面向切面编程)的简称,维基百科对 AOP 的描述如下:Aspect 是一种新的模块化机制,用来描述分散在对象、类或函数中的横切关注点。从关注点中分离出横切关注点是面向切面的程序设计的核心概念。分离关注点使得解决特定领域问题的代码从业务逻辑中独立出来,业务逻辑代码中不再含有针对特定领域问题代码的调用,业务领域同特定领域问题的关系通过切面来封装、维护,这样原本分散在整个应用程序中的变动就可以很好地管理起来。
由 AOP 联盟定义的 AOP 体系结构如下图所示:
AOP 体系结构分为从上到下、从使用到实现的三层结构。最高层是语言和开发环境,可以看到几个重要的概念:
1. 基础,可以视为待增强对象,或者说目标对象。
2. 切面,是对基础的增强应用。
3. 配置,负责衔接基础和切面。把基础和切面结合起来,从而完成切面对目标对象的编织实现。
第二个层次是为语言和开发环境提供支持的,在这个层次可以看到 AOP 框架的高层实现,主要包括配置和编织实现两部分内容。
最底层是编织的具体实现模块,是为 AOP 提供技术支持的各种技术:反射、程序预处理、拦截器框架、元数据处理。
对于 Spring 平台来说,AOP 是 Spring 框架的核心功能模块之一。AOP 与 IoC 容器的结合使用,为应用开发和 Spring 自身功能的扩展都提供了许多便利。下面先简单介绍一下 Spring AOP 的几个概念:
1. Advice 通知:定义在连接点做什么,为切面增强提供织入接口,相当于 AOP 体系结构中的“切面”。
2. Pointcut 切点:决定 Advice 通知应该作用于哪个连接点,也就是通过 Pointcut 来定义需要增强的方法的集合,集合的选取按照一定规则来完成。这个待增强的方法集合相当于 AOP 体系结构中的“基础”。
3. Advisor 通知器:负责把 Advice 和 Pointcut 结合起来,相当于 AOP 体系结构中的“配置”。
与 IoC 容器的衔接
在 AopNamespaceHandler 里,注册了对 aspectj-autoproxy 标签的解析类 AspectJAutoProxyBeanDefinitionParser。public class AopNamespaceHandler extends NamespaceHandlerSupport { public void init() { // In 2.0 XSD as well as in 2.1 XSD. registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser()); registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser()); registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator()); // Only in 2.0 XSD: moved to context namespace as of 2.1 registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser()); } }
AspectJAutoProxyBeanDefinitionParser 类实现了 BeanDefinitionParser 接口,在其 parse 方法中注册了 AnnotationAwareAspectJAutoProxyCreator 类。
class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser { public BeanDefinition parse(Element element, ParserContext parserContext) { AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element); extendBeanDefinition(element, parserContext); return null; } } public abstract class AopConfigUtils { public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) { return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source); } }
AnnotationAwareAspectJAutoProxyCreator 类实现了 BeanPostProcessor 接口,当 Spring 加载 Bean 时,会在实例化后调用其 postProcessAfterInitialization 方法
// 位于父类 AbstractAutoProxyCreator public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (!this.earlyProxyReferences.contains(cacheKey)) { // 进行代理 return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; } protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { // 部分特殊类,不做代理,直接返回 if (this.targetSourcedBeans.contains(beanName)) { return bean; } if (this.nonAdvisedBeans.contains(cacheKey)) { return bean; } if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.nonAdvisedBeans.add(cacheKey); return bean; } // 根据 class 获取对应的增强类 advice Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.add(cacheKey); // 创建代理 Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } this.nonAdvisedBeans.add(cacheKey); return bean; }
getAdvicesAndAdvisorsForBean 方法获取用户定义的 Advice,createProxy 方法负责创建代理,createProxy 主要是由 ProxyFactory 类创建代理。
protected Object createProxy( Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) { ProxyFactory proxyFactory = new ProxyFactory(); // Copy our properties (proxyTargetClass etc) inherited from ProxyConfig. proxyFactory.copyFrom(this); if (!shouldProxyTargetClass(beanClass, beanName)) { // 如果使用接口代理,则设置代理接口 Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, this.proxyClassLoader); for (Class<?> targetInterface : targetInterfaces) { proxyFactory.addInterface(targetInterface); } } // 根据 advice 创建 advisor Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); for (Advisor advisor : advisors) { proxyFactory.addAdvisor(advisor); } // 设置要代理的类 proxyFactory.setTargetSource(targetSource); // 定制代理,默认是一个空方法,子类可实现,面向未来设计 customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy); if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); } return proxyFactory.getProxy(this.proxyClassLoader); }
代理工厂 ProxyFactory
具体创建代理使用的 ProxyFactory 类,在设置了 advisor、targetInterface、targetSource 等之后,调用 getProxy 方法生成代理。public Object getProxy(ClassLoader classLoader) { return createAopProxy().getProxy(classLoader); } // 位于基类 ProxyCreatorSupport 中 protected final synchronized AopProxy createAopProxy() { if (!this.active) { activate(); } return getAopProxyFactory().createAopProxy(this); } // AopProxyFactory 目前只有一个实现类 DefaultAopProxyFactory public AopProxyFactory getAopProxyFactory() { return this.aopProxyFactory; }
在 getProxy 方法中,首先要调用 createAopProxy 创建代理类,createAopProxy 最终调用 DefaultAopProxyFactory 来创建代理:
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } if (targetClass.isInterface()) { return new JdkDynamicAopProxy(config); } if (!cglibAvailable) { throw new AopConfigException( "Cannot proxy target class because CGLIB2 is not available. " + "Add CGLIB to the class path or specify proxy interfaces."); } return CglibProxyFactory.createCglibProxy(config); } else { return new JdkDynamicAopProxy(config); } } private static class CglibProxyFactory { public static AopProxy createCglibProxy(AdvisedSupport advisedSupport) { return new Cglib2AopProxy(advisedSupport); } }
createAopProxy 中根据一些信息来决定使用 JDK 代理 JdkDynamicAopProxy,还是 Cglib 代理 Cglib2AopProxy?
1. 如果目标类是接口,则使用 JDK 动态代理。
2. 如果配置了 < aop:aspectj-autoproxy proxy-target-class=”true”> 则优先使用 Cglib 代理。
3. 如果采用激进优化策略,则使用 Cglib 代理。
4. 如果目标类没有实现接口,则是以 Cglib 代理。
AopProxy 实现
在上面提到的 JdkDynamicAopProxy 和 Cglib2AopProxy 都是 AopProxy 接口的子类,这两个类分别负责调用 JDK 动态代理和 Cglib 代理来生成代理类。public interface AopProxy { // 创建代理 Object getProxy(); // 使用指定的 classLoader 创建代理 Object getProxy(ClassLoader classLoader); }
JdkDynamicAopProxy 代理类
JdkDynamicAopProxy 实现了 AopProxy 接口,getProxy 方法中,主要是调用了 Proxy.newProxyInstance 方法来生成代理。final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable { public Object getProxy() { return getProxy(ClassUtils.getDefaultClassLoader()); } public Object getProxy(ClassLoader classLoader) { if (logger.isDebugEnabled()) { logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource()); } // 要代理的接口集合 Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); } }
Proxy.newProxyInstance 有三个参数:classLoader、代理接口集合、InvocationHandler。第三个参数的值为 this,因为 JdkDynamicAopProxy 同时也是实现了 InvocationHandler 接口,该接口有一个 invoke 方法,负责调用增强方法和目标方法。具体 Proxy.newProxyInstance 是如何生成代理的,可以看看这篇文章:深度剖析JDK动态代理机制。
public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; } final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable { 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 { // equals 方法处理 if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { return equals(args[0]); } // hashCode 方法处理 if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { 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; if (this.advised.exposeProxy) { // Make invocation available if necessary. oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } // May be null. Get as late as possible to minimize the time we "own" the target, // in case it comes from a pool. target = targetSource.getTarget(); if (target != null) { targetClass = target.getClass(); } // 获取当前方法的拦截器链 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); // 如果拦截器链为空则直接调用 if (chain.isEmpty()) { retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args); } else { // 将拦截器链和目标类等进行封装,并调用 proceed 执行 invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); retVal = invocation.proceed(); } if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { // 处理特殊情况 retVal = proxy; } return retVal; } finally { if (target != null && !targetSource.isStatic()) { targetSource.releaseTarget(target); } if (setProxyContext) { // Restore old proxy. AopContext.setCurrentProxy(oldProxy); } } } }
Cglib2AopProxy 代理类
Cglib2AopProxy 也是类似的,实现了 AopProxy 方法,在 getProxy 中使用 Cglib 的 Enhancer 来生成了代理类。final class Cglib2AopProxy implements AopProxy, Serializable { public Object getProxy(ClassLoader classLoader) { try { Class rootClass = this.advised.getTargetClass(); Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy"); Class proxySuperClass = rootClass; if (ClassUtils.isCglibProxyClass(rootClass)) { proxySuperClass = rootClass.getSuperclass(); Class[] additionalInterfaces = rootClass.getInterfaces(); for (Class additionalInterface : additionalInterfaces) { this.advised.addInterface(additionalInterface); } } // 校验,final 类不可被代理 validateClassIfNecessary(proxySuperClass); // 创建并设置 Enhancer... Enhancer enhancer = createEnhancer(); if (classLoader != null) { enhancer.setClassLoader(classLoader); if (classLoader instanceof SmartClassLoader && ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) { enhancer.setUseCache(false); } } enhancer.setSuperclass(proxySuperClass); enhancer.setStrategy(new UndeclaredThrowableStrategy(UndeclaredThrowableException.class)); enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised)); enhancer.setInterceptDuringConstruction(false); Callback[] callbacks = getCallbacks(rootClass); // 设置拦截器 enhancer.setCallbacks(callbacks); enhancer.setCallbackFilter(new ProxyCallbackFilter( this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset)); Class[] types = new Class[callbacks.length]; for (int x = 0; x < types.length; x++) { types[x] = callbacks[x].getClass(); } enhancer.setCallbackTypes(types); // 创建代理类 Object proxy; if (this.constructorArgs != null) { proxy = enhancer.create(this.constructorArgTypes, this.constructorArgs); } else { proxy = enhancer.create(); } return proxy; } catch (CodeGenerationException ex) { throw new AopConfigException("Could not generate CGLIB subclass of class [" + this.advised.getTargetClass() + "]: " + "Common causes of this problem include using a final class or a non-visible class", ex); } catch (IllegalArgumentException ex) { throw new AopConfigException("Could not generate CGLIB subclass of class [" + this.advised.getTargetClass() + "]: " + "Common causes of this problem include using a final class or a non-visible class", ex); } catch (Exception ex) { // TargetSource.getTarget() failed throw new AopConfigException("Unexpected AOP exception", ex); } } }
相关文章推荐
- Java框架spring 学习笔记(十四):注解aop操作
- 开源框架spring学习之道:AOP的深刻理解
- SSH与SSM学习之Spring14——动态代理之自己的AOP框架
- Java框架spring 学习笔记(十二):aop实例操作
- Spring学习框架之四(AOP)
- Spring AOP框架学习笔记(2):AOP拦截器调用的实现
- 框架学习之Spring 第三节 采用Spring实现AOP功能
- 框架学习—Spring的IOC容器之注解方式与AOP技术
- 框架学习之Spring 第三节 采用Spring实现AOP功能
- Jimoshi_Spring 框架学习(二)--AOP(面向切面)、AOP管理事务
- Web框架梳理:第四章:Spring学习入门、Spring属性注入、AOP编程、注解开发
- 学习笔记--代理与AOP及实现类似SPRING的可配置的AOP框架
- SSM框架系列学习总结2之Spring AOP
- Java代理学习-实现类似spring的可配置的AOP框架
- 开源框架spring学习之道:事务管理的深刻理解
- java框架Spring学习--Spring开发流程
- Spring Cloud与微服务学习总结(2)——Spring Cloud相较于Dubbo等RPC服务框架的优势
- Spring 4 学习笔记4:Java动态代理(Spring AOP原理)
- 通过学习spring优秀框架来学习设计模式---单例、工厂
- Spring学习笔记(一) Spring基础IOC、AOP