(目标:AOP 实例化advisors)
AOP所需要的基础对象,在实例化前需要提前创建,那么对应到IOC的流程中,应该通过BeanPostProcessor来处理。
首先来分析下BeanPostProcessor的接口与实现类的关系,分析它执行的流程:
BeanPostProcessor的接口方法:
postProcessBeforeInitialization
postProcessAfterInitialization
InstantiationAwareBeanPostProcessor的方法:
postProcessBeforeInstantiation
postProcessAfterInstantiation
postProcessProperties
IOC中的进行AOP的对应流程源码:
AbstractAutowireCapableBeanFactory#createBean
protected Object createBean(String beanName, RootBeanDefinition mbd){
...
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
return beanInstance;
}
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
Class<?> targetType = determineTargetType(beanName, mbd);
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
return bean;
}
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
}
return null;
}
调用 InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation 是接口定义,
由实现类AbstractAutoProxyCreator#postProcessBeforeInstantiation来实现代理对象生成。
//org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
//生成代理对象
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
return proxy;
}
spring中动态代理的大致流程就是这样,接下来再回头分析下springAOP配置文件的解析工作。
解析的流程依然是以配置文件为例,入口在refreash防范中:
//1
//AbstractApplicationContext#refresh
// Tell the subclass to refresh the internal bean factory.
// 核心加载
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//2
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 核心加载
refreshBeanFactory();
return getBeanFactory();
}
//3
//AbstractRefreshableApplicationContext#refreshBeanFactory
protected final void refreshBeanFactory(){
...
// 核心加载
loadBeanDefinitions(beanFactory);
}
//4
//AbstractXmlApplicationContext#loadBeanDefinitions()
/**
* Loads the bean definitions via an XmlBeanDefinitionReader.
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
* @see #initBeanDefinitionReader
* @see #loadBeanDefinitions
*/
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// then proceed with actually loading the bean definitions.
// 核心加载
loadBeanDefinitions(beanDefinitionReader);
}
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
String[] configLocations = getConfigLocations();
if (configLocations != null) {
// 核心加载
reader.loadBeanDefinitions(configLocations);
}
}
//5
//AbstractBeanDefinitionReader#loadBeanDefinitions(...)
public int loadBeanDefinitions(String... locations) {
int count = 0;
for (String location : locations) {
// 核心加载
count += loadBeanDefinitions(location);
}
return count;
}
public int loadBeanDefinitions(String location) {
// Can only load single resources by absolute URL.
Resource resource = resourceLoader.getResource(location);
// 核心加载
int count = loadBeanDefinitions(resource);
return count;
}
}
//6
//XmlBeanDefinitionReader#loadBeanDefinitions()
public int loadBeanDefinitions(EncodedResource encodedResource) {
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
InputSource inputSource = new InputSource(inputStream);
// 核心加载
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
catch (IOException ex) {
}
}
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
{
Document doc = doLoadDocument(inputSource, resource);
// 核心加载
int count = registerBeanDefinitions(doc, resource);
return count;
}
public int registerBeanDefinitions(Document doc, Resource resource){
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
// 核心加载
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
//7
// DefaultBeanDefinitionDocumentReader#registerBeanDefinitions
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
// 核心加载
doRegisterBeanDefinitions(doc.getDocumentElement());
}
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
preProcessXml(root);
// 核心加载
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
// 核心加载 默认spring的配置元素
parseDefaultElement(ele, delegate);
}
else {
// 核心加载 自定义的配置元素
delegate.parseCustomElement(ele);
}
}
}
}
else {
// 核心加载
delegate.parseCustomElement(root);
}
}
AOP属于自定义的配置元素,接下来分析AOP标签元素的解析过程,由此可知晓BeanDefinition的封装,以及类之间的包含关系。
解析:<aop:config>
//1
//BeanDefinitionParserDelegate#parseCustomElement(...)
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(ele);
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
//核心解析流程
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
//2 org.springframework.beans.factory.xml.NamespaceHandler#parse
//3 org.springframework.beans.factory.xml.NamespaceHandlerSupport#parse
public BeanDefinition parse(Element element, ParserContext parserContext) {
BeanDefinitionParser parser = findParserForElement(element, parserContext);
return (parser != null ? parser.parse(element, parserContext) : null);
}
//4 org.springframework.beans.factory.xml.BeanDefinitionParser#parse
//5 org.springframework.aop.config.ConfigBeanDefinitionParser#parse
public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compositeDef =
new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
parserContext.pushContainingComponent(compositeDef);
//核心解析流程 注册自动代理生成器 AspectJAwareAdvisorAutoProxyCreator
configureAutoProxyCreator(parserContext, element);
List<Element> childElts = DomUtils.getChildElements(element);
for (Element elt: childElts) {
String localName = parserContext.getDelegate().getLocalName(elt);
if (POINTCUT.equals(localName)) {
//核心解析流程
parsePointcut(elt, parserContext);
}
else if (ADVISOR.equals(localName)) {
//核心解析流程
parseAdvisor(elt, parserContext);
}
else if (ASPECT.equals(localName)) {
//核心解析流程
parseAspect(elt, parserContext);
}
}
parserContext.popAndRegisterContainingComponent();
return null;
}
/**
* Configures the auto proxy creator needed to support the {@link BeanDefinition BeanDefinitions}
* created by the '{@code <aop:config/>}' tag. Will force class proxying if the
* '{@code proxy-target-class}' attribute is set to '{@code true}'.
* @see AopNamespaceUtils
*/
private void configureAutoProxyCreator(ParserContext parserContext, Element element) {
//核心解析流程
AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
}
// 6 //org.springframework.aop.config.AopNamespaceUtils#registerAspectJAutoProxyCreatorIfNecessary
public static void registerAspectJAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
//核心解析流程
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
registerComponentIfNecessary(beanDefinition, parserContext);
}
public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
//核心解析流程
return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
}
Parser解析器的类关系:
ConfigBeanDefinitionParser 用来解析自定义标签 <aop:config>
AspectJAutoProxyBeanDefinitionParser 用来解析注解 @AspectJ
解析<aop:aspect>的时候,会准备相关材料,需要先充分掌握以下类的关系,才能理解此处的解析:
//一级对象
class AspectJPointcutAdvisor {
//二级对象
private final AbstractAspectJAdvice advice;
private final Pointcut pointcut;
@Nullable
private Integer order;
}
//二级对象
class AbstractAspectJAdvice{
//切面方法
protected transient Method aspectJAdviceMethod;
//切面表达式
private final AspectJExpressionPointcut pointcut;
//实例工厂
private final AspectInstanceFactory aspectInstanceFactory;
}
// org.springframework.aop.config.ConfigBeanDefinitionParser#parseAspect
//1
private void parseAspect(Element aspectElement, ParserContext parserContext) {
String aspectId = aspectElement.getAttribute(ID);
String aspectName = aspectElement.getAttribute(REF);
try {
this.parseState.push(new AspectEntry(aspectId, aspectName));
List<BeanDefinition> beanDefinitions = new ArrayList<>();
List<BeanReference> beanReferences = new ArrayList<>();
// We have to parse "advice" and all the advice kinds in one loop, to get the
// ordering semantics right.
NodeList nodeList = aspectElement.getChildNodes();
boolean adviceFoundAlready = false;
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (isAdviceNode(node, parserContext)) {
//核心流程 解析增强
AbstractBeanDefinition advisorDefinition = parseAdvice(
aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
beanDefinitions.add(advisorDefinition);
}
}
AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(
aspectElement, aspectId, beanDefinitions, beanReferences, parserContext);
parserContext.pushContainingComponent(aspectComponentDefinition);
List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
for (Element pointcutElement : pointcuts) {
//核心流程 解析切点
parsePointcut(pointcutElement, parserContext);
}
parserContext.popAndRegisterContainingComponent();
}
finally {
this.parseState.pop();
}
}
//2 准备 构造切面对象的三种材料 method;factory;point
/**
* Parses one of '{@code before}', '{@code after}', '{@code after-returning}',
* '{@code after-throwing}' or '{@code around}' and registers the resulting
* BeanDefinition with the supplied BeanDefinitionRegistry.
* @return the generated advice RootBeanDefinition
*/
private AbstractBeanDefinition parseAdvice(
String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext,
List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
try {
this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement)));
// create the method factory bean
RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
methodDefinition.setSynthetic(true);
// create instance factory definition
RootBeanDefinition aspectFactoryDef =
new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
aspectFactoryDef.setSynthetic(true);
// register the pointcut
AbstractBeanDefinition adviceDef = createAdviceDefinition(
adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
beanDefinitions, beanReferences);
// configure the advisor
RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
advisorDefinition.setSource(parserContext.extractSource(adviceElement));
advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
advisorDefinition.getPropertyValues().add(
ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
}
// register the final advisor
parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);
return advisorDefinition;
}
finally {
this.parseState.pop();
}
}
//4
/**
* Creates the RootBeanDefinition for a POJO advice bean. Also causes pointcut
* parsing to occur so that the pointcut may be associate with the advice bean.
* This same pointcut is also configured as the pointcut for the enclosing
* Advisor definition using the supplied MutablePropertyValues.
*/
private AbstractBeanDefinition createAdviceDefinition(
Element adviceElement, ParserContext parserContext, String aspectName, int order,
RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));
adviceDefinition.setSource(parserContext.extractSource(adviceElement));
adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName);
adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order);
if (adviceElement.hasAttribute(RETURNING)) {
adviceDefinition.getPropertyValues().add(
RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING));
}
if (adviceElement.hasAttribute(THROWING)) {
adviceDefinition.getPropertyValues().add(
THROWING_PROPERTY, adviceElement.getAttribute(THROWING));
}
if (adviceElement.hasAttribute(ARG_NAMES)) {
adviceDefinition.getPropertyValues().add(
ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES));
}
ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues();
cav.addIndexedArgumentValue(METHOD_INDEX, methodDef);
Object pointcut = parsePointcutProperty(adviceElement, parserContext);
if (pointcut instanceof BeanDefinition) {
cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcut);
beanDefinitions.add((BeanDefinition) pointcut);
}
else if (pointcut instanceof String) {
RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut);
cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef);
beanReferences.add(pointcutRef);
}
cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef);
return adviceDefinition;
}