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 .


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


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

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 .

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 }

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
Get , Otherwise, an error is reported :

So modify the code :

Don't forget to modify EnableAspectJAutoProxy of exposeProxy attribute :