目录
- AOP编程中的基本概念
- Spring中的概念
- 核心类
- SpringAop基于AspectJ注解方式
- Spring AOP源码分析
AOP编程中的基本概念
- 连接点: 程序执行某个特定位置,如类的初始化前后,某个方法调用前后,方法报出异常后,一个类或者一段代码拥有一些边界性质的特定点。Spring仅支持方法的连接点
- 切点: 每个程序都拥有多个连接点。AOP通过切点定位连接点,一个切点可以对应多个连接点。
- 增强: 增强是一段代码。是织入到目标类的连接点上的一段代码。
- 目标对象: 增强逻辑的织入目标类
- 引介: 引介是特殊的增强,他为类添加一些属性和方法
- 织入: 将增强添加到具体目标对象的连接点的过程
- 切面: 切面是由切点和增强组成
Spring中的概念
- advisor: 封装了SpringAop的切点和通知(类似为切面) 后面我们把advisor结尾的类称为切面类
- advice: 通知,也就是增强。后面我们把spring中以advice结尾的类称为增强类
- creator: 相当于织入(只不过spring是通过动态代理织入增强的) 为了方便称呼我们后面把creator结尾的类成为织入类
核心类
advisorCreator自动织入类:
- BeanNameAutoProxyCreator: 根据指定的名称创建代理对象,通过设置advisor,可以对指定的beanName进行代理。支持模糊
- AbstractAdvisorAutoProxyCreator: 扫描所有的advisor的实现类。动态匹配每一个类,判断是否可以被代理。默认的实现类是DefaultAdvisorAutoProxyCreator
- AspectJAwareAdvisorAutoProxyCreator: AspectJ的实现方式,spring最常用的实现方式。其子类(AnnotationAwareAspectJAutoProxyCreator)是默认的支持方式,会扫描@Aspect注解的类,生产对应的切面。
advisor核心类(都集成Advisor接口)
- StaticMethodMatcherPointcut: 静态方法切面,抽象类。定义了一个classFilter,通过重写getClassFilter()方法来指定切面规则。另外实现了StaticMethodMatcher接口,通过重写matches来指定方法匹配规则
- StaticMethodMatcherPointcutAdvisor: 静态方法匹配切面,扩展了排序方法。
- NameMatchMethodPointcut: 名称匹配切面,通过指定方法集合变量mappedNames,模糊匹配。
- NameMatchMethodPointcutAdvisor: 方法名称切面,内部封装了NameMatchMethodPointcut,通过设置方法名称模糊匹配规则和通知来实现切面功能
- DefaultPointcutAdvisor: 默认的切面类
- RegexpMethodPointcutAdvisor: 用于支持正则表达式的切面类,可支持函多个正则表达式
- NameMatchMethodPointcutAdvisor: 方法名称切面
- InstantiationModelAwarePointcutAdvisorImpl: 自动封装的切面实现。在自动织入的时候会默认会把AspectJ注解默认包装改该类。比较常用的切面类
advice增强核心类
- AspectJMethodBeforeAdvice: 前置增强(@Before标注的方法会被解析成该通知)
- AspectJAfterReturningAdvice: 后置增强(@AfterReturning 标注的方法会被解析成该通知)
- AspectJAroundAdvice: 环绕增强(@Around标注的方法会被解析成该通知)
- AspectJAfterAdvice: 返回增强(@After 标注的方法会被解析成该通知)忽略异常
SpringAop基于AspectJ注解方式
目标对象
@Component
public class TargetA {
public void sayHello(){
System.out.println("sayHello");
}
}
增强
@Component
@Aspect
public class ProxyA {
@Pointcut("execution(* org.springframework.apo..*.*(..))")
public void point(){
}
@Before("point()")
public void before(){
System.out.println("begin say..");
}
@After("point()")
public void after(){
System.out.println("after say ...");
}
}
启动类
@ComponentScan("org.springframework.apo")
@EnableAspectJAutoProxy
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(App.class);
TargetA bean = applicationContext.getBean(TargetA.class);
bean.sayHello();
}
}
可以看到在spring中我们只需要定义增强 其他的不需要我们关心。 spring的creator会帮我织入到目标类。上面的流程最关键的两点 其一是AspectJ连接点表达式比较关键 其二是在启动类上加@EnableAspectAutoProxy注解(springboot引入了spring-boot-starter-aop就不需要再手动Enabled)。下面我们从注解入手看一下 spring织入的整个流程。
Spring AOP源码分析
启动注解EnableAspectJAutoProxy
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
我们看到上述代码中使用@Import标签向spring容器中导入了一个AspectJAutoProxyRegistrar。继续跟进AspectJAutoProxyRegistrar
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//向IOC容器中注入AnnotationAwareAspectJAutoProxyCreator
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
上面代码其实主要是向容器中加了AnnotationAwareAspectJAutoProxyCreator 这个织入类。并根据我们的配置(注解中有两个属性 后续会讲解)。到这这个注解的使命就完成了。那为什么像springIOC容器注入了一个AnnotationAwareAspectJAutoProxyCreator 就能实现织入的能力呢?下面我们从这个类入手了解一下spring的整个织入流程。
类的继承关系
在看spring源码的时候我们可以发现 spring框架中大量运用了模板方法模式。所以只要出现Abstract开头的类 我们就应该好好的去看一下。分析这一部分的源码我们就从第第一个抽象类入手AbstractAutoProxyCreator。
看一下初始化过程
父类初始化AbstractAutoProxyCreator
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
@Override
public void setBeanFactory(BeanFactory beanFactory) {
super.setBeanFactory(beanFactory);
if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
throw new IllegalArgumentException(
"AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
}
initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
}
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
this.advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);
}
}
子类初始化
public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
//这个方法是在bean初始化之前调用 在spring启动期间会把BeanFactory注入进来 是一个初始化方法。
@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.initBeanFactory(beanFactory);
if (this.aspectJAdvisorFactory == null) {
//ReflectiveAspectJAdvisorFactory是一个支持AspectJ注解的类。可以解析AspectJ注解包装成Advisor。简单的理解是对AspectJ的语法的支持。
this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
}
//这里是对ReflectiveAspectJAdvisorFactory的包装 内部真正解析AspectJ注解的是ReflectiveAspectJAdvisorFactory类。
this.aspectJAdvisorsBuilder =
new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
}
}
可以发现它实现了SmartInstantiationAwareBeanPostProcessor 。这个接口是springIOC容器的扩展接口其最顶层的父接口是BeanPostProcessor。在springIOC容器启动和 bean的创建 初始化前后调用。如果对这一块比较模糊可以去看一下BeanFactoryPostProcessor和BeanPostProcessor这两个父接口衍生出来的几个接口的注释。里面对于调用点的注释还挺清楚。我们这里就不做过多解释了。
下面我们把这个类中我们需要用的方法复制出来
//这个方法是InstantiationAwareBeanPostProcessor接口中的方法 是在bean实例化之前被调用
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
//advisedBeans用于存储不能被代理的bean 如果当前bean出现在集合中立马返回
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
//如果当前类继承 Advice,Pointcut,Advisor,AopInfrastructureBean等这些类也不能被
//代理
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
//得到目标源 这是一次尝试 因为如果我们设置customTargetSourceCreators 这个属性 这个时候就
//会获取我们设置的TargetSource对象 如果没设置就跳过了这个方法。 下面的代理过程我们暂且先不管
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
//如果找到确实设置了TargetSource 就加入到缓存集合
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
下面我们看一下shouldSkip这个方法 子类的实现
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// 从bean工厂中查找所有的advisor 如果当前bean的名字在当前advisor的列表中 则跳过不需要代理
//暂时不展开
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}
上面我们分析了postProcessBeforeInstantiation方法 如果设置自定义的TargetSourceCreator 就只做了一件事件 找到所有的增强并封装成切面
//这个方法BeanPostProcessor中的方法 在bean初始化(初始化方法)之后调用。
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
//重点是这里 进入这个方法
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
//前面都是判断 直接来到这一行代码 我们暂时不展开 大概的意思是从我们所有的切面中筛选符合当前bean的切面
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
//如果有符合当前类的切面 将当前类放到缓存中
this.advisedBeans.put(cacheKey, Boolean.TRUE);
//创建一个当前类的代理 相当于把增强织入到当前类
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
//把类型缓存起来
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
到目前为止 如果我们不展开getAdvicesAndAdvisorsForBean 方法和createProxy方法 其实整个过程已经结束了。
最后我们着重分析一下advisor的创建过程和代理类的创建过程
- advisor创建 getAdvicesAndAdvisorsForBean这个方法是一个抽象方法 是并且是AbstractAutoProxyCreator唯一的一个抽象方法 我们直接进入子类(AbstractAdvisorAutoProxyCreator)的实现
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
//这里继续调用查找Advisor的方法
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
继续跟进findEligibleAdvisors 当前所在AbstractAdvisorAutoProxyCreator类
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
//这个方法被子类重写就是查找被AspectJ语法修饰的切面
List<Advisor> candidateAdvisors = findCandidateAdvisors();
//找出所有切面应用在当前实例上面的
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
//扩展方法 子类实现的时候像 集合中加入了ExposeInvocationInterceptor
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
进入子类的findCandidateAdvisors方法
@Override
protected List<Advisor> findCandidateAdvisors() {
// 先调用父类的方法获取容器中所有实现Advisor的子类的实例
List<Advisor> advisors = super.findCandidateAdvisors();
if (this.aspectJAdvisorsBuilder != null) {
//然后加入所有AspectJ注解修饰的切面
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
继续展开this.aspectJAdvisorsBuilder.buildAspectJAdvisors() 这个方法是查找的核心 代码有点多
public List<Advisor> buildAspectJAdvisors() {
//aspectBeanNames这个是缓存的所有 有AspectJ注解的实例 第一次是null
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
//这里就是找到所有的bean 因为传的类型是Object 所以所有的实例的名字都会查找出来
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
//这里判断当前类型是否有AspectJ注解
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
//这里找到当前实例的Advisor 这里不作展开了 就是通过反射拿到对应的方法封装成InstantiationModelAwarePointcutAdvisorImpl的过程
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
//这里缓存分为单例和原型的方式缓存
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
//然后将本次解析结果加入集合
advisors.addAll(classAdvisors);
}
else {
// Per target or per this.
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;
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
到此我们的解析Advisor流程就结束了
下面我们在看一下代理的创建
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
//创建一个代理工厂 ProxyFactory区别于ProxyFactoryBean 关于ProxyFactoryBean后面会介绍
ProxyFactory proxyFactory = new ProxyFactory();
//设置一些ProxyFactory的属性例如proxyTargetClass,exposeProxy 因为 ProxyFactory和AbstractAutoProxyCreator都继承自ProxyConfig
//下面都是对ProxyFactory的设置
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
//设置切面
proxyFactory.addAdvisors(advisors);
//设置代理源
proxyFactory.setTargetSource(targetSource);
//这个是扩展方法 留个子类实现可以对ProxyFactory自定义。
//例如我们可以自定义一种织入策略 实现AbstractAutoProxyCreator 然后重写该方法 去自定义ProxyFactory
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
//这里是创建代理的逻辑
return proxyFactory.getProxy(getProxyClassLoader());
}
下面进入getProxy中 下面这个方法就是根据代理类是否有接口去创建不同的AopProxy
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
如果proxy-target-class
设置为true 除非被代理的类是一个接口 一般情况下是要使用CGLIB代理的。springboot环境下默认就是true。
好了到这里 我们把基本的流程叙述了一遍。这一块的代码太多 不可能很详细 读者可以下去自行翻阅。