1. Start with annotations to find the corresponding core class

2. Draw the core class diagram and guess the core method

3. Read key methods and understand core processes

4. To summarize

1. Start with annotations to find the corresponding core class

Most of my recent work has been implementing AOP functions based on annotations. The most commonly used annotation to start AOP is @enableAspectJAutoProxy, which we’ll start with.

! [](https://upload-images.jianshu.io/upload_images/24533109-0c9c5d8ec32aa09c? imageMogr2/auto-orient/strip|imageView2/2/w/638/format/webp)

The steps of the GIF flow are as follows: @EnableAspectJAutoProxy –> AspectJAutoProxyRegistrar –>AopConfigUtils .registerAspectJAnnotationAutoProxyCreatorIfNecessary –>AnnotationAwareAspectJAutoProxyCreator.class

AnnotationAwareAspectJAutoProxyCreator (below) to see the Chinese annotation, make sure it is the core of AOP classes! — Wen Anshi 20191020

AspectJAwareAdvisorAutoProxyCreator subclass, used to deal with the current application context in the comments section

Any classes annotated by AspectJ are automatically identified.

If the SpringAOP proxy pattern is recognized, the Spring proxy pattern is preferred.

It overrides the method execution join point

If you use aop:include elements, only @AspectJ beans whose names match the include pattern are treated as facets and are automatically proxied by Spring.

Please refer to the processing of Spring Advisors.

org.springframework.aop

.framework.autoproxy.AbstractAdvisorAutoProxyCreator

@SuppressWarnings(“serial”)

publicclassAnnotationAwareAspectJAutoProxyCreator

extendsAspectJAwareAdvisorAutoProxyCreator

{

/ /… Omit the implementation

} Annotation section

The core class is found, but the core method is not! Let’s try to draw a class diagram to identify the core methods.

2. Draw the core class diagram and guess the core method

AnnotationAwareAspectJAutoProxyCreator part of the class diagram.

AnnotationAwareAspectJAutoProxyCreator saw AnnotationAwareAspectJAutoProxyCreator realized BeanPostProcessor from class diagram, AOP functionality should be executed after the Bean is created, Guess AnnotationAwareAspectJAutoProxyCreator realize BeanPostProcessor postProcessAfterInitialization (instantiation bean post-processing) is the core method. See AnnotationAwareAspectJAutoProxyCreator postProcessAfterInitialization method, actually this method in AbstractAutoProxyCreator father classes.

! [](https://upload-images.jianshu.io/upload_images/24533109-33f95cf075382ffe? imageMogr2/auto-orient/strip|imageView2/2/w/486/format/webp)

/ / AbstractAutoProxyCreator postProcessAfterInitialization in implementation

@Override

publicObjectpostProcessAfterInitialization(Object bean, String beanName)

throwsBeansException

{

if(bean ! =null) {

Object cacheKey = getCacheKey(bean.getClass(), beanName);

if(! this.earlyProxyReferences.contains(cacheKey)) {

returnwrapIfNecessary(bean, beanName, cacheKey);

}

}

returnbean;

}

WrapIfNecessary (createProxy) wrapIfNecessary (createProxy) Make sure you’re in the right place.

protectedObjectwrapIfNecessary

(Object bean, String beanName, Object cacheKey)

{

if(beanName ! =null&&this.targetSourcedBeans.contains(beanName)) {

returnbean;

}

if(Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {

returnbean;

}

if(isInfrastructureClass(bean.getClass())

|| shouldSkip(bean.getClass(), beanName)) {

this.advisedBeans.put(cacheKey, Boolean.FALSE);

returnbean;

}

// Create the proxy

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,newSingletonTargetSource(bean));

this.proxyTypes.put(cacheKey, proxy.getClass());

returnproxy;

}

this.advisedBeans.put(cacheKey, Boolean.FALSE);

returnbean;

}

BeanPostProcessor AnnotationAwareAspectJAutoProxyCreator realized postProcessAfterInitialization method, In this method, wrapIfNecessary implements the functions of AOP. There are two and core methods in wrapIfNecessary

GetAdvicesAndAdvisorsForBean for current bean matching enhancer

CreateProxy creates the proxy for the current bean. To understand the core flow, you need to analyze these two methods.

3. Read key methods and understand core processes

3.1 getAdvicesAndAdvisorsForBean for current bean matching enhancer

View the source code is as follows, the default implementation in AbstractAdvisorAutoProxyCreator.

@Override

@Nullable

protectedObject[] getAdvicesAndAdvisorsForBean(

Class beanClass, String beanName,

@NullableTargetSource targetSource) {

List advisors = findEligibleAdvisors(beanClass, beanName);

if(advisors.isEmpty()) {

returnDO_NOT_PROXY;

}

returnadvisors.toArray();

}

If you look at the findEligibleAdvisors method, you do three things

Find all enhancers, that is, all beans annotated with @aspect

Find the matched enhancer, that is, match the current bean according to the expression on the @before, @after annotations, and expose the matched bean.

To extend and sort matched enhancers, sort them by the data value of @Order or PriorityOrdered getOrder, the smaller, the more advanced.

protectedListfindEligibleAdvisors(Class<? > beanClass, String beanName){

// Find all enhancers

List candidateAdvisors = findCandidateAdvisors();

// Find all matching enhancers

List eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);

extendAdvisors(eligibleAdvisors);

if(! eligibleAdvisors.isEmpty()) {

/ / sorting

eligibleAdvisors = sortAdvisors(eligibleAdvisors);

}

returneligibleAdvisors;

}

AnnotationAwareAspectJAutoProxyCreator rewrite the findCandidateAdvisors, below we look at specific implementation

3.1.1 findCandidateAdvisors find all enhancer, that is, all @ Aspect annotated beans

@Override

protectedListfindCandidateAdvisors(){

// Add all the Spring advisors found according to superclass rules.

List advisors =super.findCandidateAdvisors();

// Build Advisors for all AspectJ aspects in the bean factory.

if(this.aspectJAdvisorsBuilder ! =null) {

// @aspect annotated classes are added here

advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());

}

returnadvisors;

}

From this method we can see processing @ Aspect of annotation of the bean method is: enclosing aspectJAdvisorsBuilder. BuildAspectJAdvisors (). This method is as follows:

publicListbuildAspectJAdvisors(){

List aspectNames =this.aspectBeanNames;

if(aspectNames ==null) {

synchronized(this) {

aspectNames =this.aspectBeanNames;

if(aspectNames ==null) {

List advisors =newArrayList<>();

aspectNames =newArrayList<>();

// Find all BeanName

String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(

this.beanFactory, Object.class,true,false);

for(String beanName : beanNames) {

if(! isEligibleBean(beanName)) {

continue;

}

// It must be noted that the bean is exposed ahead of time and cached by the Spring container, but cannot be woven at this point.

Class beanType =this.beanFactory.getType(beanName);

if(beanType ==null) {

continue;

}

if(this.advisorFactory.isAspect(beanType)) {

// Find all classes annotated by @aspect

aspectNames.add(beanName);

AspectMetadata amd =newAspectMetadata(beanType, beanName);

if(amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {

MetadataAwareAspectInstanceFactory factory =

newBeanFactoryAspectInstanceFactory(this.beanFactory, beanName);

// Parse encapsulation returns as Advisor

List classAdvisors =this.advisorFactory.getAdvisors(factory);

if(this.beanFactory.isSingleton(beanName)) {

this.advisorsCache.put(beanName, classAdvisors);

}

else{

this.aspectFactoryCache.put(beanName, factory);

}

advisors.addAll(classAdvisors);

}

else{

// Per target or per this.

if(this.beanFactory.isSingleton(beanName)) {

thrownewIllegalArgumentException(“Bean with name ‘”+ beanName +

“‘ is a singleton, but aspect instantiation model is not singleton”);

}

MetadataAwareAspectInstanceFactory factory =

newPrototypeAspectInstanceFactory(this.beanFactory, beanName);

this.aspectFactoryCache.put(beanName, factory);

advisors.addAll(this.advisorFactory.getAdvisors(factory));

}

}

}

this.aspectBeanNames = aspectNames;

returnadvisors;

}

}

}

if(aspectNames.isEmpty()) {

returnCollections.emptyList();

}

List advisors =newArrayList<>();

for(String aspectName : aspectNames) {

List cachedAdvisors =this.advisorsCache.get(aspectName);

if(cachedAdvisors ! =null) {

advisors.addAll(cachedAdvisors);

}

else{

MetadataAwareAspectInstanceFactory factory =this.aspectFactoryCache.get(aspectName);

advisors.addAll(this.advisorFactory.getAdvisors(factory));

}

}

returnadvisors;

}

This approach can be summarized as:

Find all the BeanName

Filter out classes annotated by @aspect based on BeanName

Class, Before. Class, After. Class, AfterReturning. Class, AfterThrowing. Each method corresponds to an Advisor.

3.2 createProxy Creates a proxy for the current bean.

3.2.1 Two Methods for Creating an Agent

It is well known that there are two common ways to create proxies: JDK creation and CGLIB. Let’s take a look at these two examples.

3.2.1.1 JDK proxy Creation example

importjava.lang.reflect.InvocationHandler;

importjava.lang.reflect.Method;

importjava.lang.reflect.Proxy;

publicclassJDKProxyMain{

publicstaticvoidmain(String[] args){

JDKProxyTestInterface target =newJDKProxyTestInterfaceImpl();

// Create a proxy object based on the target object

JDKProxyTestInterface proxy =

(JDKProxyTestInterface) Proxy

.newProxyInstance(target.getClass().getClassLoader(),

target.getClass().getInterfaces(),

newJDKProxyTestInvocationHandler(target));

// Invoke the proxy object method

proxy.testProxy();

}

interfaceJDKProxyTestInterface{

voidtestProxy();

}

staticclassJDKProxyTestInterfaceImpl

implementsJDKProxyTestInterface

{

@Override

publicvoidtestProxy(){

System.out.println(“testProxy”);

}

}

staticclassJDKProxyTestInvocationHandler

implementsInvocationHandler

{

privateObject target;

publicJDKProxyTestInvocationHandler(Object target){

this.target=target;

}

@Override

publicObjectinvoke(Object proxy, Method method,

Object[] args)

throwsThrowable{

System.out.println(” before execution “);

Object result= method.invoke(this.target,args);

System.out.println(” after execution “);

returnresult;

}

}

3.2.1.2 Cglib proxy Creation Example

importorg.springframework.cglib.proxy.Enhancer;

importorg.springframework.cglib.proxy.MethodInterceptor;

importorg.springframework.cglib.proxy.MethodProxy;

importjava.lang.reflect.Method;

publicclassCglibProxyTest{

staticclassCglibProxyService{

publicCglibProxyService(){

}

voidsayHello(){

System.out.println(” hello !” );

}

}

staticclassCglibProxyInterceptorimplementsMethodInterceptor{

@Override

publicObjectintercept(Object sub, Method method,

Object[] objects, MethodProxy methodProxy)

throwsThrowable

{

System.out.println(“before hello”);

Object object = methodProxy.invokeSuper(sub, objects);

System.out.println(“after hello”);

returnobject;

}

}

publicstaticvoidmain(String[] args){

// The process of obtaining proxy objects through CGLIB dynamic proxies

Enhancer enhancer =newEnhancer();

// Set the enhancer object’s parent class

enhancer.setSuperclass(CglibProxyService.class);

// Set the enhancer callback object

enhancer.setCallback(newCglibProxyInterceptor());

// Create a proxy object

CglibProxyService proxy= (CglibProxyService)enhancer.create();

System.out.println(CglibProxyService.class);

System.out.println(proxy.getClass());

// Call the target method through the proxy object

proxy.sayHello();

}

}

3.2.1.3 Differences between JDK proxy creation and Cglib proxy creation

! [](https://upload-images.jianshu.io/upload_images/24533109-8547648ef7f0c575? imageMogr2/auto-orient/strip|imageView2/2/w/657/format/webp)

3.2.2 How does Spring choose which method to use

Spring’s selection selects how to delegate when in DefaultAopProxyFactory.

publicclassDefaultAopProxyFactoryimplementsAopProxyFactory,

Serializable

{

@Override

publicAopProxycreateAopProxy(AdvisedSupport config)

throwsAopConfigException

{

if(config.isOptimize()

|| config.isProxyTargetClass()

|| hasNoUserSuppliedProxyInterfaces(config)) {

Class targetClass = config.getTargetClass();

if(targetClass ==null) {

thrownewAopConfigException(

“TargetSource cannot determine target class: “

+”Either an interface or a target “+

” is required for proxy creation.”);

}

if(targetClass.isInterface()

|| Proxy.isProxyClass(targetClass)) {

returnnewJdkDynamicAopProxy(config);

}

returnnewObjenesisCglibAopProxy(config);

}

else{

returnnewJdkDynamicAopProxy(config);

}

}

/ /…

}

Config.isoptimize () looks at the source code comments and finds that this is how to configure active policies when using the Cglib agent. This value is generally not recommended!

In the config. IsProxyTargetClass () is @ EnableAspectJAutoProxy proxyTargetClass attributes.

//exposeProxy=true ProxyTargetClass =true CGLIB generate proxy @enableAspectJAutoProxy (exposeProxy=true,proxyTargetClass=true)

HasNoUserSuppliedProxyInterfaces whether there is any agent interface

To summarize how Spring chooses to create proxies:

If proxyTargetClass=true is set, it must be a CGLIB agent

If proxyTargetClass=false, the target object implements the interface and goes to the JDK proxy

If no interface is implemented, use the CGLIB proxy

4. To summarize

How does Spring implement AOP? You can say:

AnnotationAwareAspectJAutoProxyCreator is the core AOP processing class

AnnotationAwareAspectJAutoProxyCreator implements BeanProcessor postProcessAfterInitialization is the core of them.

Core implementation is divided into 2 steps getAdvicesAndAdvisorsForBean for current bean matching enhancer createProxy create proxy for the bean

The following a getAdvicesAndAdvisorsForBean core logic. Find all enhancers, that is, all @aspect annotated beans B. Find the matched enhancer, that is, match the current bean according to the expression on the @before, @after annotations, and expose the matched bean. C. Expand and sort matched enhancers by the value of the @Order or PriorityOrdered getOrder, the smaller the value, the more advanced it is.

CreateProxy can be created using JDK proxy or CGLIB A. If proxyTargetClass=true is set, it must be CGLIB agent B. If proxyTargetClass=false, the target object implements the interface, go to JDK proxy C. If no interface is implemented, use the CGLIB proxy

! [](https://upload-images.jianshu.io/upload_images/24533109-128926e6885b333e.jpg?imageMogr2/auto-orient/strip|imageView2/ 2/w/860/format/webp)