This is the third day of my participation in the August More text Challenge. For details, see:August is more challenging
An overview of the
Have used the Spring framework partners all know, the importance of SPRING AOP, learning source code is essential, the text record some source tracking source skills learning experience, the need to correct and correct the error please leave a comment below
A general analysis of AOP principle
This Internet search a lot of, repeat to elaborate without meaning, say next my personal understanding, key two words agent what call agent, and the bank is the same, you do what should pass somebody else’s hand, so as long as your money has changed the bank all know
Same thing with Spring. Let’s say I have a class
public class A{
void test(a){
system.out.println("test run"); }}Copy the code
We need to make an aspect of test() in A and spring will generate A proxy object that you actually call, so you’ll have an aspect when you call the method
class ProxyThe $1{ A a; test(){ a.test(); }}Copy the code
This can also be viewed as a static proxy. If you have multiple proxies, you might see something like thisBut this code is not dead, so the proxy cannot be static, also known as dynamic proxy
There are two ways to dynamically generate proxy classes in Spring
- cglib
- The JDK agent
How to use them in detail is not explained in this article
To prepare the demo
The first is a Spring portal
@ComponentScan("bean")
@EnableAspectJAutoProxy
public class Application {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = newAnnotationConfigApplicationContext(Application.class); ComService bean = context.getBean(ComService.class); bean.testAop(); }}Copy the code
A proxied object
@Service
public class ComService {
public void testAop(a){
System.out.println("===== ComService ===="); }}Copy the code
Section definition
@Aspect
@Component
public class Aop {
@Pointcut("execution(public * bean.service.ComService.testAop())")
public void businessService(a) {}
@Around("businessService()")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
// start stopwatch
Object retVal = pjp.proceed();
System.out.println(pjp.getSignature().getName() + "=== section");
// stop stopwatch
returnretVal; }}Copy the code
Source code analysis
In fact, online such source code parsing posts many, but have in common, are directly tell you where to look at this code, and then paste some of their understanding comments, but as a new learning spring or spring source research is not deep development partners, I want to know how you find this code, This article shares where I found the key source code step by step. The technique may be very low, but it is quite practical. This is how I find most framework source code if I don’t read the blog first
Here are two main answers
When is the section resolved
In a project we represent aspects by adding annotations to the classes@Aspect
So there must be some code that’s the easiest way to parse this annotation and just see where it’s called, so I just downloaded the spring source code, and that’s itYou can seeorg.aspectj.internal.lang.reflect.AjTypeImpl#getPerClause
We have get and we’re looking at where is this method being calledAt this point, you can interrupt in some way you think is possible and see if it comes in (it’s low but I think it’s useful for a guy like me).
// The code is abbreviated
List<String> aspectNames = this.aspectBeanNames;
// This method is called more than once
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true.false);
for (String beanName : beanNames) {
....
// Check whether there are aspect annotations
// This is not the class that calls the method, so finding this code is a fluke
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
// This will call the method I guessed earlier
/ / the method will be called a below advisors. The addAll (this) advisorFactory) getAdvisors (factory));
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
...
}
else{... }}}this.aspectBeanNames = aspectNames;
return advisors;
}
Copy the code
How to generate proxy classes
Here to find the source code some clever, a few days ago just learned the source code of the Spring bean lifecycle, so directly inDefaultSingletonBeanRegistry#getSingleton()
Debug, write a breakpoint conditionAnd then a little bit of release code, look at the return value obj and if it’s changed then it’s foundorg.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
In this method, the object has been initially created
You can seeAbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
After this line of code this object is no longer the same object as it was before and then we start to analyze it
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
Copy the code
Similarly is also break point Can find AbstractAutoProxyCreator# postProcessAfterInitialization – > AbstractAutoProxyCreator# wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {...// Create an aspect proxy
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if(specificInterceptors ! = DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);
// Generate the proxy class
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;
}
Copy the code
So let’s go down proxyFactor #getProxy
// createAopProxy() this method returns an object that implements AopProxy
return createAopProxy().getProxy(classLoader);
Copy the code
Defaultaopproxyfactor #createAopProxy This determines how the proxy class is generated
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if(! IN_NATIVE_IMAGE &&// Whether to optimize
(config.isOptimize() ||
// Whether direct proxy and interface
config.isProxyTargetClass() ||
/ / judge whether realized org. Springframework. Aop. SpringProxy interface classes
hasNoUserSuppliedProxyInterfaces(config))) {
// Class that needs to be proxiedClass<? > targetClass = config.getTargetClass();if (targetClass == null) {
throw new AopConfigException();
}
// If it is an interface
if (targetClass.isInterface()
// Is itself a proxy class
|| Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return newJdkDynamicAopProxy(config); }}Copy the code
Simply put, if the class being proxied is an interface, or is itself a proxy class then use JDK proxy, otherwise it’s a Cglib proxy because the JDK can only proxy interfaces
So either the JDK proxy or the Cglib proxy, the purpose is to generate the layer proxy class and then I want to know what to do if I have multiple sections,
org.springframework.aop.framework.JdkDynamicAopProxy#invoke
org.springframework.aop.framework.CglibAopProxy#getProxy(java.lang.ClassLoader)
Debug the above code to see what methods a bean has in its facets
feeling
With this aop general flow in mind, we can have a general idea of the problems we encounter in development. For example, common AOP failure problems can be summarized in two aspects
- The aspect is not resolved to
- The proxy class is not generated
Most problems can be solved by debugging, if you know where to debug
The last
Welcome to comment below your source reading skills, I also want to learn