a 一. AOP介绍
AOP(Aspect Oriented Programming) 面向切面编程, 是OOP(Object Oriented Programming)面向对象编程的 补充,是一种思想。 OOP的特性(封装,继承,多态,抽象),主要强调的 对象或者类之间的纵向关系, 而横向关系却无法得到确保。 AOP正是补充的横向关系。
一个非常简单的小例子,例如我们当前有三个类(User,Admin,Employee),都有findOne查询, 我们需要统计查询消耗的时间,在只有OOP的时候,我们就要这么写(如下图)。 亦或是根据继承,可以自行在BaseService里封装两个方法,一个beforeExecute(),一个afterExecute(), 执行时候换成 super.beforeExecute()和 super.afterExecute()。大同小异。
import ..... // 省略
@Service
public class AdminService extends BaseService{
@Resource
private AdminDAO adminDAO;
// Slf4j日志
private final Logger logger = LoggerFactory.getLogger(ScheduledService.class);
public Admin findOne() {
logger.info("查询开始了" + System.currentTimeMillis());
return adminDAO.findOne(); // "SELECT * FROM admin limit 1"
logger.info("查询结束了" + System.currentTimeMillis());
}
}
Employee和User同理,不重复了
可以看到,每一个实现最起码要调用一次,(大项目成百上千的model,service),重复量就很大, 如果是想修改其中的逻辑,就需要每一个都修改一次,重复工作量很大。
AOP利用 "横切"思想,横向扩展类,并将公共行为封装到一起(所谓的Aspect,切面),减少系统的重复代码,降低模块之间的耦合度,提升可维护度。 二. AOP一些常用概念
1. advice : 直译 为 "增强",或者"通知"。 是aop执行的具体逻辑操作, spring定义了 前置(beforeAdvice),后置(afterAdvice),异常(ThrowsAdvice),引入(DynamicIntroductionAdvice)四种,具体目录为org.springframework.aop。 需要注意的是, 第五种, 环绕(AspectJAroundAdvice)不是spring定义的,而是AspectJ定义的,具体路径为org.springframework.aop.aspectj。
2. join point : 连接点。 是在逻辑执行时可插入切面的一个点。这个点可以是调用方法时、抛出异常时或者其他行为。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。
3. pointcut : 切点。切点的定义会匹配通知所要织入的一个或多个连接点。我们通常使用明确的类和方法名称,或是通过表达式匹配的一组类或方法。
关于切点和连接点,查资料查的我一度非常混淆这两个甚至觉得这就是一个概念。 在官方搜索的一个小博客里,看到了这样一句话 "pointcut that allows selecting join points in beans with a matching name pattern". 大概我自己的理解就是 切点一定是连接点,而连接点不一定是切点。
4.aspect : 切面。 是一个大的概念,切面应该是pointcut + advice ,是一个整体的东西。
5.weaving : 织入。 构建新对象(代理对象)的方法,spring选择在运行时动态注入,而aspectj选择在编译器或者类装载时,根据类的修饰决定是jdk代理还是cglib代理。一般都是由ProxyFactory来完成
总的来说,AOP通过切点进行织入, 通过代理的方式构造出代理对象,来替代原对象进行逻辑的执行。
三. aop的源码分析
使用过springboot的童鞋们都知道,利用注解@EnableAspectJAutoProxy则可以开启aop模式(记得加载aop的jar包)。 而早些版本的spring则需要在xml文件中配置 <aop:config>或者是<aop:aspectj-autoproxy>来开启。
我们从@EnableAspectJAutoProxy 追溯进去,到达注解类的源码。
package org.springframework.context.annotation; // 具体的包位置 有兴趣的可以看看
import ...// import省略
@Target({ElementType.TYPE}) // 元注解之一, 表示该注解的修饰范围
@Retention(RetentionPolicy.RUNTIME) // 元注解之一, 表示该类保留的阶段
@Documented // 元注解之一,标记为公众api,可以javadoc文档话
@Import({AspectJAutoProxyRegistrar.class}) // 导入注解,类似于组合,将参数类(可以为多个)注入到当前容器中
public @interface EnableAspectJAutoProxy {
// 代理类标志,为true代表直接代理类,需要利用cglib代理。 为false则直接使用传统的jdk代理方式
boolean proxyTargetClass() default false;
// 是否将该代理对象暴露为线程共享,为true则暴露,使用threadLocal方式,为false则忽略
boolean exposeProxy() default false;
}
ps: 关于元注解,其实是修饰注解的注解,大概所有@Enable开头的注解类都有这几个修饰。 可以参考这篇文章 : java元注解
ps_2: 关于@Import,个人更容易理解为组合的模式,没有继承或者实现的关系,更像是一种内部类的感觉,类似于php的trait,或是python的imp.load_source。
看一下AspectJAutoProxyRegisterar的源码,发现只有一个方法
package org.springframework.context.annotation;
import ... // import省略
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
AspectJAutoProxyRegistrar() {
}
/*
* @param AnnotationMetadata 导入数据的配置类
* @param BeanDefinitionRegistry 一种bean的定义格式,包含一些注册的接口,通常为beanFactory
*/
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 注册成spring使用的beanDefinition格式 --- 1
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
// 将配置数据注册到 AnnotationAttributes格式(封装的特殊map) 的属性列表
AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata,
EnableAspectJAutoProxy.class);
// 判断配置数据的map
if (enableAspectJAutoProxy != null) {
// 判断对应的属性值(该属性值上文已讲), 为true则直接使用cglib代理 ---2
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
// 判断对应的属性值(该属性值上文已讲), 为true则直接使用暴露性接口 ---3
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
重点就是 1的方法,注册成beanDefinitition,包含了整体的核心逻辑。 其中 最重要的则是被调用的重载方法, 将一个很核心的类AnnotationAwareAspectJAutoProxyCreator注入。
public abstract class AopConfigUtils {
//外部调用的注册方法,实际调用的是内部对应的重载方法
@Nullable // 参数可为null的注解
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, (Object)null);
}
// 被调用的重载方法,此步是重点
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {
// 在此地方注入AnnotationAwareAspectJAutoProxyCreator 这个类,是aop的关键类
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
// 执行注册
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
// 实际注册的org.springframework.aop.config.internalAutoProxyCreator
if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
// 获取internalAutoProxyCreator的定义
BeanDefinition apcDefinition = registry.getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");
// 与我们传入的类名做对比, 如果一致则不做处理。 如果不一致,则需要决定优先级问题
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
// 获取优先级并进行对比
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
// 优先级被更高的取代时, 设置beanClassName。 定义的名称,不等同于最终的beanName
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
} else {
// else分支表示目前没有internalAutoProxyCreator的定义,则直接新建
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", -2147483648);
beanDefinition.setRole(2);
// 注册定义
registry.registerBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator", beanDefinition);
return beanDefinition;
}
}
}
// 优先级队列获取,可以看到,这个类维护了一个优先级的数组,使用static代码块进行初始化,越靠后的优先级就越高
// 直接根据index的索引定优先级也是很暴力的操作。
private static int findPriorityForClass(Class<?> clazz) {
return APC_PRIORITY_LIST.indexOf(clazz);
}
// 静态代码块初始化
static {
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}
补充一点 : 在registerOrEscalateApcAsRequired方法中 注册了"org.springframework.aop.config.internalAutoProxyCreator"这个类。查了一些资料没有什么有价值的, 我翻了一下老版本的源码的发现是个预定义的常量,名为"AUTO_PROXY_CREATOR_BEAN_NAME"。 然而 "org.springframework.aop.config.internalAutoProxyCreator"只是BeanDefintion的定义的className而已,并非真的类名.其对应的真实类是org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator。 具体在哪里进行的alias别名没有找到,暂时留一个坑吧。
如果通读这段逻辑会发现,我们明明注册的是"AnnotationAwareAspectJAutoProxyCreator",在首次进入的时候,却直接注册"org.springframework.aop.config.internalAutoProxyCreator"。(第一个if判断的时候已经走的else)
我打开了AnnotationAwareAspectJAutoProxyCreator类的继承图,说明先注册的是父类,所以并没有什么问题,但是具体为什么这么设计就不得而知了。即使再次注册到子类也会因为优先级的原因,将类变为对应的子类。
继而我们可以继续分析其源码,打开AnnotationAwareAspectJAutoProxyCreator,发现只有简单的几个属性和一些setter。
<--插播一些spring bean生命周期的知识--> bean在初始化时一般会执行
postProcessBeforeInstantiation() -> constructor() -> postProcessPropertyValues() 这几步,而代理对象一般也在这三步中产生。所以我们向上查找直到AbstractAutoProxyCreator 。 找到了postProcessBeforeInstantiation()方法
查看AbstractAutoProxyCreator的postProcessBeforeInstantiation方法。 AbstractAutoProxyCreator定义许多属性,有数组,map甚至bool来辅助记录各种状态的bean,方便后续使用,不贴这部分的代码了,有兴趣可以去看一下
// AbstractAutoProxyCreator.class
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
// 拿取缓存的key
Object cacheKey = this.getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
// 如果是增强类。直接忽略
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
// 判断 特殊bean,判断是否和切面、切点bean等 aop相关类或实现其接口的类
// shouldSkip则判断是否是 original类,也就是原始类
if (this.isInfrastructureClass(beanClass) || this.shouldSkip(beanClass, beanName)) {
// 则直接放入属性advisedBeans(concurrentHashMap)中, 并打上对应的tag,标记其为特殊类
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// 判断自定义的targetSource方法
TargetSource targetSource = this.getCustomTargetSource(beanClass, beanName);
// 如果有自定义target方法则加入对应的属性(map)中
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
// 获取增强的方法 --- 重点1
Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
// 创建代理对象 --- 重点2
Object proxy = this.createProxy(beanClass, beanName, specificInterceptors, targetSource);
// 将对象标记并存入自身属性(Map)中
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
} else {
return null;
}
}
上述比较重要的方法就是获取对应的增强getAdvicesAndAdvisorsForBean()方法,和 获取代理对象的方法 createProxy()。会发现AbstractAutoProxyCreator的getAdvicesAndAdvisorsForBean()是个抽象方法,交由子类实现。 实现地点在子类AbstractAdvisorAutoProxyCreator中(上述类图的第一个子类)
// AbstractAdvisorAutoProxyCreator.class
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 获取 对应beanClass的所有增强
List<Advisor> advisors = this.findEligibleAdvisors(beanClass, beanName);
// DO_NOT_PROXY是一个空数组常量。 如果找不到则返回空数组,否则返回转到数组状态的增强类
return advisors.isEmpty() ? DO_NOT_PROXY : advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 寻找目前所有的增强类
List<Advisor> candidateAdvisors = this.findCandidateAdvisors();
// 所有增强类进行处理,筛选 来确定使用的
List<Advisor> eligibleAdvisors = this.findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
// 将增强加入对应的属性
this.extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) { // 进行一下排序
eligibleAdvisors = this.sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
findCandidateAdvisors由子类进行了实现,扩展了父类的该方法。 算法还是有些复杂的,整体流程还是比较干净清晰的。大概流程就是通过递归方式遍历所有的bean,如果有@Aspect修饰就加入到数组中进行标记。
// AnnotationAwareAspectJAutoProxyCreator.class
protected List<Advisor> findCandidateAdvisors() {
// 调用的实际是 父类的方法
List<Advisor> advisors = super.findCandidateAdvisors();
// 扩展后续的逻辑
if (this.aspectJAdvisorsBuilder != null) {
// 寻找所有注解为@ASpect的增强类
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
// org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder.class
// 寻找注解为@Aspect的增强器,包含父类的递归查询
public List<Advisor> buildAspectJAdvisors() {
// 所有的增强类
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized(this) {
aspectNames = this.aspectBeanNames;
// 如果还没定义切面的beanName
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList();
List<String> aspectNames = new ArrayList();
// 递归方法,从下到上查找所有的bean,
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
String[] var18 = beanNames;
int var19 = beanNames.length;
for(int var7 = 0; var7 < var19; ++var7) {
String beanName = var18[var7];
// isEligibleBean交由实现类实现,判断一些类的条件,当前类默认返回true
if (this.isEligibleBean(beanName)) {
// 直接从beanFactory拿对应的bean
Class<?> beanType = this.beanFactory.getType(beanName);
// isAspect()判断该bean是否由 @Aspect注解 有则返回true
if (beanType != null && this.advisorFactory.isAspect(beanType)) {
// 加入数组中
aspectNames.add(beanName);
// 创建一个AspectMetadata类(Aspect注解类的实例化模型),判断是否为Aspect的实现。 一层一层的遍历,从子找到父, 直到找到不为Object子类的 Aspect对象
AspectMetadata amd = new AspectMetadata(beanType, beanName);
// 判断切面的实例模式 -- 后边会引入文章介绍
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
// 创建Aspect的元数据
MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
// 通过反射,获取该增强内所有的方法
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
// 对应不同的模式 进行不同的标记处理
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
} else {
this.aspectFactoryCache.put(beanName, factory);
}
// 将获取到的增强加入List中
advisors.addAll(classAdvisors);
} else {
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName + "' is a singleton, but aspect instantiation model is not singleton");
}
// 非单例模式的方法, 直接加入对应的工厂中和数组中,
MetadataAwareAspectInstanceFactory factory = new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
// 应对aspectName数组不为空的时候
if (aspectNames.isEmpty()) {
return Collections.emptyList();
} else {
// 通过迭代的方法,直接遍历当前的aspectName
List<Advisor> advisors = new ArrayList();
Iterator var3 = aspectNames.iterator();
while(var3.hasNext()) {
String aspectName = (String)var3.next();
List<Advisor> cachedAdvisors = (List)this.advisorsCache.get(aspectName);
// 在Cache的查找 如果没有则新建 和上述操作差不多
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
} else {
MetadataAwareAspectInstanceFactory factory = (MetadataAwareAspectInstanceFactory)this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
}
// org.springframework.beans.factory.BeanFactoryUtils.class
// 通过递归的方法 从下之上搜索拿去所有的bean
public static String[] beanNamesForTypeIncludingAncestors(ListableBeanFactory lbf, Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
Assert.notNull(lbf, "ListableBeanFactory must not be null");
String[] result = lbf.getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
if (lbf instanceof HierarchicalBeanFactory) {
HierarchicalBeanFactory hbf = (HierarchicalBeanFactory)lbf;
if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {
// 递归的拿取父节点
String[] parentResult = beanNamesForTypeIncludingAncestors((ListableBeanFactory)hbf.getParentBeanFactory(), type, includeNonSingletons, allowEagerInit);
result = mergeNamesWithParent(result, parentResult, hbf);
}
}
return result;
}
关于amd.getAjType().getPerClause().getKind(). 其实是Aspect的AspectMetadata类提供的一些方式,目前有四种,默认为singleton(和spring一样的单例),其他的三种是pertarget、perthis、pertypewithin。找到这么一篇帖子, 实例化切面模式
// todo
后面继续写
findAdvisorsThatCanApply
和 getProxy....