先来看一个简单的例子:
先建一个Person类作为业务类:
public class Person {
public int doDivision(int a, int b) {
return (a / b);
}
}
新建切面类LogWriter,此处只加了两个通知:
@Aspect //指定此类为一个切面类
public class LogWriter {
//切点及切入点表达式
@Pointcut("execution(public int com.practice.bean.Person.*(..))")
public void pointCut() {
}
@Before("pointCut()") //前置通知
public void beforeDivision(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
System.out.println("LogWriter....+before" + joinPoint.getSignature().getName() + Arrays.asList(args));
}
//返回通知, 在方法返回结果之后执行
@AfterReturning(value="pointCut()",returning="result")
public void divisionReturn(JoinPoint joinPoint,Object result){
System.out.println(""+joinPoint.getSignature().getName()+"正常返回,结果为:"+result);
}
}
配置类如下,为注入业务类和启用自动代理:
@Configuration
@EnableAspectJAutoProxy//启用切面自动代理
public class MainConfig {
@Bean
public Person person() {
return new Person();
}
@Bean
public LogWriter logWriter() {
return new LogWriter();
}
}
执行测试类:
@Test
public void test01() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Person person = applicationContext.getBean(Person.class);
person.doDivision(1, 2);
}
结果如下:
LogWriter....+beforedoDivision[1, 2]
doDivision正常返回,结果为:0
Tips:AspectJ支持五种切面类型的通知注解:
- @Before: 前置通知, 在方法执行之前执行
- @After: 后置通知, 在方法执行之后执行 。
- @AfterRunning: 返回通知, 在方法返回结果之后执行
- @AfterThrowing: 异常通知, 在方法抛出异常之后,(方法参数中加上Exception可以接收到返回的异常)
- @Around: 环绕通知, 围绕着方法执行
@Around方法做一个测试,还是以上代码,切面类中的方法为:
@Around("pointCut()")
public Object aroundMethod(ProceedingJoinPoint jointPoint) throws Throwable{
//前置方法
long startTime=System.currentTimeMillis();
System.out.println("-->开始时间为:"+startTime);
//调用执行目标方法(result为目标方法执行结果)
Object result=jointPoint.proceed();
System.out.println("执行结果为:"+result);
long endTime=System.currentTimeMillis();
//后置方法。记录结束时间和执行时长
System.out.println("-->结束时间为:"+endTime+"。执行时长为:"+(endTime-startTime));
//获取业务方法签名
System.out.println(jointPoint.getSignature().getName());
//获取执行参数
System.out.println(Arrays.asList(jointPoint.getArgs()));
return result;
}
测试结果为:
-->开始时间为:1571236822985
执行结果为:0
-->结束时间为:1571236822992。执行时长为:7
doDivision
[1, 2]
一.在配置类中,引入了@EnableAspectJAutoProxy注解,这个注解是做什么的?
1.先看一下这个注解的源代码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
可以看出该注解为容器导入了AspectJAutoProxyRegistrar组件,
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar
该组件实现了ImportBeanDefinitionRegistrar接口,这个接口可以为容器导入组件(在第一篇文章中已有介绍)
可以看到为容器导入了org.springframework.aop.config.internalAutoProxyCreator=AnnotationAwareAspectJAutoProxyCreator
导入的类如下(源码注释):
Registers an {@link org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
------->
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
beanName为:
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
"org.springframework.aop.config.internalAutoProxyCreator";
二.注入的AnnotationAwareAspectJAutoProxyCreator组件做了什么?
AnnotationAwareAspectJAutoProxyCreator类图如下:
21.该类实现了Aware接口下的BeanFactoryAware接口,说明为AnnotationAwareAspectJAutoProxyCreator类注入了beanFactory。
具体实现在AbstractAdvisorAutoProxyCreator类中:
@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);
}
initBeanFactory又被子类AnnotationAwareAspectJAutoProxyCreator重写:
@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);
}
2.2实现了BeanPostProcess接口,说明在初始化Bean阶段会调用后置处理器方法。
三.AnnotationAwareAspectJAutoProxyCreater组件的创建过程。
在registerBeanPostProcessors(beanFactory)方法中注册bean的后置处理器来拦截bean的创建:
进入registerBeanPostProcessors方法,
- 先获取ioc容器已经定义了的需要创建对象的所有BeanPostProcessor的ID;
- 注册BeanPostProcessorChecker;
- 优先注册实现了PriorityOrdered接口的BeanPostProcessor;
- 再给容器中注册实现了Ordered接口的BeanPostProcessor;
- 注册没实现优先级接口的BeanPostProcessor;
在beanFactory.getBean(ppName, BeanPostProcessor.class)创建了BeanPostProcess组件,最后注册组件到容器中:
//找到所有的BeanPostProcessessors,并注册到容器中
registerBeanPostProcessors(beanFactory, internalPostProcessors);
---》
private static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {
for (BeanPostProcessor postProcessor : postProcessors) {
beanFactory.addBeanPostProcessor(postProcessor);
}
}
四.AnnotationAwareAspectJAutoProxyCreator(InstantiationAwareBeanPostProcessor) 的作用:
- 以下为获取业务类Person为例:
进入refresh()方法中的finishBeanFactoryInitialization(beanFactory),完成BeanFactory初始化工作,创建剩下的单实例bean
getBean->doGetBean()->getSingleton()-->先从缓存中获取,如果没有获取到则执行:
return createBean(beanName, mbd, args);进入创建Bean方法。
1.进入此方法,我们在容器中获取要创建的组件,在组件创建之前,会执行下面的方法:
给后置处理器一个机会去创建代理实例去替代Bean的实例对象:
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
进入resolveBeforeInstantiation方法,有执行下面两个方法:
---->applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
---> applyBeanPostProcessorsAfterInitialization(bean, beanName);
第一个方法的主要逻辑执行的为下面这个接口中定义的方法:
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor
判断是否为InstantiationAwareBeanPostProcessor,如果是则执行ibp.postProcessBeforeInstantiation(beanClass, beanName);
此方法为AbstractAutoProxyCreator实现:
- 判断当前bean是否在advisedBeans中(保存了所有需要增强bean)
- 判断当前bean是否是基础类型的Advice、Pointcut、Advisor、AopInfrastructureBean,或者是否是切面(@Aspect)或是否需要跳过
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// TODO: Consider optimization by caching the list of the aspect names
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}
- 获取候选的增强器(切面里面的通知方法)【List<Advisor> candidateAdvisors】 每一个封装的通知方法的增强器是 InstantiationModelAwarePointcutAdvisor;判断每一个增强器是否是 AspectJPointcutAdvisor 类型的;返回true
- 父类super方法永远返回false
Tips:在此处不会执行以下方法创建代理对象逻辑:
/*如果我们有自定义的targetsource将在此处创建代理。禁止不必要的目标bean默认实例化:targetsource将以自定义方式处理目标实例。*/
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
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;
}
返回为空;第二个applyBeanPostProcessorsAfterInitialization方法在此处不会执行;
2.接下来会进入创建对象的逻辑:
doCreateBean-->initializeBean-->
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
第二个方法主要逻辑在这-->processor.postProcessAfterInitialization(result, beanName)
此处在AbstractAutoProxyCreator类中实现:
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
-->return wrapIfNecessary(bean, beanName, cacheKey):
如果有通知的话则创建代理
// Create proxy if we have advice.
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;
}
1、获取当前bean的所有通知方法 Object[] specificInterceptors
1、找到候选的所有的通知方法(找哪些通知方法是需要切入当前bean方法的)
2、获取到能在bean使用的通知方法。
3、给获取到的通知方法排序
2、将当前bean保存到advisedBeans中;
3、创建当前bean的代理对象;
return proxyFactory.getProxy(getProxyClassLoader());
1、获取所有通知方法
2、保存到proxyFactory
3、创建代理对象:Spring自动决定
@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);
}
}
Tips:两种代理方式:
1.JdkDynamicAopProxy(config);jdk动态代理;
2.ObjenesisCglibAopProxy(config);cglib的动态代理;
4、给容器中返回当前组件使用cglib增强了的代理对象;
5、以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程;
五、代理对象方法的执行
在业务方法打上断点,执行进入:
容器中保存了组件的代理对象(cglib增强后的对象),这个对象里面保存了详细信息(比如增强器,目标对象,xxx);
1.进入CglibAopProxy类的下面这个方法:拦截目标方法的执行
CglibAopProxy.intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy)
2.根据ProxyFactory对象获取将要执行的目标方法拦截器链:
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
进入上面的方法,主要逻辑如下--->拦截器链的获取:
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);
用List<Object> interceptorList = new ArrayList<>(advisors.length);来保存所有拦截器
可以看到其中有两个:
一个默认的ExposeInvocationInterceptor 和 1个LogWriter的aroundMethod通知方法。
遍历所有的通知方法,将其转为Interceptor---->registry.getInterceptors(advisor);
如果是MethodInterceptor,直接加入到集合中,如果不是,使用AdvisorAdapter将增强器转为MethodInterceptor;
转换完成返回MethodInterceptor数组;
拦截器链(每一个通知方法又被包装为方法拦截器,利用MethodInterceptor机制)
registry.getInterceptors(advisor);
-----》
@Override
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<>(3);
Advice advice = advisor.getAdvice();
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) {
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[0]);
}
3.如果没有拦截器链,直接执行目标方法;
4. 如果有拦截器链,把需要执行的目标对象,目标方法,拦截器链等信息传入创建的一个 CglibMethodInvocation 对象,并调用 proceed()方法
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
5.拦截器链的触发过程:
如果没有拦截器执行执行目标方法,或者拦截器的索引和拦截器数组-1大小一样(指定到了最后一个拦截器)执行目标方法;
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
currentInterceptorIndex 默认为-1,每执行一个通知方法则++currentInterceptorIndex ;
private int currentInterceptorIndex = -1;
++this.currentInterceptorIndex
链式获取每一个拦截器,拦截器执行invoke方法,每一个拦截器等待下一个拦截器执行完成返回以后再来执行;
当遍历到最后一个拦截器时,执行
return invokeJoinpoint();跳出递归调用
前置通知在递归向上层返回时调用了,先执行了前置通知方法:
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
------>
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
执行完前置通知后进入目标方法执行然后依次执行各通知,利用catch,finally等控制异常通知和返回通知的顺序。
拦截器链的机制,保证通知方法与目标方法的执行顺序;