上面三篇文档介绍了bean的生命周期。通知是如何绑定的,代理对象是如何产生的以及aop是如何调用的呢。
一个aop切面包含了哪些内容了
一个切面有多个切入点,每个切入点有不同的通知,通知分为before after around(此环境)
around 的通知有两个也是之前和之后,这个之前会在before之前执行,这个之后会在after之前执行。
那么aop是如何调用的呢。比如我们需要增强A类的query方法。如果A是一个接口,代理对象通过jdk动态代理生成,如果是一个类,代理对象通过cglib生成。那么增强的A类的query方法会有通知,切点会切query方法的通知。当调用query方法的时候,绑定的通知对象即该切面对象会调用增强的通知,不是代理对象。代理对象再调用query方法,调用完后,且秒对象会再调用around 之后的方法 和 after 方法。
比如 我们现在声明了一个切面(本应用只支持简单的表达式如execution(public * com.xx.service.OrderService.*(..)) 粒度只有类级别的)
此处并未按照Aspect api源码进行解析匹配对象
@XxComponent
@XxAspect
public class ServiceAop {
@XxPointcut("execution(public * com.xx.service.OrderService.*(..))")
public void pointCut01(){}
@XxBefore("pointCut01()")
public void beforeCut01() {
System.out.println("==before 01==");
}
@XxAfter("pointCut01()")
public void afterCut01() {
System.out.println("==after 01==");
}
@XxAround("pointCut01()")
public void aroundCut01(){
System.out.println("==around 01==");
}
}
切面对象 ServiceAop 切点OrderService的所有方法,切点通知pointCut01() 有XxBefore,XxAfter,XxAround三种通知
OrderService 有个query 方法需要增强 最终是 OrderService的代理对象执行query,ServiceAop 去执行三个切点的方法。所以我们是要将 OrderService 和 ServiceAop ,ServiceAop的切点,切点的通知进行绑定
XxAspectJ --> List<XxAspectPointCut>
XxAspectPointCut -->List<XxAspectAdvice>
具体的关系可以看gitee源码里面的:advisor 包对象关系
https://gitee.com/wanganfen/xx-spring/tree/master/simple-spring/src/main/java/com/xx/advisor
通知处理器:handle包 有之前、之后,环绕的处理器
https://gitee.com/wanganfen/xx-spring/tree/master/simple-spring/src/main/java/com/xx/handle
具体的执行就在创建代理类的invoke方法里面
public Object invokeProxy(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object invoke = null;
XxAspectJ xxAspectJ = new XxAspectJ(beanFactory);
xxAspectJ = xxAspectJ.getXxAspectJByInstanceName(beanName);
XxAspectPointCut xxAspectPointCut = xxAspectJ.getPointCuts().stream().filter(x -> x.getInstanceMaps().keySet().contains(beanName)).findFirst().get();
List<MethodAdviceHandle> beansOfType = (List<MethodAdviceHandle>) beanFactory.getBeansOfType().get(MethodAdviceHandle.class);
List<MethodAdviceHandle> methodAdviceHandleList = beansOfType.stream().sorted(Comparator.comparing(MethodAdviceHandle::order)).collect(Collectors.toList());
List<XxAspectAdvice> advices = xxAspectPointCut.getAdvices();
for (MethodAdviceHandle methodAdviceHandle : methodAdviceHandleList) {
methodAdviceHandle.applyMethodBeforeAdviceHandleInitialization(xxAspectJ.getTarget(),advices,args);
}
if(Objects.isNull(proxy)){
invoke = method.invoke(target, args);
}else{
invoke = methodProxy.invokeSuper(proxy, args);
}
for (MethodAdviceHandle methodAdviceHandle : methodAdviceHandleList) {
methodAdviceHandle.applyMethodAfterAdviceHandleInitialization(xxAspectJ.getTarget(),advices,args);
}
return invoke;
}
jdk动态代理传进去的是一个目标对象,即原始对象。
cglib动态代理传进去的是一个代理对象。
代理及逻辑:proxy包
https://gitee.com/wanganfen/xx-spring/tree/master/simple-spring/src/main/java/com/xx/proxy
生成代理对象再Spring Bean的生命周期的最后一步
public class XxAutoProxyCreatorBeanPostProcessor implements XxBeanPostProcessor{
private final XxDefaultListableBeanFactory beanFactory;
public XxAutoProxyCreatorBeanPostProcessor(XxDefaultListableBeanFactory beanFactory){
this.beanFactory = beanFactory;
}
@Override
public Object applyObjectBeforeInstance(String beanName, Object instance) {
List<XxAspectJ> xxAspectJList = new ArrayList<>(beanFactory.getXxAspectJMaps().values());
xxAspectJList.forEach(x->{
List<XxAspectPointCut> pointCuts = x.getPointCuts();
pointCuts.forEach(y->{
if(y.getInstanceMaps().keySet().contains(beanName)){
XxBeanDefinition xxBeanDefinition = beanFactory.getXxBeanDefinitionMaps().get(beanName);
xxBeanDefinition.setProxy(true);
}
});
});
return instance;
}
@Override
public Object applyObjectAfterInstance(String beanName, Object instance) {
XxBeanDefinition xxBeanDefinition = beanFactory.getXxBeanDefinitionMaps().get(beanName);
if(xxBeanDefinition.isProxy){
return getProxy(beanName,instance);
}
return instance;
}
private Object getProxy(String beanName , Object instance){
ProxyFactory proxyFactory = new ProxyFactory(beanName,instance,beanFactory);
return proxyFactory.createProxy();
}
}
通常我们写的jdk或者是cglib动态代理的案例,目标对象都是写死了。但是有ioc之后,在这个对象的生命周期中就可以动态的去生成代理对象了,并且直接调用好已经绑定的通知了。
手写详情可见地址
https://gitee.com/wanganfen/xx-spring/tree/master/simple-spring
主要包:aop 包 和 proxy包