SpringAOP作為Spring最核心的能力之一,其重要性不言而喻。然後需要知道的是AOP並不只是Spring特有的功能,而是一種思想,一種通用的功能。而SpringAOP只是在AOP的基礎上將能力整合到SpringIOC中,使其作為bean的一種,從而我們能夠很方便的進行使用。
當我們在日常業務開發中,例如有些功能模組是通用的(紀錄檔、許可權等),或者我們需要在某些功能前後去做一些增強,例如在某些方法執行後傳送一條mq訊息等。
如果我們將這些通用模組程式碼與業務程式碼放在一塊,那麼每個業務程式碼都要寫這些通用模組,維護成本與耦合情況都十分嚴重。
因此,我們可以將此模組抽象出來,就有了」切面「的概念。
AOP的使用方式相對比較簡單,首先我們需要完成業務程式碼
@Service
public class AopDemo implements AopInterface{
public Student start(String name) {
System.out.println("執行業務邏輯程式碼.....");
return new Student(name);
}
}
業務邏輯比較簡單,接收一個name引數。
接下來我們需要建立其對應的切面
//將該切面加入spring容器
@Service
//宣告該類為一個切面
@Aspect
class AopAspect {
//宣告要進行代理的方法
@Pointcut("execution(* com.example.demo.aop.AopInterface.start(..))")
public void startAspect() {
}
//在方法執行之前的邏輯
@Before(value = "startAspect()")
public void beforeAspect() {
System.out.println("業務邏輯前程式碼.....");
}
//在方法執行之後的邏輯
@After(value = "startAspect()")
public void afterAspect() {
System.out.println("業務邏輯後程式碼.....");
}
//圍繞方法前後的邏輯
@Around("startAspect()")
public Object aroundAspect(ProceedingJoinPoint point) throws Throwable {
Object[] requestParams = point.getArgs();
String name = requestParams[0].toString();
System.out.println("傳入引數:" + name);
requestParams[0] = "bob";
return point.proceed(requestParams);
}
}
可以看到,首先需要我們指明要代理的物件及方法,然後根據需要選擇不同的註解即可實現代理物件。
傳入引數:tom
業務邏輯前程式碼.....
執行業務邏輯程式碼.....
業務邏輯後程式碼.....
根據上面的使用情況,我們知道只需要宣告對應的註解即可,不需要其他額外的設定,然後我們獲得的bean物件就已經是被代理的了,那麼我們可以推斷代理物件的過程一定是發生在bean建立的過程的。
我們回顧一下建立bean的流程
只有第三步初始化bean的時候才會有機會進行代理。
找到對應的程式碼位置:
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//前置處理器
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
//...
try {
//物件的初始化方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
if (mbd == null || !mbd.isSynthetic()) {
//後置處理器,AOP開始的地方
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
後置處理器會執行那些實現了後置處理器介面的程式碼:
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
//獲取所有的後置處理器
for (BeanPostProcessor processor : getBeanPostProcessors()) {
//實現其要執行的方法
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
而AOP的後置處理器就是其中的一個: AbstractAutoProxyCreator
其對應的方法為(以下程式碼不為同一個類,而是對應的執行順序):
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;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// Create proxy if we have advice.
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;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
protected Object createProxy(Class beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
//獲取advisors
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// Use original ClassLoader if bean class not locally loaded in overriding class loader
ClassLoader classLoader = getProxyClassLoader();
if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
}
//通過代理工廠建立代理物件
return proxyFactory.getProxy(classLoader);
}
public Object getProxy(@Nullable ClassLoader classLoader) {
//首先獲取對應的代理
return createAopProxy().getProxy(classLoader);
}
//該方法根據要被代理的類選擇使用jdk代理還是cglib代理
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (!NativeDetector.inNativeImage() &&
(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
Class targetClass = config.getTargetClass();
//如果被代理的類是一個介面則使用jdk代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
//否則使用cglib代理
return new ObjenesisCglibAopProxy(config);
}
else {
//根據設定選擇強制使用jdk代理
return new JdkDynamicAopProxy(config);
}
}
我們知道,代理方式有jdk動態代理與cglib動態代理兩種方式,而我們一個bean使用那種代理方式則由上述的方法決定。
至此,我們已經確定了使用那種代理方式獲取代理物件。
從上文中,我們已經確定了選用何種方式構建代理物件。接下來就是通過不同的方式是如何獲取代理物件的。
看懂本章需要實現瞭解jdk動態代理或者cglib動態代理的方式。
首先在獲取代理物件時選擇 JdkDynamicAopProxy
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
//這裡通過反射建立代理物件
return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
}
當被代理物件執行被代理的方法時,會進入到此方法。(jdk動態代理的概念)
JDK通過反射建立物件,效率上來說相對低一些。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
// 獲取被代理物件的所有切入點
List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// 如果呼叫鏈路為空說明沒有需要執行的切入點,直接執行對應的方法即可
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 如果有切入點的話則按照切入點順序開始執行
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}
return retVal;
}
}
invocation.proceed();這個方法就是通過遞迴的方式執行所有的呼叫鏈路。
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// 繼續執行
return proceed();
}
}
else {
// 如果呼叫鏈路還持續的話,下一個方法仍會呼叫proceed()
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
public Object getProxy(@Nullable ClassLoader classLoader) {
try {
//設定CGLIB Enhancer...
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
//1.獲取回撥函數,對於代理類上所有方法的呼叫,都會呼叫CallBack,而Callback則需要實現intercept()方法
Callback[] callbacks = getCallbacks(rootClass);
Class[] types = new Class[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
//2.建立代理物件
return createProxyClassAndInstance(enhancer, callbacks);
}
catch (CodeGenerationException | IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
": Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (Throwable ex) {
// TargetSource.getTarget() failed
throw new AopConfigException("Unexpected AOP exception", ex);
}
}
可以看到我們在建立代理物件前會先獲取代理物件的所有回撥函數:
首先可以看到我們一共有7個回撥方法,其中第一個為AOP相關的方法,其他的為spring相關。
在第一個對調物件中持有的 advised 物件中有 advisors 屬性,就是對應我們的代理類中四個切片,@Before等等。
然後我們看一下 createProxyClassAndInstance()都做了什麼。
//CglibAopProxy類的建立代理物件方法
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
enhancer.setInterceptDuringConstruction(false);
enhancer.setCallbacks(callbacks);
return (this.constructorArgs != null && this.constructorArgTypes != null ?
enhancer.create(this.constructorArgTypes, this.constructorArgs) :
enhancer.create());
}
//ObjenesisCglibAopProxy繼承了CglibAopProxy類,並覆寫了其方法
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
Class proxyClass = enhancer.createClass();
Object proxyInstance = null;
//1.嘗試使用objenesis建立物件
if (objenesis.isWorthTrying()) {
try {
proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache());
}
catch (Throwable ex) {
logger.debug("Unable to instantiate proxy using Objenesis, " +
"falling back to regular proxy construction", ex);
}
}
//2.根據commit的提交記錄發現,objenesis有可能建立物件失敗,如果失敗的話則選用放射的方式建立物件
if (proxyInstance == null) {
// Regular instantiation via default constructor...
try {
Constructor ctor = (this.constructorArgs != null ?
proxyClass.getDeclaredConstructor(this.constructorArgTypes) :
proxyClass.getDeclaredConstructor());
ReflectionUtils.makeAccessible(ctor);
proxyInstance = (this.constructorArgs != null ?
ctor.newInstance(this.constructorArgs) : ctor.newInstance());
}
catch (Throwable ex) {
throw new AopConfigException("Unable to instantiate proxy using Objenesis, " +
"and regular proxy instantiation via default constructor fails as well", ex);
}
}
//
((Factory) proxyInstance).setCallbacks(callbacks);
return proxyInstance;
}
此處有個遇到的問題,當我在debug的時候,發現怎麼都進不去 createProxyClassAndInstance(),百思不得其解,然後看到IDEA旁邊有一個向下的箭頭,代表該方法可能其子類被覆寫了。然後在其子類處打斷點果然發現是其子類的實現。
此處在2.2中也可看到:
可以看到返回的是其子類的物件,而不是CglibAopProxy本身的物件。
作者:京東科技 韓國凱
來源:京東雲開發者社群