because Spring The code logic in the aspect is dynamically changed during the run time “ Weave in ” Inside container object method , Allows developers to add code snippets before and after container object methods without perception , therefore AOP It's actually an agent model . All agents , Because the code is not directly readable , yes
bug Hardest hit areas .

<> case

A game system , Including classes responsible for counting and recharging coupons CouponService, It contains a recharge method deposit():

deposit() Will use wechat to pay for recharge . So in this method , join pay().

As wechat payment is a third-party interface , Interface call time shall be recorded .
introduce @Around enhance , Separately recorded in pay() Time before and after method execution , And calculate pay() Execution time .

Controller:

Access interface , You will find that the section of this calculation time has not been executed , The output log is as follows :

The facet class clearly defines the facet correspondence method , But it didn't work . The description is inside the class , adopt this Method called , Will not be AOP enhance .

<> analysis

* this The corresponding object is an ordinary object CouponService object :

* And in Controller Automatic assembly in layers CouponService object :


It's a quilt Spring Enhanced Bean, So execute deposit() Time , The enhanced operation of recording the interface call time will be performed . and this The corresponding object is just an ordinary object , There are no additional enhancements .
Why? this The referenced object is just an ordinary object ?
Want from Spring AOP In the process of enhancing objects .

<> realization

AOP The bottom layer of is dynamic agent , There are two ways to create a proxy :

* JDK mode
A proxy can only be generated for a class that implements an interface , Cannot be for normal classes
* CGLIB mode
You can implement proxies for classes , It mainly generates a subclass for the specified class , Method of overwriting , To implement the proxy object .

For non Spring Boot program , In addition to adding related AOP Out of dependency , Also use @EnableAspectJAutoProxy open AOP function .

This annotation class introduces AspectJAutoProxyRegistrar, It is realized by ImportBeanDefinitionRegistrar Interface complete AOP relevant Bean preparation .

Now let's look at the process of creating a proxy object . Let's first look at the call stack :

* When to create a proxy object
Create a Bean Time
The key work created by AnnotationAwareAspectJAutoProxyCreator complete

<>AnnotationAwareAspectJAutoProxyCreator

one kind BeanPostProcessor. So its execution is to complete the original Bean Post build initialization Bean(initializeBean) In the process

<>AbstractAutoProxyCreator#postProcessAfterInitialization
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; }
Key methods wrapIfNecessary: When needed AOP Time , It will create the original Bean object wrap Become a proxy object , As Bean return .

<>AbstractAutoProxyCreator#wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey)
{ // Omit non critical code 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, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } // Omit non critical code }
<>createProxy

Key to creating proxy objects :
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) { // ... //
1. Create an agent factory ProxyFactory proxyFactory = new ProxyFactory(); if (!proxyFactory.
isProxyTargetClass()) { if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true); } else { evaluateProxyInterfaces(
beanClass, proxyFactory); } } Advisor[] advisors = buildAdvisors(beanName,
specificInterceptors); // 2. Send Notifier (advisors), The proxy object and other information are added to the agent factory proxyFactory.
addAdvisors(advisors); proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory); // ... // 3. Get proxy object through proxy factory return
proxyFactory.getProxy(getProxyClassLoader()); }

After such a process , A proxy object is created . We from Spring All the objects obtained in are the proxy object , So have AOP function . And used directly before this The reference is only an ordinary object , Naturally, there is no way to achieve it AOP The function of .

<> correct

Only objects created by dynamic proxies are referenced , Will be Spring enhance , have AOP What should be .
What kind of object has such conditions ?

<> cover @Autowired annotation

adopt @Autowired, Inside the class , Quote yourself :

<> Directly from AopContext Get current Proxy

AopContext, Is through a ThreadLocal Lai Jiang Proxy Bind to thread , In this way, you can take out the data bound by the current thread at any time Proxy.

There are two prerequisites for using this scheme , Need in @EnableAspectJAutoProxy Add configuration item exposeProxy = true
, Represents putting a proxy object into ThreadLocal, This can be passed directly
AopContext.currentProxy()
Get , Otherwise, an error is reported :

So modify the code :

Don't forget to modify EnableAspectJAutoProxy of exposeProxy attribute :

Technology