Spring框架系列(10) - Spring AOP实现原理详解之AOP代理的创建
Posted realpdai
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring框架系列(10) - Spring AOP实现原理详解之AOP代理的创建相关的知识,希望对你有一定的参考价值。
上文我们介绍了Spring AOP原理解析的切面实现过程(将切面类的所有切面方法根据使用的注解生成对应Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor)。本文在此基础上继续介绍,代理(cglib代理和JDK代理)的创建过程。@pdai
引入
前文主要Spring AOP原理解析的切面实现过程(加载配置,将切面类的所有切面方法根据使用的注解生成对应Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor)。
同时我们也总结了Spring AOP初始化的过程,具体如下:
- 由IOC Bean加载方法栈中找到parseCustomElement方法,找到parse
aop:aspectj-autoproxy
的handler(org.springframework.aop.config.AopNamespaceHandler) - AopNamespaceHandler注册了
<aop:aspectj-autoproxy/>
的解析类是AspectJAutoProxyBeanDefinitionParser - AspectJAutoProxyBeanDefinitionParser的parse 方法 通过AspectJAwareAdvisorAutoProxyCreator类去创建
- AspectJAwareAdvisorAutoProxyCreator实现了两类接口,BeanFactoryAware和BeanPostProcessor;根据Bean生命周期方法找到两个核心方法:postProcessBeforeInstantiation和postProcessAfterInitialization
- postProcessBeforeInstantiation:主要是处理使用了@Aspect注解的切面类,然后将切面类的所有切面方法根据使用的注解生成对应Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor
- postProcessAfterInitialization:主要负责将Advisor注入到合适的位置,创建代理(cglib或jdk),为后面给代理进行增强实现做准备。
本文接着介绍postProcessAfterInitialization的方法,即Spring AOP的代理(cglib或jdk)的创建过程。
代理的创建
创建代理的方法是postProcessAfterInitialization:如果bean被子类标识为代理,则使用配置的拦截器创建一个代理
/**
* Create a proxy with the configured interceptors if the bean is
* identified as one to proxy by the subclass.
* @see #getAdvicesAndAdvisorsForBean
*/
@Override
Object (@Nullable Object bean, String beanName)
(bean != )
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 如果不是提前暴露的代理
(.earlyProxyReferences.remove(cacheKey) != bean)
wrapIfNecessary(bean, beanName, cacheKey);
bean;
wrapIfNecessary方法主要用于判断是否需要创建代理,如果Bean能够获取到advisor才需要创建代理
/**
* Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
* @param bean the raw bean instance
* @param beanName the name of the bean
* @param cacheKey the cache key for metadata access
* @return a proxy wrapping the bean, or the raw bean instance as-is
*/
Object (Object bean, String beanName, Object cacheKey)
// 如果bean是通过TargetSource接口获取
(beanName != && .targetSourcedBeans.contains(beanName))
bean;
// 如果bean是切面类
(Boolean.FALSE.equals(.advisedBeans.get(cacheKey)))
bean;
// 如果是aop基础类?是否跳过?
(isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName))
.advisedBeans.put(cacheKey, Boolean.FALSE);
bean;
// 重点:获取所有advisor,如果没有获取到,那说明不要进行增强,也就不需要代理了。
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, );
(specificInterceptors != DO_NOT_PROXY)
.advisedBeans.put(cacheKey, Boolean.TRUE);
// 重点:创建代理
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, SingletonTargetSource(bean));
.proxyTypes.put(cacheKey, proxy.getClass());
proxy;
.advisedBeans.put(cacheKey, Boolean.FALSE);
bean;
获取所有的Advisor
我们看下获取所有advisor的方法getAdvicesAndAdvisorsForBean
@Override
@Nullable
Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource)
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
(advisors.isEmpty())
DO_NOT_PROXY;
advisors.toArray();
通过findEligibleAdvisors方法获取advisor, 如果获取不到返回DO_NOT_PROXY(不需要创建代理),findEligibleAdvisors方法如下
/**
* Find all eligible Advisors for auto-proxying this class.
* @param beanClass the clazz to find advisors for
* @param beanName the name of the currently proxied bean
* @return the empty List, not @code null,
* if there are no pointcuts or interceptors
* @see #findCandidateAdvisors
* @see #sortAdvisors
* @see #extendAdvisors
*/
List<Advisor> (Class<?> beanClass, String beanName)
// 和上文一样,获取所有切面类的切面方法生成Advisor
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 找到这些Advisor中能够应用于beanClass的Advisor
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
// 如果需要,交给子类拓展
extendAdvisors(eligibleAdvisors);
// 对Advisor排序
(!eligibleAdvisors.isEmpty())
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
eligibleAdvisors;
获取所有切面类的切面方法生成Advisor
/**
* Find all candidate Advisors to use in auto-proxying.
* @return the List of candidate Advisors
*/
List<Advisor> ()
Assert.state(.advisorRetrievalHelper != , "No BeanFactoryAdvisorRetrievalHelper available");
.advisorRetrievalHelper.findAdvisorBeans();
找到这些Advisor中能够应用于beanClass的Advisor
/**
* Determine the sublist of the @code candidateAdvisors list
* that is applicable to the given class.
* @param candidateAdvisors the Advisors to evaluate
* @param clazz the target class
* @return sublist of Advisors that can apply to an object of the given class
* (may be the incoming List as-is)
*/
List<Advisor> (List<Advisor> candidateAdvisors, Class<?> clazz)
(candidateAdvisors.isEmpty())
candidateAdvisors;
List<Advisor> eligibleAdvisors = ArrayList<>();
(Advisor candidate : candidateAdvisors)
// 通过Introduction实现的advice
(candidate IntroductionAdvisor && canApply(candidate, clazz))
eligibleAdvisors.add(candidate);
hasIntroductions = !eligibleAdvisors.isEmpty();
(Advisor candidate : candidateAdvisors)
(candidate IntroductionAdvisor)
// already processed
;
// 是否能够应用于clazz的Advice
(canApply(candidate, clazz, hasIntroductions))
eligibleAdvisors.add(candidate);
eligibleAdvisors;
创建代理的入口方法
获取所有advisor后,如果有advisor,则说明需要增强,即需要创建代理,创建代理的方法如下:
/**
* Create an AOP proxy for the given bean.
* @param beanClass the class of the bean
* @param beanName the name of the bean
* @param specificInterceptors the set of interceptors that is
* specific to this bean (may be empty, but not null)
* @param targetSource the TargetSource for the proxy,
* already pre-configured to access the bean
* @return the AOP proxy for the bean
* @see #buildAdvisors
*/
Object (Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource)
(.beanFactory ConfigurableListableBeanFactory)
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) .beanFactory, beanName, beanClass);
ProxyFactory proxyFactory = ProxyFactory();
proxyFactory.copyFrom();
(proxyFactory.isProxyTargetClass())
// Explicit handling of JDK proxy targets (for introduction advice scenarios)
(Proxy.isProxyClass(beanClass))
// Must allow for introductions; cant just set interfaces to the proxys interfaces only.
(Class<?> ifc : beanClass.getInterfaces())
proxyFactory.addInterface(ifc);
// No proxyTargetClass flag enforced, lets apply our default checks...
(shouldProxyTargetClass(beanClass, beanName))
proxyFactory.setProxyTargetClass();
evaluateProxyInterfaces(beanClass, proxyFactory);
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(.freezeProxy);
(advisorsPreFiltered())
proxyFactory.setPreFiltered();
// Use original ClassLoader if bean class not locally loaded in overriding class loader
ClassLoader classLoader = getProxyClassLoader();
(classLoader SmartClassLoader && classLoader != beanClass.getClassLoader())
classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
proxyFactory.getProxy(classLoader);
proxyFactory.getProxy(classLoader)
/**
* Create a new proxy according to the settings in this factory.
* <p>Can be called repeatedly. Effect will vary if weve added
* or removed interfaces. Can add and remove interceptors.
* <p>Uses the given class loader (if necessary for proxy creation).
* @param classLoader the class loader to create the proxy with
* (or @code null for the low-level proxy facilitys default)
* @return the proxy object
*/
Object (@Nullable ClassLoader classLoader)
createAopProxy().getProxy(classLoader);
依据条件创建代理(jdk或cglib)
DefaultAopProxyFactory.createAopProxy
@Override
AopProxy (AdvisedSupport config) AopConfigException
(!NativeDetector.inNativeImage() &&
(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)))
Class<?> targetClass = config.getTargetClass();
(targetClass == )
AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
(targetClass.isInterface() || Proxy.isProxyClass(targetClass))
JdkDynamicAopProxy(config);
ObjenesisCglibAopProxy(config);
JdkDynamicAopProxy(config);
几个要点
- config.isOptimize() 是通过optimize设置,表示配置是自定义的,默认是false;
- config.isProxyTargetClass()是通过
<aop:config proxy-target-class="true" />
来配置的,表示优先使用cglib代理,默认是false; - hasNoUserSuppliedProxyInterfaces(config) 表示是否目标类实现了接口
由此我们可以知道:
Spring默认在目标类实现接口时是通过JDK代理实现的,只有非接口的是通过Cglib代理实现的。当设置proxy-target-class为true时在目标类不是接口或者代理类时优先使用cglib代理实现。
更多文章
首先, 从Spring框架的整体架构和组成对整体框架有个认知。
- Spring是什么?它是怎么诞生的?有哪些主要的组件和核心功能呢? 本文通过这几个问题帮助你构筑Spring和Spring Framework的整体认知。
其次,通过案例引出Spring的核心(IoC和AOP),同时对IoC和AOP进行案例使用分析。
- 上文中我们简单介绍了Spring和Spring Framework的组件,那么这些Spring Framework组件是如何配合工作的呢?本文主要承接上文,向你展示Spring Framework组件的典型应用场景和基于这个场景设计出的简单案例,并以此引出Spring的核心要点,比如IOC和AOP等;在此基础上还引入了不同的配置方式, 如XML,Java配置和注解方式的差异。
- 在Spring基础 - Spring简单例子引入Spring的核心中向你展示了IoC的基础含义,同时以此发散了一些IoC相关知识点; 本节将在此基础上进一步解读IOC的含义以及IOC的使用方式
- 在Spring基础 - Spring简单例子引入Spring的核心中向你展示了AOP的基础含义,同时以此发散了一些AOP相关知识点; 本节将在此基础上进一步解读AOP的含义以及AOP的使用方式。
基于Spring框架和IOC,AOP的基础,为构建上层web应用,需要进一步学习SpringMVC。
- 前文我们介绍了Spring框架和Spring框架中最为重要的两个技术点(IOC和AOP),那我们如何更好的构建上层的应用呢(比如web 应用),这便是SpringMVC;Spring MVC是Spring在Spring Container Core和AOP等技术基础上,遵循上述Web MVC的规范推出的web开发框架,目的是为了简化Java栈的web开发。 本文主要介绍SpringMVC的请求流程和基础案例的编写和运行。
Spring进阶 - IoC,AOP以及SpringMVC的源码分析
- 在对IoC有了初步的认知后,我们开始对IOC的实现原理进行深入理解。本文将帮助你站在设计者的角度去看IOC最顶层的结构设计
- 上文,我们看了IOC设计要点和设计结构;紧接着这篇,我们可以看下源码的实现了:Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的
- 上文,我们看了IOC设计要点和设计结构;以及Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的;容器中存放的是Bean的定义即BeanDefinition放到beanDefinitionMap中,本质上是一个
ConcurrentHashMap<String, Object>
;并且BeanDefinition接口中包含了这个类的Class信息以及是否是单例等。那么如何从BeanDefinition中实例化Bean对象呢,这是本文主要研究的内容?
- 前文,我们分析了Spring IOC的初始化过程和Bean的生命周期等,而Spring AOP也是基于IOC的Bean加载来实现的。本文主要介绍Spring AOP原理解析的切面实现过程(将切面类的所有切面方法根据使用的注解生成对应Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor,为后续交给代理增强实现做准备的过程)。
- 上文我们介绍了Spring AOP原理解析的切面实现过程(将切面类的所有切面方法根据使用的注解生成对应Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor)。本文在此基础上继续介绍,代理(cglib代理和JDK代理)的实现过程。
- 我们在前文中已经介绍了SpringAOP的切面实现和创建动态代理的过程,那么动态代理是如何工作的呢?本文主要介绍Cglib动态代理的案例和SpringAOP实现的原理。
- 上文我们学习了SpringAOP Cglib动态代理的实现,本文主要是SpringAOP JDK动态代理的案例和实现部分。
- 前文我们有了IOC的源码基础以及SpringMVC的基础,我们便可以进一步深入理解SpringMVC主要实现原理,包含DispatcherServlet的初始化过程和DispatcherServlet处理请求的过程的源码解析。本文是第一篇:DispatcherServlet的初始化过程的源码解析。
- 前文我们有了IOC的源码基础以及SpringMVC的基础,我们便可以进一步深入理解SpringMVC主要实现原理,包含DispatcherServlet的初始化过程和DispatcherServlet处理请求的过程的源码解析。本文是第二篇:DispatcherServlet处理请求的过程的源码解析。
以上是关于Spring框架系列(10) - Spring AOP实现原理详解之AOP代理的创建的主要内容,如果未能解决你的问题,请参考以下文章
Spring框架系列 - Spring和Spring框架组成