- 前言
- 第一部分 核心实现
- 第 1 章 Spring 整体架构和环境搭建
- 第 2 章 容器的基本实现
- 第 3 章 默认标签的解析
- 第 4 章 自定义标签的解析
- 第 5 章 bean 的加载
- 第 6 章 容器的功能扩展
- 第 7 章 AOP
- 第二部分 企业应用
- 第 8 章 数据库连接 JDBC
- 第 9 章 整合 MyBatis
- 第 10 章 事务
- 第 11 章 SpringMVC
- 第 12 章 远程服务
- 第 13 章 Spring 消息
10.2.2 获取对应 class/method 的增强器
获取指定 bean 对应的增强器,其中包含两个关键字:增强器与对应。也就是说在 getAdvicesAndAdvisorsForBean 函数中,不但要找出增强器,而且还需要判断增强器是否满足要求。
protected Object[] getAdvicesAndAdvisorsForBean(Class beanClass, String beanName,
TargetSource targetSource) {
List advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors,
beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
其实我们也渐渐地体会到了 Spring 中代码的优秀,即使是一个很复杂的逻辑,在 Spring 中也会被拆分成若干个小的逻辑,然后在每个函数中实现,使得每个函数的逻辑简单到我们能快速地理解,而不会像有些人开发的那样,将一大堆的逻辑都罗列在一个函数中,给后期维护人员造成巨大的困扰。
同样,通过上面的函数,Spring 又将任务进行了拆分,分成了获取所有增强器与增强器是否匹配两个功能点。
1.寻找候选增强器
在 findCandidateAdvisors 函数中完成的就是获取增强器的功能。
protected List<Advisor> findCandidateAdvisors() {
return this.advisorRetrievalHelper.findAdvisorBeans();
}
public List<Advisor> findAdvisorBeans() {
// Determine list of advisor bean names, if not cached already.
String[] advisorNames = null;
synchronized (this) {
advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
}
if (advisorNames.length == 0) {
return new LinkedList<Advisor>();
}
List<Advisor> advisors = new LinkedList<Advisor>();
for (String name : advisorNames) {
if (isEligibleBean(name) && !this.beanFactory.isCurrentlyInCreation(name)) {
try {
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
if (this.beanFactory.isCurrentlyInCreation(bce.getBeanName())) {
if (logger.isDebugEnabled()) {
logger.debug("Ignoring currently created advisor '"
+ name + "': " + ex.getMessage());
}
continue;
}
}
throw ex;
}
}
}
return advisors;
}
对于上面的函数,你看懂其中的奥妙了吗?首先是通过 BeanFactoryUtils 类提供的工具方法获取所有对应 Advisor.class 的类,获取办法无非是使用 ListableBeanFactory 中提供的方法:
String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean
allowEagerInit);
而当我们知道增强器在容器中的 beanName 时,获取增强器已经不是问题了,在 BeanFactory 中提供了这样的方法,可以帮助我们快速定位对应的 bean 实例。
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
或许你已经忘了之前留下的悬念,在我们讲解自定义标签时曾经注册了一个类型为 BeanFactoryTransactionAttributeSourceAdvisor 的 bean,而在此 bean 中我们又注入了另外两个 Bean,那么此时这个 Bean 就会被开始使用了。因为 BeanFactoryTransactionAttribute Source Advisor 同样也实现了 Advisor 接口,那么在获取所有增强器时自然也会将此 bean 提取出来,并随着其他增强器一起在后续的步骤中被织入代理。
2.候选增强器中寻找到匹配项
当找出对应的增强器后,接来的任务就是看这些增强器是否与对应的 class 匹配了,当然不只是 class,class 内部的方法如果匹配也可以通过验证。
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors,
Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
//首先处理引介增强
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
//引介增强已经处理
if (candidate instanceof IntroductionAdvisor) {
continue;
}
//对于普通 bean 的处理
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean
hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) {
return((IntroductionAdvisor)advisor).getClassFilter().Matches
(targetClass);
}else if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}else {
return true;
}
}
当前我们分析的是对于 UserService 是否适用于此增强方法,那么当前的 advisor 就是之前查找出来的类型为 BeanFactoryTransactionAttributeSourceAdvisor 的 bean 实例,而通过类的层次结构我们又知道:BeanFactoryTransactionAttributeSourceAdvisor 间接实现了 PointcutAdvisor。因此,在 canApply 函数中的第二个 if 判断时就会通过判断,会将 BeanFactory Transaction AttributeSourceAdvisor 中的 getPointcut() 方法返回值作为参数继续调用 canApply 方法,而 getPoint() 方法返回的是 TransactionAttributeSourcePointcut 类型的实例。对于 transactionAttribute Source 这个属性大家还有印象吗?这是在解析自定义标签时注入进去的。
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttribute
SourcePointcut() {
@Override
protected TransactionAttributeSource getTransactionAttributeSource() {
return transactionAttributeSource;
}
};
那么,使用 ransactionAttributeSourcePointcut 类型的实例作为函数参数继续跟踪 canApply。
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
//此时的 pc 表示 TransactionAttributeSourcePointcut
//pc.getMethodMatcher() 返回的正是自身(this).
MethodMatcher methodMatcher = pc.getMethodMatcher();
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
Set<Class> classes = new HashSet<Class>(ClassUtils. GetAllInterfaces
ForClassAsSet(targetClass));
classes.add(targetClass);
//classes:[interface test.IITestBean, class test.TestBean]
for (Class<?> clazz : classes) {
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if ((introductionAwareMethodMatcher != null &&
introductionAwareMethodMatcher.matches(method, targetClass,
hasIntroductions)) ||
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
通过上面函数大致可以理清大体脉络,首先获取对应类的所有接口并连同类本身一起遍历,遍历过程中又对类中的方法再次遍历,一旦匹配成功便认为这个类适用于当前增强器。
到这里我们不禁会有疑问,对于事物的配置不仅仅局限于在函数上配置,我们都知道,在类活接口上的配置可以延续到类中的每个函数,那么,如果针对每个函数进行检测,在类本身上配置的事务属性岂不是检测不到了吗?带着这个疑问,我们继续探求 matcher 方法。
做匹配的时候 methodMatcher.matches(method, targetClass) 会使用 TransactionAttributeSource Pointcut 类的 matches 方法。
public boolean matches(Method method, Class targetClass) {
//自定义标签解析时注入
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
此时的 tas 表示 AnnotationTransactionAttributeSource 类型,而 AnnotationTransactionAttribute Source 类型的 getTransactionAttribute 方法如下:
public TransactionAttribute getTransactionAttribute(Method method, Class<?>
targetClass) {
Object cacheKey = getCacheKey(method, targetClass);
Object cached = this.attributeCache.get(cacheKey);
if (cached != null) {
if (cached == NULL_TRANSACTION_ATTRIBUTE) {
return null;
}
else {
return (TransactionAttribute) cached;
}
}
else {
TransactionAttribute txAtt = computeTransactionAttribute(method, targetClass);
// Put it in the cache.
if (txAtt == null) {
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Adding transactional method '" + method.getName()
+ "' with attribute: " + txAtt);
}
this.attributeCache.put(cacheKey, txAtt);
}
return txAtt;
}
}
很遗憾,在 getTransactionAttribute 函数中并没有找到我们想要的代码,这里是指常规的一贯的套路。尝试从缓存加载,如果对应信息没有被缓存的话,工作又委托给了 computeTransaction Attribute 函数,在 computeTransactionAttribute 函数中终于的我们看到了事务标签的提取过程。
3.提取事务标签
private TransactionAttribute computeTransactionAttribute(Method method, Class<?>
targetClass) {
// Don't allow no-public methods as required.
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
// Ignore CGLIB subclasses - introspect the actual user class.
Class<?> userClass = ClassUtils.getUserClass(targetClass);
//method 代表接口中的方法,specificMethod 代表实现类中的方法
Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass);
// If we are dealing with method with generic parameters, find the original method.
specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
//查看方法中是否存在事务声明
TransactionAttribute txAtt = findTransactionAttribute(specificMethod);
if (txAtt != null) {
return txAtt;
}
//查看方法所在类中是否存在事务声明
txAtt = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAtt != null) {
return txAtt;
}
//如果存在接口,则到接口中去寻找
if (specificMethod != method) {
//查找接口方法
txAtt = findTransactionAttribute(method);
if (txAtt != null) {
return txAtt;
}
//到接口中的类中去寻找
return findTransactionAttribute(method.getDeclaringClass());
}
return null;
}
对于事务属性的获取规则相信大家都已经很清楚,如果方法中存在事务属性,则使用方法上的属性,否则使用方法所在的类上的属性,如果方法所在类的属性上还是没有搜寻到对应的事务属性,那么再搜寻接口中的方法,再没有的话,最后尝试搜寻接口的类上面的声明。对于函数 computeTransactionAttribute 中的逻辑与我们所认识的规则并无差别,但是上面函数中并没有真正的去做搜寻事务属性的逻辑,而是搭建了个执行框架,将搜寻事务属性的任务委托给了 findTransactionAttribute 方法去执行。
protected TransactionAttribute findTransactionAttribute(Method method) {
return determineTransactionAttribute(method);
}
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement ae) {
for (TransactionAnnotationParser annotationParser : this.annotationParsers) {
TransactionAttribute attr = annotationParser.parseTransaction Annotation (ae);
if (attr != null) {
return attr;
}
}
return null;
}
this.annotationParsers 是在当前类 AnnotationTransactionAttributeSource 初始化的时候初始化的,其中的值被加入了 SpringTransactionAnnotationParser,也就是当进行属性获取的时候其实是使用 SpringTransactionAnnotationParser 类的 parseTransactionAnnotation 方法进行解析的。
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
Transactional ann = AnnotationUtils.getAnnotation(ae, Transactional.class);
if (ann != null) {
return parseTransactionAnnotation(ann);
}
else {
return null;
}
}
至此,我们终于看到了想看到的获取注解标记的代码。首先会判断当前的类是否含有 Transactional 注解,这是事务属性的基础,当然如果有的话会继续调用 parseTransactionAnnotation 方法解析详细的属性。
public TransactionAttribute parseTransactionAnnotation(Transactional ann) {
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
//解析 propagation
rbta.setPropagationBehavior(ann.propagation().value());
//解析 isolation
rbta.setIsolationLevel(ann.isolation().value());
//解析 timeout
rbta.setTimeout(ann.timeout());
//解析 readOnly
rbta.setReadOnly(ann.readOnly());
//解析 value
rbta.setQualifier(ann.value());
ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList<RollbackRule
Attribute>();
//解析 rollbackFor
Class[] rbf = ann.rollbackFor();
for (Class rbRule : rbf) {
RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
//解析 rollbackForClassName
String[] rbfc = ann.rollbackForClassName();
for (String rbRule : rbfc) {
RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
//解析 noRollbackFor
Class[] nrbf = ann.noRollbackFor();
for (Class rbRule : nrbf) {
NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
//解析 noRollbackForClassName
String[] nrbfc = ann.noRollbackForClassName();
for (String rbRule : nrbfc) {
NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
rbta.getRollbackRules().addAll(rollBackRules);
return rbta;
}
上面方法中实现了对对应类或者方法的事务属性解析,你会在这个类中看到任何你常用或者不常用的属性提取。
至此,我们终于完成了事务标签的解析。我们是不是分析的太远了,似乎已经忘了从哪里开始了。再回顾一下,我们的现在的任务是找出某个增强器是否适合于对应的类,而是否匹配的关键则在于是否从指定的类或类中的方法中找到对应的事务属性,现在,我们以 UserServiceImpl 为例,已经在它的接口 UserService 中找到了事务属性,所以,它是与事务增强器匹配的,也就是它会被事务功能修饰。
至此,事务功能的初始化工作便结束了,当判断某个 bean 适用于事务增强时,也就是适用于增强器 BeanFactoryTransactionAttributeSourceAdvisor,没错,还是这个类,所以说,在自定义标签解析时,注入的类成为了整个事务功能的基础。
BeanFactoryTransactionAttributeSourceAdvisor 作为 Advisor 的实现类,自然要遵从 Advisor 的处理方式,当代理被调用时会调用这个类的增强方法,也就是此 bean 的 Advise,又因为在解析事务定义标签时我们把 TransactionInterceptor 类型的 bean 注入到了 BeanFactory TransactionAttributeSourceAdvisor 中,所以,在调用事务增强器增强的代理类时会首先执行 TransactionInterceptor 进行增强,同时,也就是在 TransactionInterceptor 类中的 invoke 方法中完成了整个事务的逻辑。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论