- postProcessAfterInitialization初始化之后进行代理
-
- earlyProxyReferences是什么
- AbstractAutoProxyCreator的getEarlyBeanReference
- wrapIfNecessary代理
-
- getAdvicesAndAdvisorsForBean
-
- findEligibleAdvisors
-
- findAdvisorsThatCanApply
- AopUtils的findAdvisorsThatCanApply
- AopUtils的canApply是否可以应用
- 获取的结果:
postProcessAfterInitialization初始化之后进行代理
AOP的真正代理是在实例创建了,初始化之后进行代理,也就是在这个里面由AbstractAutoProxyCreator
进的postProcessAfterInitialization
方法进行处理:
首先查看是否在earlyProxyReferences
里存在,也就是已经处理过了,不存在就考虑是否要包装,也就是代理。
@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;
}
earlyProxyReferences是什么
这个其实就是前面讲过的为了解决单例的循环依赖,在实例化bean
之后,需要把一个工厂方法加到singletonFactories
集合里:
getEarlyBeanReference
这个方法其实是处理器处理的,一般的处理器不做什么,直接返回,只是AOP
的处理器会去做处理:
AbstractAutoProxyCreator的getEarlyBeanReference
就是放入集合里,然后判断要不要包装,其实就是在循环依赖注入属性的时候如果有AOP
代理的话,也会进行代理,然后返回。
wrapIfNecessary代理
这个跟前面讲Aspect注解解析差不多,会先进行判断是否是已经处理过,是否需要跳过,跳过的话直接就放进advisedBeans
里,表示不进行代理,但是这个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;
}
// Create proxy if we have advice. 获取拦截器
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);//要代理的就添加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
其实就是检查前面切面解析是否有通知器advisors
创建,有就返回,没有就是null
。
@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
findEligibleAdvisors
首先就是获取所有切面里的Advisor
,因为切面解析上篇讲过,在第一个自定义的bean
实例化之前就解析出来了,所以这个时候一般就是直接从缓存里获取了。然后找出适用于beanClass的Advisor
,然后进行扩展,会增加一个ExposeInvocationInterceptor
的内部实例DefaultPointcutAdvisor
,为了暴露AOP
调用,以便于一些AspectJ
类型的切点匹配,最后进行排序,这里的排序很重要,直接影响后面通知的方法调用顺序,然后返回。
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();//获取所有切面中的Advisor
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);//排序
}
return eligibleAdvisors;
}
findAdvisorsThatCanApply
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
AopUtils的findAdvisorsThatCanApply
前面是先判断IntroductionAdvisor
类型的,这个是跟introduction
功能相关的,会用到DeclareParents
注解,说的就是把某一个包下的所有类都实现某个接口,具体的实行方法会用到另外一个实现类,可以把一个类变成一个接口类型的,而且还实现了,不需要改动原来的类,很神奇,当然我们暂时不说这个。我们说一般的。一般的就是遍历每一个Advisor
,然后判断是否可以应用到目标类clazz
上,可以的话就加入候选列表。
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new ArrayList<>();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
AopUtils的canApply是否可以应用
其实能不能用,切点上都定义了呀,所以这里就只要拿出切点来匹配下就可以啦,确实他也是这么做的,具体内部的代码涉及到aspectj
,有兴趣的去看吧,现在知道大致流程就好了,就是我切点知道要在什么包下什么类,什么方法上用通知,所以你传进来的类,我都要检查一下,看advisor
能不能用:
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
else if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
return canApply(pca.getPointcut(), targetClass, hasIntroductions);//是否匹配切点表达式信息
}
else {
return true;
}
}
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
if (!pc.getClassFilter().matches(targetClass)) {
//targetClass是否匹配切点表达式
return false;
}
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
//存放要代理的类,以及他的接口
Set<Class<?>> classes = new LinkedHashSet<>();
if (!Proxy.isProxyClass(targetClass)) {
//不是JDK的代理类
classes.add(ClassUtils.getUserClass(targetClass));
}
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
for (Class<?> clazz : classes) {
//查看方法是否是切点表达式匹配的
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
获取的结果:
好了,获取通知器基本讲完了,其实就是去匹配你传入的类和切点表达式中的定义,符合的话就会返回相应的通知器,准备进行代理。
好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。