学习本文你可以掌握 1、被切面拦截的目标类是如何实例化 2、都知道AOP是基于JDK动态代理或者Cglib,那么原理是怎么实现的
一、使用案例
1、先定义一个service方法
public interface UserService {
void addUser();
}
@Service
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("新增用户...");
}
}
2、在定义一个切面
@Aspect
@Component
public class SimpleAspect {
@Pointcut("execution(* com.xiaour.spring.boot.service.UserService.*(..))")
private void pointcut() {
}
@Around("pointcut()")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws InterruptedException {
String methodName = proceedingJoinPoint.getSignature().getName();
System.out.println("执行" + methodName + "的环绕通知(@Around)...");
Object result = proceedingJoinPoint.proceed();
}
@Before("pointcut()")
public void before(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("执行" + methodName + "的前置通知(@Before)...");
}
@After("pointcut()")
public void after(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("执行" + methodName + "的后置通知(@After)...");
}
@AfterReturning("pointcut()")
public void afterReturning(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("执行" + methodName + "的后置返回通知(@AfterReturning)...");
}
}
3、开启Aspect注解
@EnableAspectJAutoProxy
@SpringBootApplication
public class Application {
......
}
至此Service的任意方法被调用都会进到切面的通知方法里面去。
二、下面开始介绍下原理
1、先从@EnableAspectJAutoProxy注解开始说
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
该注解2个属性 proxyTargetClass :AOP代理的具体实现方式。英文注释很简单哈,是否开启CGLIB(基于子类)的代理,为true的话使用CGLIB,为false的话使用基于标准 Java 接口的代理,也就是JDK动态代理。如果是true,目标类是接口还是会使用动态代理。 exposeProxy:控制代理的暴露方式。是否暴露当前代理对象为ThreadLocal模式。可以解决内部调用不能使用切面的问题,为true的话可以获取代理对象,通过代理对象调用方法进入切面。
T proxy=(T) AopContext.currentProxy();
@Import(AspectJAutoProxyRegistrar.class)先导入AspectJAutoProxyRegistrar类,看下该类会做什么事情
public class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
最终向容器中添加一个类AnnotationAwareAspectJAutoProxyCreator,该类一层层实现很多接口,顶层有个BeanPostProcessor,所以AnnotationAwareAspectJAutoProxyCreator也算一个BeanPostProcessor,也会被添加到BeanPostProcessor执行链中去,然后在Bean初始化前后调用BeanPostProcessor的前置后置回调方法,AnnotationAwareAspectJAutoProxyCreator在调用后置回调方法时,会返回一个代理代理对象,从而生成了bean的代理实例。
2、下面就开始创建userService普通实例,然后执行设置属性方法populateBean和初始化方法initializeBean
3、执行前置-初始化-后置方法
4、执行AnnotationAwareAspectJAutoProxyCreator的后置方法,生成userService代理对象,替换传进来的userService的普通实例对象
5、执行AnnotationAwareAspectJAutoProxyCreator父类的postProcessAfterInitialization,里面会执行最为重要的方法-wrapIfNecessary
6、下面介绍下wrapIfNecessary方法
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
.....
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;
}
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;
}
先获取通知拦截器,判断userService是否是符合通知拦截器定义的规则,也就是是否符合切点表达式定义的规则,如果符合则返回一系列通知方法,下面截了一张specificInterceptors的内容,其实就是我们上面定义切面里面的四个通知
protected Object createProxy(Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
....
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
for (Advisor advisor : advisors) {
proxyFactory.addAdvisor(advisor);
}
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
return proxyFactory.getProxy(getProxyClassLoader());
}
最终调用proxyFactory.getProxy,下面看ProxyFactory的getProxy方法是做了啥
public Object getProxy(ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
调用createAopProxy方法里面会先拿到aopProxyFactory,然后调用aopProxyFactory的createAopProxy
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
private AopProxyFactory aopProxyFactory;
public AopProxyFactory getAopProxyFactory() {
return this.aopProxyFactory;
}
下面看aopProxyFactory
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
更具条件是选择JDK代理还是Cglib代理,最后将生成的代理类一步一步返回
假设上面返回JdkDynamicAopProxy对象,当调用JdkDynamicAopProxy的getProxy方法是如何创建代理对象的
注意接口参数里面的interfaces的值,是一个数组,不是单个接口,而是多个接口
InvocationHandler其实就是JdkDynamicAopProxy对象,里面实现了invoke方法,下面我们看下当我们调用UserService里面的方法时,invoke里面做了什么?
拿到调用链,也就是由目标方法+切面环绕通知+前置通知+后置通知组成的调用链一层一层执行下去
至此所有流程执行完成了。
总结:Spring会先加载AspectJAutoProxyRegistrar类,AspectJAutoProxyRegistrar会像容器注册AnnotationAwareAspectJAutoProxyCreator,AnnotationAwareAspectJAutoProxyCreator是一个BeanPostProcess类型的Bean,在实例化其他普通Bean的时候,会执行该bean的前置和后置方法,在AnnotationAwareAspectJAutoProxyCreator后置方法里面会创建代理对象,当我们执行目标方法时,会进入JdkDynamicAopProxy的invoke方法,然后拿到调用链,挨个调用。
三、疑问
1、在执行wrapIfNecessary方法的时候,getAdvicesAndAdvisorsForBean方法会返回当前Bean的所有通知方法,也就是下图的specificInterceptors,那么这个数组是怎么得到的
解答:
1、在解答前先说下在启动的时候,我们手动添加的@EnableAspectJAutoProxy注解,里面会注册一个AnnotationAwareAspectJAutoProxyCreator,这是一个BeanPostProcess
注册时设置的值,主要包含设置下面2个属性
- order = Integer.MIN_VALUE
- beanName = org.springframework.transaction.config.internalTransactionAdvisor
注册AnnotationAwareAspectJAutoProxyCreator必定会实例化它,看下AnnotationAwareAspectJAutoProxyCreator的初始化方法
public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
private AspectJAdvisorFactory aspectJAdvisorFactory;
private BeanFactoryAspectJAdvisorsBuilder aspectJAdvisorsBuilder;
@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.initBeanFactory(beanFactory);
if (this.aspectJAdvisorFactory == null) {
this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
}
this.aspectJAdvisorsBuilder = new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
}
}
BeanFactoryAspectJAdvisorsBuilder类,里面有几个Map,存的是带有@Aspect的通知方法集合,就比如类SimpleAspect带有@Aspect注解,那么SimpleAspect就是一个切面,切面里面一定有切点+通知方法,那么这些通知方法都存在aspectJAdvisorsBuilder的Map里面,至于怎么知道SimpleAspect类带有@Aspect注解,以及找出他的通知方法,都是由aspectJAdvisorsBuilder来实现的。 那么什么时候触发去解析的SimpleAspect里面的通知呢?在实例Bean实例化的时候,下面开始讲解
先看创建Bean时会调用一个resolveBeforeInstantiation方法,也就是下图说的
resolveBeforeInstantiation是调用doCreateBean之前调用的,也叫实例化前置方法。
下面看下resolveBeforeInstantiation怎么做的
在一对BeanPostProcess集合中,轮训调用实例化前置方法,当然也包含AnnotationAwareAspectJAutoProxyCreator
1、AnnotationAwareAspectJAutoProxyCreator是InstantiationAwareBeanPostProcessor的子类 2、实现了postProcessBeforeInstantiation方法
下面看下AnnotationAwareAspectJAutoProxyCreator的postProcessBeforeInstantiation方法,shouldSkip方法很重要
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor) {
if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) {
return true;
}
}
}
return super.shouldSkip(beanClass, beanName);
}
shouldSkip会调用findCandidateAdvisors方法,下面看下findCandidateAdvisors做了什么?
最终是通过前面说到的aspectJAdvisorsBuilder对象,调用buildAspectJAdvisors方法完成解析找到带有@Aspect注解的类,并且解析里面的通知方法。
上图主要流程,拿到所有BeanName判断这个Bean是否带有@Aspect注解,如果有那么解析这个Bean的所有通知方法。看下是如何判断是否带有@Aspect注解的
AnnotationUtils.findAnnotation(clazz, Aspect.class) != null
下面说下处理@Aspect类的逻辑
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
主要是把里面的方法转成Advisor对象,看下最终包含哪些方法
1、SimpleAspect.around 2、SimpleAspect.before 3、SimpleAspect.after 4、SimpleAspect.afterReturning
注意是不包含切入点表达式的方法,只有通知,再回到上面wrapIfNecessary
|