一、前言
首先我们先准备一下spring 事务的配置文件,具体内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:property-placeholder location="classpath:dbconfig.properties"></context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" >
<constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="bookService" class="com.mashibing.tx.xml.service.BookService">
<property name="bookDao" ref="bookDao"></property>
</bean>
<bean id="bookDao" class="com.mashibing.tx.xml.dao.BookDao">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
<aop:config>
<aop:pointcut id="txPoint" expression="execution(* com.mashibing.tx.xml.*.*.*(..))"/>
<aop:advisor advice-ref="myAdvice" pointcut-ref="txPoint"></aop:advisor>
</aop:config>
<tx:advice id="myAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="checkout" propagation="REQUIRED" />
<tx:method name="updateStock" propagation="REQUIRES_NEW" />
</tx:attributes>
</tx:advice>
</beans>
然后是我们对应的启动类,代码如下:
public static void main(String[] args) throws SQLException {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"d:\\code");
ApplicationContext context = new ClassPathXmlApplicationContext("tx.xml");
BookService bookService = context.getBean("bookService", BookService.class);
bookService.checkout("zhangsan",1);
}
二、源码分析
在启动spring容器之前首先会去解析我们的配置文件,在之前介绍过解析配置文件是通过一系列重载的loadBeanDefinitionsf方法,最后就会通过调用对应parser对象解析配置文件。核心代码如下:
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)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
@Nullable
public BeanDefinition parseCustomElement(Element ele) {
return parseCustomElement(ele, null);
}
@Nullable
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
// 获取对应的命名空间
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
}
// 根据命名空间找到对应的NamespaceHandlerspring
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
// 调用自定义的NamespaceHandler进行解析
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
然后就会按照我们配置文件的解析顺序,首先就会解析aop-poincut标签
我们看下他是如何去解析aop-pointcut标签的。
/**
* 解析切入点
*
* Parses the supplied {@code <pointcut>} and registers the resulting
* Pointcut with the BeanDefinitionRegistry.
*/
private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
// 切入点的唯一标识
String id = pointcutElement.getAttribute(ID);
// 获取切入点的表达式
String expression = pointcutElement.getAttribute(EXPRESSION);
AbstractBeanDefinition pointcutDefinition = null;
try {
// 采用栈保存切入点
this.parseState.push(new PointcutEntry(id));
// 创建切入点bean对象
// beanClass为AspectJExpressionPointcut.class。并且设置属性expression到该beanClass中
pointcutDefinition = createPointcutDefinition(expression);
pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));
String pointcutBeanName = id;
if (StringUtils.hasText(pointcutBeanName)) {
// 注册bean对象
parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
}
else {
pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
}
parserContext.registerComponent(
new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
}
finally {
// 创建后移除
this.parseState.pop();
}
return pointcutDefinition;
}
然后继续往下跟createPointcutDefinition。
/**
* Creates a {@link BeanDefinition} for the {@link AspectJExpressionPointcut} class using
* the supplied pointcut expression.
*/
protected AbstractBeanDefinition createPointcutDefinition(String expression) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(AspectJExpressionPointcut.class);
beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
beanDefinition.setSynthetic(true);
beanDefinition.getPropertyValues().add(EXPRESSION, expression);
return beanDefinition;
}
这里就会设置一个AspectJExpressionPointCut对象,继续往下跟。
此时就会往容器中注入了一个AspectJExpressionPointCut的BeanDefinition信息。继续解析下一个标签。
此时就会解析到advisor对象,还记得之前aop中是如果解析advisor对象的吗?aop是advisor对象里面包着一层advice对象,而advice对象分为AspectJMethodBeforAdvice,AspectJAfterAdvice、AspectJAfterReturingAdvice、AspectJAroundAdvice、AspectJAfterThrowingAdvice。而事务这里这里有所不一样,我们继续往下跟。
/**
* 解析advisor顾问类
*
* Parses the supplied {@code <advisor>} element and registers the resulting
* {@link org.springframework.aop.Advisor} and any resulting {@link org.springframework.aop.Pointcut}
* with the supplied {@link BeanDefinitionRegistry}.
*/
private void parseAdvisor(Element advisorElement, ParserContext parserContext) {
// 解析<aop:advisor>节点,最终创建的beanClass为`DefaultBeanFactoryPointcutAdvisor`
// 另外advice-ref属性必须定义,其与内部属性adviceBeanName对应
AbstractBeanDefinition advisorDef = createAdvisorBeanDefinition(advisorElement, parserContext);
String id = advisorElement.getAttribute(ID);
try {
// 注册到bean工厂
this.parseState.push(new AdvisorEntry(id));
String advisorBeanName = id;
if (StringUtils.hasText(advisorBeanName)) {
parserContext.getRegistry().registerBeanDefinition(advisorBeanName, advisorDef);
}
else {
advisorBeanName = parserContext.getReaderContext().registerWithGeneratedName(advisorDef);
}
// 解析point-cut属性并赋值到DefaultBeanFactoryPointcutAdvisor#pointcut内部属性
Object pointcut = parsePointcutProperty(advisorElement, parserContext);
if (pointcut instanceof BeanDefinition) {
advisorDef.getPropertyValues().add(POINTCUT, pointcut);
parserContext.registerComponent(
new AdvisorComponentDefinition(advisorBeanName, advisorDef, (BeanDefinition) pointcut));
}
else if (pointcut instanceof String) {
advisorDef.getPropertyValues().add(POINTCUT, new RuntimeBeanReference((String) pointcut));
parserContext.registerComponent(
new AdvisorComponentDefinition(advisorBeanName, advisorDef));
}
}
finally {
this.parseState.pop();
}
}
继续往下跟createAdvisorBeanDefinition看他是如何创建advisor对象的。
/**
* Create a {@link RootBeanDefinition} for the advisor described in the supplied. Does <strong>not</strong>
* parse any associated '{@code pointcut}' or '{@code pointcut-ref}' attributes.
*/
private AbstractBeanDefinition createAdvisorBeanDefinition(Element advisorElement, ParserContext parserContext) {
RootBeanDefinition advisorDefinition = new RootBeanDefinition(DefaultBeanFactoryPointcutAdvisor.class);
advisorDefinition.setSource(parserContext.extractSource(advisorElement));
String adviceRef = advisorElement.getAttribute(ADVICE_REF);
if (!StringUtils.hasText(adviceRef)) {
parserContext.getReaderContext().error(
"'advice-ref' attribute contains empty value.", advisorElement, this.parseState.snapshot());
}
else {
advisorDefinition.getPropertyValues().add(
ADVICE_BEAN_NAME, new RuntimeBeanNameReference(adviceRef));
}
if (advisorElement.hasAttribute(ORDER_PROPERTY)) {
advisorDefinition.getPropertyValues().add(
ORDER_PROPERTY, advisorElement.getAttribute(ORDER_PROPERTY));
}
return advisorDefinition;
}
这里看到他注入的是DefaultBeanFactoryPointcutAdvisor对象,然后就会设置一系列属性,包括advice-ref等。
到此,我们的aop:pointcut以及aop:advisor标签已经解析完毕,总结一下,他就是生成了AspectJExpressionPointcut以及DefaultBeanFactoryPointcutAdvisor两个BeanDefination。
接下来就是解析对应的tx标签。
就会在AbstractBeanDefinitionParser解析对应的tx标签。为啥会在在这里去解析,可以去看一下之前xml配置文件解析去查看是如何去查找对应的parser对象的。
我们继续往下看具体的解析逻辑。
@Override
@Nullable
public final BeanDefinition parse(Element element, ParserContext parserContext) {
AbstractBeanDefinition definition = parseInternal(element, parserContext);
if (definition != null && !parserContext.isNested()) {
try {
String id = resolveId(element, definition, parserContext);
if (!StringUtils.hasText(id)) {
parserContext.getReaderContext().error(
"Id is required for element '" + parserContext.getDelegate().getLocalName(element)
+ "' when used as a top-level tag", element);
}
String[] aliases = null;
if (shouldParseNameAsAliases()) {
String name = element.getAttribute(NAME_ATTRIBUTE);
if (StringUtils.hasLength(name)) {
aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
}
}
// 将AbstractBeanDefinition转换为BeanDefinitionHolder并注册
BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
registerBeanDefinition(holder, parserContext.getRegistry());
if (shouldFireEvents()) {
// 通知监听器进行处理
BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
postProcessComponentDefinition(componentDefinition);
parserContext.registerComponent(componentDefinition);
}
}
catch (BeanDefinitionStoreException ex) {
String msg = ex.getMessage();
parserContext.getReaderContext().error((msg != null ? msg : ex.toString()), element);
return null;
}
}
return definition;
}
往下跟parseInternal看他是如何生成BeanDefinition信息的。
@Override
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
String parentName = getParentName(element);
if (parentName != null) {
builder.getRawBeanDefinition().setParentName(parentName);
}
// 获取自定义标签中的class,此时会调用自定义解析器
Class<?> beanClass = getBeanClass(element);
if (beanClass != null) {
builder.getRawBeanDefinition().setBeanClass(beanClass);
}
else {
// 若子类没有重写getBeanClass方法则尝试检查子类是否重写getBeanClassName方法
String beanClassName = getBeanClassName(element);
if (beanClassName != null) {
builder.getRawBeanDefinition().setBeanClassName(beanClassName);
}
}
builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
BeanDefinition containingBd = parserContext.getContainingBeanDefinition();
if (containingBd != null) {
// Inner bean definition must receive same scope as containing bean.
// 若存在父类则使用父类的scope属性
builder.setScope(containingBd.getScope());
}
if (parserContext.isDefaultLazyInit()) {
// Default-lazy-init applies to custom bean definitions as well.
// 配置延迟加载
builder.setLazyInit(true);
}
// 调用子类重写的doParse方法进行解析
doParse(element, parserContext, builder);
return builder.getBeanDefinition();
}
然后去看下对应的getClass方法。
可以看到 他给我们返回的是一个TransactionInterceptor对象,我们来看下这个是个啥东西?
还记得我们之前在讲aop的时候,我们要实现一个拦截器,要么就是就是实现对应的MethodInterceptor接口,要么是通过适配器来返回对应的Interceptor。而AOP也是这样子,MethodBefore跟AfterReturing是没有实现MethodInterceptor而是通过适配器来获取的。
对应的源码位置为:DynamicAdvisedInterceptor通过对应的advisor获取对应的Interceptor的时候去获取的。
// 将 Advisor转换为 MethodInterceptor
@Override
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<>(3);
// 从Advisor中获取 Advice
Advice advice = advisor.getAdvice();
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) {
// 转换为对应的 MethodInterceptor类型
// AfterReturningAdviceInterceptor MethodBeforeAdviceInterceptor ThrowsAdviceInterceptor
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[0]);
}
而我们知道AOP是基于IOC的一个拓展,而事务又是基于AOP的一个拓展,所以这个TransactionInterceptor他直接实现了对应的MethodIntercetor接口,他就能够实现拦截器功能,然后在对应的invoke方法实现对应的控制事务的方法,这个后续会看到,我们先继续往下看他对应的核心对象生成。
然后我们继续接着往下看对应doParse方法。
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
builder.addPropertyReference("transactionManager", TxNamespaceHandler.getTransactionManagerName(element));
List<Element> txAttributes = DomUtils.getChildElementsByTagName(element, ATTRIBUTES_ELEMENT);
if (txAttributes.size() > 1) {
parserContext.getReaderContext().error(
"Element <attributes> is allowed at most once inside element <advice>", element);
}
else if (txAttributes.size() == 1) {
// Using attributes source.
Element attributeSourceElement = txAttributes.get(0);
RootBeanDefinition attributeSourceDefinition = parseAttributeSource(attributeSourceElement, parserContext);
builder.addPropertyValue("transactionAttributeSource", attributeSourceDefinition);
}
else {
// Assume annotations source.
builder.addPropertyValue("transactionAttributeSource",
new RootBeanDefinition("org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"));
}
}
这里就会接着去解析对应的<tx:attributes>标签。
private RootBeanDefinition parseAttributeSource(Element attrEle, ParserContext parserContext) {
List<Element> methods = DomUtils.getChildElementsByTagName(attrEle, METHOD_ELEMENT);
ManagedMap<TypedStringValue, RuleBasedTransactionAttribute> transactionAttributeMap =
new ManagedMap<>(methods.size());
transactionAttributeMap.setSource(parserContext.extractSource(attrEle));
for (Element methodEle : methods) {
String name = methodEle.getAttribute(METHOD_NAME_ATTRIBUTE);
TypedStringValue nameHolder = new TypedStringValue(name);
nameHolder.setSource(parserContext.extractSource(methodEle));
RuleBasedTransactionAttribute attribute = new RuleBasedTransactionAttribute();
String propagation = methodEle.getAttribute(PROPAGATION_ATTRIBUTE);
String isolation = methodEle.getAttribute(ISOLATION_ATTRIBUTE);
String timeout = methodEle.getAttribute(TIMEOUT_ATTRIBUTE);
String readOnly = methodEle.getAttribute(READ_ONLY_ATTRIBUTE);
if (StringUtils.hasText(propagation)) {
attribute.setPropagationBehaviorName(RuleBasedTransactionAttribute.PREFIX_PROPAGATION + propagation);
}
if (StringUtils.hasText(isolation)) {
attribute.setIsolationLevelName(RuleBasedTransactionAttribute.PREFIX_ISOLATION + isolation);
}
if (StringUtils.hasText(timeout)) {
try {
attribute.setTimeout(Integer.parseInt(timeout));
}
catch (NumberFormatException ex) {
parserContext.getReaderContext().error("Timeout must be an integer value: [" + timeout + "]", methodEle);
}
}
if (StringUtils.hasText(readOnly)) {
attribute.setReadOnly(Boolean.parseBoolean(methodEle.getAttribute(READ_ONLY_ATTRIBUTE)));
}
List<RollbackRuleAttribute> rollbackRules = new ArrayList<>(1);
if (methodEle.hasAttribute(ROLLBACK_FOR_ATTRIBUTE)) {
String rollbackForValue = methodEle.getAttribute(ROLLBACK_FOR_ATTRIBUTE);
addRollbackRuleAttributesTo(rollbackRules, rollbackForValue);
}
if (methodEle.hasAttribute(NO_ROLLBACK_FOR_ATTRIBUTE)) {
String noRollbackForValue = methodEle.getAttribute(NO_ROLLBACK_FOR_ATTRIBUTE);
addNoRollbackRuleAttributesTo(rollbackRules, noRollbackForValue);
}
attribute.setRollbackRules(rollbackRules);
transactionAttributeMap.put(nameHolder, attribute);
}
RootBeanDefinition attributeSourceDefinition = new RootBeanDefinition(NameMatchTransactionAttributeSource.class);
attributeSourceDefinition.setSource(parserContext.extractSource(attrEle));
attributeSourceDefinition.getPropertyValues().add("nameMap", transactionAttributeMap);
return attributeSourceDefinition;
}
可以看到这里就是解析对应的method标签,并且设置对应的隔离级别,传播属性,只读,回滚等属性,最后会把这些method放在一个NameMatchTransactionAttributeSource对象中。
看到这里可以看到,目前就往容器放入了这些BeanDefinition。
有了这些BeanDefinition之后,接下来就是创建对应bean对象。
接下来就会根据对应的顺序来创建对应的bean。
此时我们来看下对应的一级缓存中已经存在了哪些对象。
之前我们知道第一个创建bean对象的时候,会在AspectJAwareAutoProxyCreator的before方法之前去创建对应的advisor对象,我们直接断点到那里。
然后就会在shouldSkip中去获取的advisor然后并且创建这个advisor。
这里就获取得到我们直接解析配置文件放入的DefaultBeanFactoryPointcutAdvisor对象。
然后就会去创建这个advisor。
在创建这个advisor的时候,就会属性注入的时候就创建他对应的需要的两个属性,一个是pointcut对象一个是advice对象。
第一个循环就会去创建对应的advice对象,然后第二个就回去创建对应pointcut对象。我们这里跳过。此时我们去看一下一级缓存里面已经创建好的对象有哪些。
此时创建advisor需要提前创建以下对象。
首先就会去解析第一个属性advice。
可以看到,我们的adviceName还没有去创建,只是返回了一个引用名称。
然后就会去解析第二个属性,pointcut对象。
txpoint就会去解析并且创建出来对应的对象。
以下是解析代码,我们继续往下跟。
@Nullable
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
try {
//定义用于一个存储bean对象的变量
Object bean;
//获取另一个Bean引用的Bean类型
Class<?> beanType = ref.getBeanType();
//如果引用来自父工厂
if (ref.isToParent()) {
//获取父工厂
BeanFactory parent = this.beanFactory.getParentBeanFactory();
//如果没有父工厂
if (parent == null) {
//抛出Bean创建异常:无法解析对bean的引用 ref 在父工厂中:没有可以的父工厂
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Cannot resolve reference to bean " + ref +
" in parent factory: no parent factory available");
}
//如果引用的Bean类型不为null
if (beanType != null) {
//从父工厂中获取引用的Bean类型对应的Bean对象
bean = parent.getBean(beanType);
}
else {
//否则,使用引用的Bean名,从父工厂中获取对应的Bean对像
bean = parent.getBean(String.valueOf(doEvaluate(ref.getBeanName())));
}
}
else {
//定义一个用于存储解析出来的Bean名的变量
String resolvedName;
//如果beanType不为null
if (beanType != null) {
//解析与beanType唯一匹配的bean实例,包括其bean名
NamedBeanHolder<?> namedBean = this.beanFactory.resolveNamedBean(beanType);
//让bean引用nameBean所封装的Bean对象
bean = namedBean.getBeanInstance();
//让resolvedName引用nameBean所封装的Bean名
resolvedName = namedBean.getBeanName();
}
else {
//让resolvedName引用ref所包装的Bean名
resolvedName = String.valueOf(doEvaluate(ref.getBeanName()));
//获取resolvedName的Bean对象
bean = this.beanFactory.getBean(resolvedName);
}
//注册beanName与dependentBeanNamed的依赖关系到Bean工厂
this.beanFactory.registerDependentBean(resolvedName, this.beanName);
}
//如果Bean对象是NullBean实例
if (bean instanceof NullBean) {
//将bean置为null
bean = null;
}
//返回解析出来对应ref所封装的Bean元信息(即Bean名,Bean类型)的Bean对象
return bean;
}
//捕捉Bean包和子包中引发的所有异常
catch (BeansException ex) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
}
}
此时我们的一级缓存里面只有这些对象,然后继续调用对呀的getBean。
以上可以看到到解析adviceName的时候就只是返回了一个refName并没有去创建,而advisor则创建了出来,那advice是什么时候创建呢?
我们再来重温一下,他是如何生成代理对象的。
/**
* 此处是真正创建aop代理的地方,在实例化之后,初始化之后就行处理
* 首先查看是否在earlyProxyReferences里存在,如果有就说明处理过了,不存在就考虑是否要包装,也就是代理
*
* Create a proxy with the configured interceptors if the bean is
* identified as one to proxy by the subclass.
* @see #getAdvicesAndAdvisorsForBean
*/
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
// 获取当前bean的key:如果beanName不为空,则以beanName为key,如果为FactoryBean类型,
// 前面还会添加&符号,如果beanName为空,则以当前bean对应的class为key
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 判断当前bean是否正在被代理,如果正在被代理则不进行封装
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 如果它需要被代理,则需要封装指定的bean
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
然后知道合适的advisor对象,我们继续往里面看他是如何去找的。
/**
* 检查前面切面解析是否有通知器advisors创建,有就返回,没有就是null
* @param beanClass the class of the bean to advise
* @param beanName the name of the bean
* @param targetSource
* @return
*/
@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 找合适的增强器对象
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
// 若为空表示没找到
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 将当前系统中所有的切面类的切面逻辑进行封装,从而得到目标Advisor
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 对获取到的所有Advisor进行判断,看其切面定义是否可以应用到当前bean,从而得到最终需要应用的Advisor
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
// 提供的hook方法,用于对目标Advisor进行扩展
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
// 对需要代理的Advisor按照一定的规则进行排序
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
我们知道他找到对应的advisor集合对象之后,会在extendAdvisors中添加一个exposeInvocationInterceptor对象,我们继续往里面看。
/**
* Add an {@link ExposeInvocationInterceptor} to the beginning of the advice chain.
* <p>This additional advice is needed when using AspectJ pointcut expressions
* and when using AspectJ-style advice.
*/
@Override
protected void extendAdvisors(List<Advisor> candidateAdvisors) {
AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
}
public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
// Don't add advisors to an empty list; may indicate that proxying is just not required
if (!advisors.isEmpty()) {
boolean foundAspectJAdvice = false;
for (Advisor advisor : advisors) {
// Be careful not to get the Advice without a guard, as this might eagerly
// instantiate a non-singleton AspectJ aspect...
if (isAspectJAdvice(advisor)) {
foundAspectJAdvice = true;
break;
}
}
if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
return true;
}
}
return false;
}
这里就会循环传入的advisor对象,我们继续跟一下 isAspectJAdvice方法。
/**
* Determine whether the given Advisor contains an AspectJ advice.
* @param advisor the Advisor to check
*/
private static boolean isAspectJAdvice(Advisor advisor) {
return (advisor instanceof InstantiationModelAwarePointcutAdvisor ||
advisor.getAdvice() instanceof AbstractAspectJAdvice ||
(advisor instanceof PointcutAdvisor &&
((PointcutAdvisor) advisor).getPointcut() instanceof AspectJExpressionPointcut));
}
然后就会去获取advice对象,继续往下跟。
@Override
public Advice getAdvice() {
Advice advice = this.advice;
// 非Spring环境一般手动set进来,所以就直接返回吧
if (advice != null) {
return advice;
}
Assert.state(this.adviceBeanName != null, "'adviceBeanName' must be specified");
Assert.state(this.beanFactory != null, "BeanFactory must be set to resolve 'adviceBeanName'");
// 若bean是单例的,那就没什么好说的,直接去工厂里拿出来就完事了(Advice.class),有可能返回null
if (this.beanFactory.isSingleton(this.adviceBeanName)) {
// Rely on singleton semantics provided by the factory.
advice = this.beanFactory.getBean(this.adviceBeanName, Advice.class);
this.advice = advice;
return advice;
}
// 若是多例的,就加锁,然后调用getBean()给他生成一个新的实例即可
else {
// No singleton guarantees from the factory -> let's lock locally but
// reuse the factory's singleton lock, just in case a lazy dependency
// of our advice bean happens to trigger the singleton lock implicitly...
synchronized (this.adviceMonitor) {
advice = this.advice;
if (advice == null) {
advice = this.beanFactory.getBean(this.adviceBeanName, Advice.class);
this.advice = advice;
}
return advice;
}
}
可以看得到这里就会调用对应的getBean方法,把我们刚刚没创建的advice对象创建出来。