Spring 5.x Source trip forty-six AOP proxy details of a wrapIfNecessary
After postProcessAfterInitialization proxy initialization
Real proxy AOP is to create an instance of, and proxy after initialization, which is in the inside by the AbstractAutoProxyCreator
advanced postProcessAfterInitialization
processing method:
First check whether earlyProxyReferences
there is there, that is has been processed, it does not exist to consider whether to packaging, but also It is the agent.
@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;
}
What is earlyProxyReferences
Recall that this fact in order to solve the circular dependency of a single embodiment, in the example of the bean
following, the method requires a factory applied to singletonFactories
the collection:
getEarlyBeanReference
This method is actually processed by the processor, the processor typically what not, return directly, only AOP
the processor will do the deal:
AbstractAutoProxyCreator的getEarlyBeanReference
Is placed in the collection, and then determine whether or not the packaging, in fact, in the cycle of dependency injection property of time if there is AOP
a proxy, then, will be the agent, and then return.
wrapIfNecessary agent
The talk with the front Aspect annotation resolve almost, will first determine whether that has been treated, whether to skip, then skip directly into the advisedBeans
inside, it means no proxy, but this bean
treated, otherwise get notifications interceptors, then began a proxy.
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
In fact, the front section to check whether there notifier resolve advisors
to create, have returned, is no 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
The first is to get all facets where Advisor
, because analytical section on the article mentioned, the first custom bean
before instantiation to parse out, so this time the general is acquired directly from the cache. Then find a suitable beanClass Advisor
, and then expand, will add a ExposeInvocationInterceptor
internal instance DefaultPointcutAdvisor
, in order to expose AOP
call, in case some AspectJ
type of matching cut-off point, and finally, the sort here is very important, a direct impact on the method of notification after the call to order and then return.
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 of findAdvisorsThatCanApply
The front is to determine IntroductionAdvisor
the type, this is with introduction
functionally related, will use DeclareParents
annotations to say is that all classes in one package implements an interface, the specific implementation method will be used to achieve another class, you can put a class into an interface type, but also to achieve, do not need to change the original class, it is amazing, of course, we do not say that. We say in general. It is generally through each Advisor
, and then determines whether applied to the target class clazz
, the words can be added to the candidate list.
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;
}
The canApply can be applied whether AopUtils
In fact, it can not be used, the cut-off point are defined Yeah, so just come here to match the cut point to be all right, he is really doing, specific internal code involved aspectj
, interested to see it, now I know the general process is like, what I want to know what the point of tangency class in what package, what with the notification method, so you passed in class, I have to check to see advisor
can not be used:
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;
}
Get results:
Well, get notifications is basically finished, in fact, to match the definition of the class and you pass the point of tangency expression, then it will return in line with the corresponding notifier in preparation for the agent.
Well, here today, we hope to help study and understand, do not spray the Great God see, understand only their own learning, limited capacity, please excuse.