Service調(diào)用其他Service的private方法, @Transactional會生效嗎
作者:zzzzbw
來源:SegmentFault 思否社區(qū)
省流大師:
一個Service調(diào)用其他Service的private方法, @Transactional會生效嗎 正常流程不能生效 經(jīng)過一番操作, 達到理論上可以
疑問
驗證
@Slf4j
@Aspect
@Component
public?class?TransactionalAop?{
????@Around("@within(org.springframework.transaction.annotation.Transactional)")
????public?Object?recordLog(ProceedingJoinPoint?p)?throws?Throwable?{
????????log.info("Transaction?start!");
????????Object?result;
????????try?{
????????????result?=?p.proceed();
????????}?catch?(Exception?e)?{
????????????log.info("Transaction?rollback!");
????????????throw?new?Throwable(e);
????????}
????????log.info("Transaction?commit!");
????????return?result;
????}
}
public?interface?HelloService?{
????void?hello(String?name);
}
@Slf4j
@Transactional
@Service
public?class?HelloServiceImpl?implements?HelloService?{
????@Override
????public?void?hello(String?name)?{
????????log.info("hello?{}!",?name);
????}
????private?long?privateHello(Integer?time)?{
????????log.info("private?hello!?time:?{}",?time);
????????return?System.currentTimeMillis();
????}
}
@Slf4j
@SpringBootTest
public?class?HelloTests?{
????@Autowired
????private?HelloService?helloService;
????@Test
????public?void?helloService()?throws?NoSuchMethodException,?InvocationTargetException,?IllegalAccessException?{
????????helloService.hello("hello");
????????Method?privateHello?=?helloService.getClass().getDeclaredMethod("privateHello",?Integer.class);
????????privateHello.setAccessible(true);
????????Object?invoke?=?privateHello.invoke(helloService,?10);
????????log.info("privateHello?result:?{}",?invoke);
????}
}

Spring Boot代理生成流程
public?class?DefaultAopProxyFactory?implements?AopProxyFactory,?Serializable?{
????@Override
????public?AopProxy?createAopProxy(AdvisedSupport?config)?throws?AopConfigException?{
????????if?(config.isOptimize()?||?config.isProxyTargetClass()?||?hasNoUserSuppliedProxyInterfaces(config))?{
????????????Class>?targetClass?=?config.getTargetClass();
????????????if?(targetClass?==?null)?{
????????????????throw?new?AopConfigException("TargetSource?cannot?determine?target?class:?"?+
????????????????????????"Either?an?interface?or?a?target?is?required?for?proxy?creation.");
????????????}
????????????//?被代理類有接口,?使用JDK代理
????????????if?(targetClass.isInterface()?||?Proxy.isProxyClass(targetClass))?{
????????????????return?new?JdkDynamicAopProxy(config);
????????????}
????????????//?被代理類沒有實現(xiàn)接口,?使用Cglib代理
????????????return?new?ObjenesisCglibAopProxy(config);
????????}
????????else?{
????????????//?默認JDK代理
????????????return?new?JdkDynamicAopProxy(config);
????????}
????}
}
則用JDK代理(JdkDynamicAopProxy), 否則用CGlib代理(ObjenesisCglibAopProxy).
假如想要強制使用JDK代理模式, 可以設(shè)置配置spring.aop.proxy-target-class=false
final?class?JdkDynamicAopProxy?implements?AopProxy,?InvocationHandler,?Serializable?{
????@Override
????public?Object?getProxy(@Nullable?ClassLoader?classLoader)?{
????????if?(logger.isTraceEnabled())?{
????????????logger.trace("Creating?JDK?dynamic?proxy:?"?+?this.advised.getTargetSource());
????????}
????????Class>[]?proxiedInterfaces?=?AopProxyUtils.completeProxiedInterfaces(this.advised,?true);
????????findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
????????return?Proxy.newProxyInstance(classLoader,?proxiedInterfaces,?this);
????}
}
JDK代理類生成流程
public?class?Proxy?implements?java.io.Serializable?{
????public?static?Object?newProxyInstance(ClassLoader?loader,
??????????????????????????????????????????Class>[]?interfaces,
??????????????????????????????????????????InvocationHandler?h)
????????throws?IllegalArgumentException
????{
????????/*
?????????*?1.?各種校驗
?????????*/
????????Objects.requireNonNull(h);
????????final?Class>[]?intfs?=?interfaces.clone();
????????final?SecurityManager?sm?=?System.getSecurityManager();
????????if?(sm?!=?null)?{
????????????checkProxyAccess(Reflection.getCallerClass(),?loader,?intfs);
????????}
????????/*
?????????*?2.?獲取生成的代理類Class
?????????*/
????????Class>?cl?=?getProxyClass0(loader,?intfs);
????????/*
?????????*?3.?反射獲取構(gòu)造方法生成代理對象實例
?????????*/
????????try?{
????????????if?(sm?!=?null)?{
????????????????checkNewProxyPermission(Reflection.getCallerClass(),?cl);
????????????}
????????????final?Constructor>?cons?=?cl.getConstructor(constructorParams);
????????????final?InvocationHandler?ih?=?h;
????????????if?(!Modifier.isPublic(cl.getModifiers()))?{
????????????????AccessController.doPrivileged(new?PrivilegedAction()?{
????????????????????public?Void?run()?{
????????????????????????cons.setAccessible(true);
????????????????????????return?null;
????????????????????}
????????????????});
????????????}
????????????return?cons.newInstance(new?Object[]{h});
????????}?catch?...
????}
}
private?static?Class>?getProxyClass0(ClassLoader?loader,
???????????????????????????????????????Class>...?interfaces)?{
????if?(interfaces.length?>?65535)?{
????????throw?new?IllegalArgumentException("interface?limit?exceeded");
????}
????/*
?????*?如果代理類已經(jīng)生成則直接返回,?否則通過ProxyClassFactory創(chuàng)建新的代理類
?????*/
????return?proxyClassCache.get(loader,?interfaces);
}
不過我們只要知道, 這個緩存在get時如果存在值, 則返回這個值, 如果不存在, 則調(diào)用ProxyClassFactory的apply()方法.
public?Class>?apply(ClassLoader?loader,?Class>[]?interfaces)?{
????...
????//?上面是很多校驗,?這里先不看
????/*
?????*?為新生成的代理類起名:proxyPkg(包名)?+ proxyClassNamePrefix(固定字符串"$Proxy")?+?num(當前代理類生成量)
?????*/
????long?num?=?nextUniqueNumber.getAndIncrement();
????String?proxyName?=?proxyPkg?+?proxyClassNamePrefix?+?num;
????/*
?????*?生成定義的代理類的字節(jié)碼?byte數(shù)據(jù)
?????*/
????byte[]?proxyClassFile?=?ProxyGenerator.generateProxyClass(
????????proxyName,?interfaces,?accessFlags);
????try?{
????????/*
?????????*?把生成的字節(jié)碼數(shù)據(jù)加載到JVM中,?返回對應(yīng)的Class
?????????*/
????????return?defineClass0(loader,?proxyName,
????????????????????????????proxyClassFile,?0,?proxyClassFile.length);
????}?catch?...
}
代理類字節(jié)碼生成流程
public?static?byte[]?generateProxyClass(final?String?name,
???????????????????????????????????????Class[]?interfaces)
{
???ProxyGenerator?gen?=?new?ProxyGenerator(name,?interfaces);
???//?實際生成字節(jié)碼
???final?byte[]?classFile?=?gen.generateClassFile();
????
????//?訪問權(quán)限操作,?這里省略
????...
???return?classFile;
}
private?byte[]?generateClassFile()?{
???/*?============================================================
????*?步驟一:?添加所有需要代理的方法
????*/
???//?添加equal、hashcode、toString方法
???addProxyMethod(hashCodeMethod,?Object.class);
???addProxyMethod(equalsMethod,?Object.class);
???addProxyMethod(toStringMethod,?Object.class);
???//?添加目標代理類的所有接口中的所有方法
???for?(int?i?=?0;?i????????Method[]?methods?=?interfaces[i].getMethods();
???????for?(int?j?=?0;?j????????????addProxyMethod(methods[j],?interfaces[i]);
???????}
???}
???//?校驗是否有重復(fù)的方法
???for?(List?sigmethods?:?proxyMethods.values())?{
???????checkReturnTypes(sigmethods);
???}
???/*?============================================================
????*?步驟二:組裝需要生成的代理類字段信息(FieldInfo)和方法信息(MethodInfo)
????*/
???try?{
???????//?添加構(gòu)造方法
???????methods.add(generateConstructor());
???????for?(List?sigmethods?:?proxyMethods.values())?{
???????????for?(ProxyMethod?pm?:?sigmethods)?{
???????????????//?由于代理類內(nèi)部會用反射調(diào)用目標類實例的方法,?必須有反射依賴,?所以這里固定引入Method方法
???????????????fields.add(new?FieldInfo(pm.methodFieldName,
???????????????????"Ljava/lang/reflect/Method;",
????????????????????ACC_PRIVATE?|?ACC_STATIC));
???????????????//?添加代理方法的信息
???????????????methods.add(pm.generateMethod());
???????????}
???????}
???????methods.add(generateStaticInitializer());
???}?catch?(IOException?e)?{
???????throw?new?InternalError("unexpected?I/O?Exception");
???}
???if?(methods.size()?>?65535)?{
???????throw?new?IllegalArgumentException("method?limit?exceeded");
???}
???if?(fields.size()?>?65535)?{
???????throw?new?IllegalArgumentException("field?limit?exceeded");
???}
???/*?============================================================
????*?步驟三:?輸出最終要生成的class文件
????*/
????//?這部分就是根據(jù)上面組裝的信息編寫字節(jié)碼
????...
???return?bout.toByteArray();
}
組裝需要生成的代理類的字段信息和方法信息. 這里會根據(jù)步驟一添加的方法, 生成實際的代理類的方法的實現(xiàn). 比如:
如果目標代理類實現(xiàn)了一個HelloService接口, 且實現(xiàn)其中的方法hello, 那么生成的代理類就會生成如下形式方法:
public?Object?hello(Object...?args){
????try{
????????return?(InvocationHandler)h.invoke(this,?this.getMethod("hello"),?args);
????}?catch?...??
}把上面添加和組裝的信息通過流拼接出最終的java class字節(jié)碼數(shù)據(jù)
不過想一下也知道, 私有方法在正常情況下外部也無法調(diào)用, 即使代理了也沒法使用, 所以也沒必要去代理.**
結(jié)論
重新實現(xiàn)一個ProxyGenerator.generateClassFile()方法, 輸出帶有private方法的代理類字節(jié)碼數(shù)據(jù) 把字節(jié)碼數(shù)據(jù)加載到JVM中, 生成Class 替代Spring Boot中默認的動態(tài)代理功能, 換成我們自己的動態(tài)代理.
前情提要: 在Service調(diào)用其他Service的private方法, @Transactional會生效嗎(上)中證明了動態(tài)代理不會代理private方法的, 并通過閱讀源碼證實了. 但是我們可以自己實現(xiàn)一個動態(tài)代理功能替代Spring Boot中原有的, 達到動態(tài)代理private方法的目的. 主要流程為:
重新實現(xiàn)一個ProxyGenerator.generateClassFile()方法, 輸出帶有private方法的代理類字節(jié)碼數(shù)據(jù) 把字節(jié)碼數(shù)據(jù)加載到JVM中, 生成Class 替代Spring Boot中默認的動態(tài)代理功能, 換成我們自己的動態(tài)代理.
前置代碼
@Getter
public?abstract?class?PrivateProxyInvocationHandler?implements?InvocationHandler?{
????private?final?Object?subject;
????public?PrivateProxyInvocationHandler(Object?subject)?{
????????this.subject?=?subject;
????}
}
為了簡便實現(xiàn), 就不實現(xiàn)掃描解析的功能了, 這里直接模仿前文的TransactionalAop的功能實現(xiàn)切面TransactionalHandler.
@Slf4j
public?class?TransactionalHandler?extends?PrivateProxyInvocationHandler?{
????public?TransactionalHandler(Object?subject)?{
????????super(subject);
????}
????@Override
????public?Object?invoke(Object?proxy,?Method?method,?Object[]?args)?throws?Throwable?{
????????log.info("Transaction?start!");
????????Object?result;
????????try?{
????????????result?=?method.invoke(getSubject(),?args);
????????}?catch?(Exception?e)?{
????????????log.info("Transaction?rollback!");
????????????throw?new?Throwable(e);
????????}
????????log.info("Transaction?commit!");
????????return?result;
????}
}
生成字節(jié)碼數(shù)據(jù)
public?class?PrivateProxyGenerator?{
????...
????private?String?generateClassSrc()?{
????????//?1.?添加equal、hashcode、toString方法
????????//?這里省略
????????//?2.?添加interface中的方法
????????for?(Class>?interfaceClz?:?interfaces)?{
????????????//?TODO?這里就不考慮多個interfaces含有相同method的情況了
????????????Method[]?methods?=?interfaceClz.getMethods();
????????????this.proxyMethods.put(interfaceClz,?Arrays.asList(methods));
????????}
????????//?3.?添加代理類中的私有方法
????????//?TODO?這是新增的
????????Object?subject?=?h.getSubject();
????????Method[]?declaredMethods?=?subject.getClass().getDeclaredMethods();
????????List?privateMethods?=?Arrays.stream(declaredMethods)
????????????????.filter(method?->?method.getModifiers()?==?Modifier.PRIVATE)
????????????????.collect(Collectors.toList());
????????this.privateMethods.addAll(privateMethods);
????????//?4.?校驗方法的簽名等@see?sun.misc.ProxyGenerator.checkReturnTypes
????????//?這里省略
????????//?5.?添加類里的字段信息和方法數(shù)據(jù)
????????//?如靜態(tài)方法、構(gòu)造方法、字段等
????????//?TODO?這里省略,?在編寫java字符串(步驟7)時直接寫入
????????//?6.?校驗一下方法長度、字段長度等
????????//?這里省略
????????//?7.?把剛才添加的數(shù)據(jù)真正寫到class文件里
????????//?TODO?這里我們根據(jù)邏輯寫成java字符串
????????return?writeJavaSrc();
????}
????...
}
private?String?writeJavaSrc()?{
????StringBuffer?sb?=?new?StringBuffer();
????int?packageIndex?=?this.className.lastIndexOf(".");
????String?packageName?=?this.className.substring(0,?packageIndex);
????String?clzName?=?this.className.substring(packageIndex?+?1);
????//?package信息
????sb.append("package").append(SPACE).append(packageName).append(SEMICOLON).append(WRAP);
????//?class?信息,?interface接口
????sb.append(PUBLIC).append(SPACE).append("class").append(SPACE).append(clzName).append(SPACE);
????sb.append("implements").append(SPACE);
????String?interfaceNameList?=?Arrays.stream(this.interfaces).map(Class::getTypeName).collect(Collectors.joining(","));
????sb.append(interfaceNameList);
????sb.append(SPACE).append("{").append(WRAP);
????//?必須要的屬性和構(gòu)造函數(shù)
????/**
?????*?private?PrivateProxyInvocationHandler?h;
?????*/
????sb.append(PRIVATE).append(SPACE).append(PrivateProxyInvocationHandler.class.getName()).append(SPACE).append("h;").append(WRAP);
????/**
?????*??public?$Proxy0(PrivateProxyInvocationHandler?h)?{
?????*??????this.h?=?h;
?????*?}
?????*/
????sb.append(PUBLIC).append(SPACE).append(clzName).append("(")
????????????.append(PrivateProxyInvocationHandler.class.getName()).append(SPACE).append("h").append("){").append(WRAP)
????????????.append("this.h?=?h;").append(WRAP)
????????????.append("}");
????//?代理public方法
????this.proxyMethods.forEach((interfaceClz,?methods)?->?{
????????for?(Method?proxyMethod?:?methods)?{
????????????writeProxyMethod(sb,?interfaceClz,?proxyMethod,?PUBLIC);
????????}
????});
????//?代理private方法
????for?(Method?proxyMethod?:?this.privateMethods)?{
????????writeProxyMethod(sb,?null,?proxyMethod,?PRIVATE);
????}
????sb.append("}");
????return?sb.toString();
}
/**
?*?編寫代理方法數(shù)據(jù)
?*/
private?void?writeProxyMethod(StringBuffer?sb,?Class>?interfaceClz,?Method?proxyMethod,?String?accessFlag)?{
????//?1.?編寫方法的聲明,?例:
????//?public?void?hello(java.lang.String?var0)
????sb.append(accessFlag)
????????????.append(SPACE)
????????????//?返回類
????????????.append(proxyMethod.getReturnType().getTypeName()).append(SPACE)
????????????.append(proxyMethod.getName()).append("(");
????//?參數(shù)類
????Class>[]?parameterTypes?=?proxyMethod.getParameterTypes();
????//?參數(shù)類名
????List?argClassNames?=?new?ArrayList<>();
????//?參數(shù)名
????List?args?=?new?ArrayList<>();
????for?(int?i?=?0;?i?????????Class>?parameterType?=?parameterTypes[i];
????????argClassNames.add(parameterType.getTypeName());
????????args.add("var"?+?i);
????}
????//?寫入?yún)?shù)的聲明
????for?(int?i?=?0;?i?????????sb.append(argClassNames.get(i)).append(SPACE).append(args.get(i)).append(",");
????}
????if?(parameterTypes.length?>?0)?{
????????//去掉最后一個逗號
????????sb.replace(sb.length()?-?1,?sb.length(),?"");
????}
????sb.append(")").append("{").append(WRAP);
????//?如果是public方法,?則編寫的代理方法邏輯大致如下
????/**
?????*?try?{
?????*??Method?m?=?HelloService.class.getMethod("hello",?String.class,?Integer.class);
?????*??return?this.h.invoke(this,?proxyMethod,?new?Object[]{var0,?var1...});
?????*?}?catch?(Throwable?e)?{
?????*??throw?new?RuntimeException(e);
?????*?}
?????*/
????//?如果是private方法,?則編寫的代理方法邏輯大致如下
????/**
?????*?try?{
?????*??Method?m?=?h.getSubject().getClass().getDeclaredMethod("hello",?String.class,?Integer.class);
?????*??m.setAccessible(true);
?????*??return?this.h.invoke(this,?proxyMethod,?new?Object[]{var0,?var1...});
?????*?}?catch?(Throwable?e)?{
?????*??throw?new?RuntimeException(e);
?????*?}
?????*/
????//?2.?try
????sb.append("try{").append(WRAP);
????//?3.?編寫獲取目標代理方法的功能
????sb.append(Method.class.getTypeName()).append(SPACE).append("m?=?");
????if?(PUBLIC.equals(accessFlag))?{
????????//?3.1?public方法的代理,?通過接口獲取實例方法.?例:
????????//?java.lang.reflect.Method?m?=?HelloService.class.getMethod("hello",?String.class,?Integer.class);
????????sb.append(interfaceClz.getTypeName()).append(".class")
????????????????.append(".getMethod(").append("\"").append(proxyMethod.getName()).append("\"").append(",").append(SPACE);
????}?else?{
????????//?3.2?private方法的代理,?通過目標代理類實例獲取方法.?例:
????????//?java.lang.reflect.Method?m?=?h.getSubject().getClass().getDeclaredMethod("hello",?String.class,?Integer.class);
????????sb.append("h.getSubject().getClass().getDeclaredMethod(").append("\"").append(proxyMethod.getName()).append("\"").append(",").append(SPACE);
????}
????argClassNames.forEach(name?->?sb.append(name).append(".class").append(","));
????if?(parameterTypes.length?>?0)?{
????????//去掉最后一個逗號
????????sb.replace(sb.length()?-?1,?sb.length(),?"");
????}
????sb.append(");").append(WRAP);
????if?(!PUBLIC.equals(accessFlag))?{
????????//?3.3?不是public方法,?設(shè)置訪問權(quán)限
????????sb.append("m.setAccessible(true);").append(WRAP);
????}
????//?4.?InvocationHandler中調(diào)用代理方法邏輯,?例:
????//?return?this.h.invoke(this,?m,?new?Object[]{var0});
????if?(!proxyMethod.getReturnType().equals(Void.class)?&&?!proxyMethod.getReturnType().equals(void.class))?{
????????//?有返回值則返回且強轉(zhuǎn)
????????sb.append("return").append(SPACE).append("(").append(proxyMethod.getReturnType().getName()).append(")");
????}
????String?argsList?=?String.join(",",?args);
????sb.append("this.h.invoke(this,?m,?new?Object[]{").append(argsList).append("});");
????//?5.?catch
????sb.append("}?catch?(Throwable?e)?{").append(WRAP);
????sb.append("throw?new?RuntimeException(e);").append(WRAP);
????sb.append("}");
????sb.append("}").append(WRAP);
}
package?cn.zzzzbw.primary.proxy.reflect;
public?class?$Proxy0?implements?cn.zzzzbw.primary.proxy.service.HelloService?{
????private?cn.zzzzbw.primary.proxy.reflect.PrivateProxyInvocationHandler?h;
????public?$Proxy0(cn.zzzzbw.primary.proxy.reflect.PrivateProxyInvocationHandler?h)?{
????????this.h?=?h;
????}
}
//?代理的public方法
public?void?hello(java.lang.String?var0)?{
????try?{
????????java.lang.reflect.Method?m?=?cn.zzzzbw.primary.proxy.service.HelloService.class.getMethod("hello",?java.lang.String.class);
????????this.h.invoke(this,?m,?new?Object[]{var0});
????}?catch?(Throwable?e)?{
????????throw?new?RuntimeException(e);
????}
}
//?代理的private方法
private?long?primaryHello(java.lang.Integer?var0)?{
????try?{
????????java.lang.reflect.Method?m?=?h.getSubject().getClass().getDeclaredMethod("privateHello",?java.lang.Integer.class);
????????m.setAccessible(true);
????????return?(long)?this.h.invoke(this,?m,?new?Object[]{var0});
????}?catch?(Throwable?e)?{
????????throw?new?RuntimeException(e);
????}
}
@Slf4j
public?class?PrivateProxyGeneratorTests?{
????public?static?void?main(String[]?args)?throws?IOException?{
????????//?1?生成java源碼
????????String?packageName?=?"cn.zzzzbw.primary.proxy.reflect";
????????String?clazzName?=?"$Proxy0";
????????String?proxyName?=?packageName?+?"."?+?clazzName;
????????Class>[]?interfaces?=?HelloServiceImpl.class.getInterfaces();
????????PrivateProxyInvocationHandler?h?=?new?TransactionalHandler(new?HelloServiceImpl());
????????String?src?=?PrivateProxyGenerator.generateProxyClass(proxyName,?interfaces,?h);
????????//?2?保存成java文件
????????String?filePath?=?PrivateProxy.class.getResource("/").getPath();
????????String?clzFilePath?=?filePath?+?packageName.replace(".",?"/")?+?"/"?+?clazzName?+?".java";
????????log.info("clzFilePath:?{}",?clzFilePath);
????????File?f?=?new?File(clzFilePath);
????????if?(!f.getParentFile().exists())?{
????????????f.getParentFile().mkdirs();
????????}
????????try?(FileWriter?fw?=?new?FileWriter(f))?{
????????????fw.write(src);
????????????fw.flush();
????????}
????}
}
package?cn.zzzzbw.primary.proxy.reflect;
public?class?$Proxy0?implements?cn.zzzzbw.primary.proxy.service.HelloService?{
????private?cn.zzzzbw.primary.proxy.reflect.PrivateProxyInvocationHandler?h;
????public?$Proxy0(cn.zzzzbw.primary.proxy.reflect.PrivateProxyInvocationHandler?h)?{
????????this.h?=?h;
????}
????public?void?hello(java.lang.String?var0)?{
????????try?{
????????????java.lang.reflect.Method?m?=?cn.zzzzbw.primary.proxy.service.HelloService.class.getMethod("hello",?java.lang.String.class);
????????????this.h.invoke(this,?m,?new?Object[]{var0});
????????}?catch?(Throwable?e)?{
????????????throw?new?RuntimeException(e);
????????}
????}
????private?long?privateHello(java.lang.Integer?var0)?{
????????try?{
????????????java.lang.reflect.Method?m?=?h.getSubject().getClass().getDeclaredMethod("privateHello",?java.lang.Integer.class);
????????????m.setAccessible(true);
????????????return?(long)?this.h.invoke(this,?m,?new?Object[]{var0});
????????}?catch?(Throwable?e)?{
????????????throw?new?RuntimeException(e);
????????}
????}
}
其所有public和private方法都被$Proxy0重新實現(xiàn)了一遍, 通過PrivateProxyInvocationHandler.invoke()來調(diào)用代理后的方法邏輯.
加載到JVM, 生成動態(tài)代理類
public?class?PrivateProxy?{
????private?static?final?String?proxyClassNamePrefix?=?"$Proxy";
????private?static?final?AtomicLong?nextUniqueNumber?=?new?AtomicLong();
????public?static?Object?newProxyInstance(ClassLoader?loader,?Class>[]?interfaces,?PrivateProxyInvocationHandler?h)?{
????????try?{
????????????//?1?生成java源碼
????????????String?packageName?=?PrivateProxy.class.getPackage().getName();
????????????long?number?=?nextUniqueNumber.getAndAdd(1);
????????????String?clazzName?=?proxyClassNamePrefix?+?number;
????????????String?proxyName?=?packageName?+?"."?+?clazzName;
????????????String?src?=?PrivateProxyGenerator.generateProxyClass(proxyName,?interfaces,?h);
????????????//?2?講源碼輸出到j(luò)ava文件中
????????????String?filePath?=?PrivateProxy.class.getResource("/").getPath();
????????????String?clzFilePath?=?filePath?+?packageName.replace(".",?"/")?+?"/"?+?clazzName?+?".java";
????????????File?f?=?new?File(clzFilePath);
????????????if?(!f.getParentFile().exists())?{
????????????????f.getParentFile().mkdirs();
????????????}
????????????try?(FileWriter?fw?=?new?FileWriter(f))?{
????????????????fw.write(src);
????????????????fw.flush();
????????????}
????????????//3、將java文件編譯成class文件
????????????JavaCompiler?compiler?=?ToolProvider.getSystemJavaCompiler();
????????????StandardJavaFileManager?manage?=?compiler.getStandardFileManager(null,?null,?null);
????????????Iterable?extends?JavaFileObject>?iterable?=?manage.getJavaFileObjects(f);
????????????JavaCompiler.CompilationTask?task?=?compiler.getTask(null,?manage,?null,?null,?null,?iterable);
????????????task.call();
????????????manage.close();
????????????f.delete();
????????????//?4、將class加載進jvm
????????????Class>?proxyClass?=?loader.loadClass(proxyName);
????????????//?通過構(gòu)造方法生成代理對象
????????????Constructor>?constructor?=?proxyClass.getConstructor(PrivateProxyInvocationHandler.class);
????????????return?constructor.newInstance(h);
????????}?catch?(Exception?e)?{
????????????e.printStackTrace();
????????}
????????return?null;
????}
}
接著通過ClassLoader加載到JVM中
@Slf4j
public?class?PrivateProxyTests?{
????public?static?void?main(String[]?args)?throws?NoSuchMethodException,?InvocationTargetException,?IllegalAccessException?{
????????PrivateProxyInvocationHandler?handler?=?new?PrivateProxyInvocationHandler(new?HelloServiceImpl())?{
????????????@Override
????????????public?Object?invoke(Object?proxy,?Method?method,?Object[]?args)?throws?Throwable?{
????????????????log.info("PrivateProxyInvocationHandler!");
????????????????return?method.invoke(getSubject(),?args);
????????????}
????????};
????????Object?o?=?PrivateProxy.newProxyInstance(ClassLoader.getSystemClassLoader(),?HelloServiceImpl.class.getInterfaces(),?handler);
????????log.info("{}",?o);
????????HelloService?helloService?=?(HelloService)?o;
????????helloService.hello("hello");
????????Method?primaryHello?=?helloService.getClass().getDeclaredMethod("privateHello",?Integer.class);
????????primaryHello.setAccessible(true);
????????Object?invoke?=?primaryHello.invoke(helloService,?10);
????????log.info("privateHello?result:?{}",?invoke);
????}
}

替代Spring Boot默認動態(tài)代理
現(xiàn)在為了讓@Transactional注解能對private方法生效, 就要把自定義的動態(tài)代理方法嵌入到Spring Boot的代理流程中
AopProxy
上文也分析了JdkDynamicAopProxy.getProxy()方法是如何返回代理對象的, 這里我們就模仿來實現(xiàn)一個自己的AopProxy.
public?class?PrivateAopProxy?implements?AopProxy?{
????private?final?AdvisedSupport?advised;
????
????/**
?????*?構(gòu)造方法
?????*?
?????*?直接復(fù)制JdkDynamicAopProxy構(gòu)造方法邏輯
?????*/
????public?PrivateAopProxy(AdvisedSupport?config)?throws?AopConfigException?{
????????Assert.notNull(config,?"AdvisedSupport?must?not?be?null");
????????if?(config.getAdvisors().length?==?0?&&?config.getTargetSource()?==?AdvisedSupport.EMPTY_TARGET_SOURCE)?{
????????????throw?new?AopConfigException("No?advisors?and?no?TargetSource?specified");
????????}
????????this.advised?=?config;
????}
????@Override
????public?Object?getProxy()?{
????????return?getProxy(ClassUtils.getDefaultClassLoader());
????}
????@Override
????public?Object?getProxy(ClassLoader?classLoader)?{
????????//?獲取目標類接口
????????Class>[]?interfaces?=?this.advised.getTargetClass().getInterfaces();
????????TransactionalHandler?handler;
????????try?{
????????????//?生成切面,?這里寫死為TransactionalHandler
????????????handler?=?new?TransactionalHandler(this.advised.getTargetSource().getTarget());
????????}?catch?(Exception?e)?{
????????????throw?new?RuntimeException(e);
????????}
????????//?返回代理類對象
????????return?PrivateProxy.newProxyInstance(classLoader,?interfaces,?handler);
????}
}
本文的目的主要是代理私有方法, 不怎么關(guān)注切面, 所以就直接固定用new TransactionalHandler().
AbstractAdvisorAutoProxyCreator
這兩種AopProxy是通過DefaultAopProxyFactory.createAopProxy()根據(jù)條件生成的, 那么現(xiàn)在就要替換掉DefaultAopProxyFactory, 通過實現(xiàn)自己的AopProxyFactory來生成PrivateAopProxy.
class?PrimaryAopProxyFactory?implements?AopProxyFactory?{
????@Override
????public?AopProxy?createAopProxy(AdvisedSupport?config)?throws?AopConfigException?{
????????return?new?PrivateAopProxy(config);
????}
}
其getProxy()方法會調(diào)用ProxyCreatorSupport中的aopProxyFactory變量, 而aopProxyFactory默認就是DefaultAopProxyFactory, 相關(guān)源碼如下:
public?class?ProxyFactory?extends?ProxyCreatorSupport?{
????
????public?Object?getProxy()?{
????????return?createAopProxy().getProxy();
????}
}
public?class?ProxyCreatorSupport?extends?AdvisedSupport?{
????private?AopProxyFactory?aopProxyFactory;
????/**
?????*?Create?a?new?ProxyCreatorSupport?instance.
?????*/
????public?ProxyCreatorSupport()?{
????????this.aopProxyFactory?=?new?DefaultAopProxyFactory();
????}
????protected?final?synchronized?AopProxy?createAopProxy()?{
????????if?(!this.active)?{
????????????activate();
????????}
????????return?getAopProxyFactory().createAopProxy(this);
????}
????public?AopProxyFactory?getAopProxyFactory()?{
????????return?this.aopProxyFactory;
????}
}
protected?Object?createProxy(Class>?beanClass,?@Nullable?String?beanName,
????????@Nullable?Object[]?specificInterceptors,?TargetSource?targetSource)?{
????if?(this.beanFactory?instanceof?ConfigurableListableBeanFactory)?{
????????AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory)?this.beanFactory,?beanName,?beanClass);
????}
????//?實例化ProxyFactory
????ProxyFactory?proxyFactory?=?new?ProxyFactory();
????
????//?下面都是為proxyFactory賦值
????proxyFactory.copyFrom(this);
????if?(!proxyFactory.isProxyTargetClass())?{
????????if?(shouldProxyTargetClass(beanClass,?beanName))?{
????????????proxyFactory.setProxyTargetClass(true);
????????}
????????else?{
????????????evaluateProxyInterfaces(beanClass,?proxyFactory);
????????}
????}
????Advisor[]?advisors?=?buildAdvisors(beanName,?specificInterceptors);
????proxyFactory.addAdvisors(advisors);
????proxyFactory.setTargetSource(targetSource);
????customizeProxyFactory(proxyFactory);
????proxyFactory.setFrozen(this.freezeProxy);
????if?(advisorsPreFiltered())?{
????????proxyFactory.setPreFiltered(true);
????}
????
????//?調(diào)用Factory工廠方法返回代理類對象
????return?proxyFactory.getProxy(getProxyClassLoader());
}
所以就考慮實現(xiàn)一個類繼承AbstractAutoProxyCreator然后重寫createProxy()方法, 在自己的createProxy()方法中修改ProxyFactory.aopProxyFactory的值.

SmartInstantiationAwareBeanPostProcessor繼承InstantiationAwareBeanPostProcessor,而InstantiationAwareBeanPostProcessor繼承BeanPostProcessor.
這兩個類的主要區(qū)別為切點的不同,?BeanNameAutoProxyCreator是通過Bean名稱等配置指定切點,?AbstractAdvisorAutoProxyCreator是基于Advisor匹配機制來決定切點.
通常使用的就是AnnotationAwareAspectJAutoProxyCreator, 從名字上看就可以知道, 它會通過注解和Aspect表達式來決定切面,
如上文實現(xiàn)的TransactionalAop切面里的@Around("@within(org.springframework.transaction.annotation.Transactional)")形式就是由AnnotationAwareAspectJAutoProxyCreator處理的.
public?class?PrivateProxyAdvisorAutoProxyCreator?extends?AnnotationAwareAspectJAutoProxyCreator?{
????@Override
????protected?Object?createProxy(Class>?beanClass,?String?beanName,?Object[]?specificInterceptors,?TargetSource?targetSource)?{
????????
????????//?由于AutoProxyUtils.exposeTargetClass不是public方法,?且與本文功能無關(guān),?這里就不作改造,?直接注釋掉
????????/*
????????if?(this.beanFactory?instanceof?ConfigurableListableBeanFactory)?{
????????????AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory)?this.beanFactory,?beanName,?beanClass);
????????}
????????*/
????????ProxyFactory?proxyFactory?=?new?ProxyFactory();
????????//?設(shè)置aopProxyFactory為PrimaryAopProxyFactory
????????proxyFactory.setAopProxyFactory(new?PrimaryAopProxyFactory());
????????proxyFactory.copyFrom(this);
????????if?(!proxyFactory.isProxyTargetClass())?{
????????????if?(shouldProxyTargetClass(beanClass,?beanName))?{
????????????????proxyFactory.setProxyTargetClass(true);
????????????}?else?{
????????????????evaluateProxyInterfaces(beanClass,?proxyFactory);
????????????}
????????}
????????Advisor[]?advisors?=?buildAdvisors(beanName,?specificInterceptors);
????????proxyFactory.addAdvisors(advisors);
????????proxyFactory.setTargetSource(targetSource);
????????customizeProxyFactory(proxyFactory);
????????proxyFactory.setFrozen(isFrozen());
????????if?(advisorsPreFiltered())?{
????????????proxyFactory.setPreFiltered(true);
????????}
????????return?proxyFactory.getProxy(getProxyClassLoader());
????}
}
再加上設(shè)置ProxyFactory.aopProxyFactory為PrimaryAopProxyFactory的代碼:?proxyFactory.setAopProxyFactory(new PrimaryAopProxyFactory());就完成了PrivateProxyAdvisorAutoProxyCreator.
引入到Bean中
但是加上之后卻沒有生效, 就去看一下AnnotationAwareAspectJAutoProxyCreator, 這個類上是沒有加@Component注解的, 那么它是怎么引入到Spring Boot的?
為了查明原因, 我就查一下哪里調(diào)用了AnnotationAwareAspectJAutoProxyCreator類, 找到了一個AopConfigUtils這么一個工具類, 上文提到的幾種AbstractAdvisorAutoProxyCreator的實現(xiàn)類就是這里引入的,
且設(shè)置Bean名為"org.springframework.aop.config.internalAutoProxyCreator", 看一下相關(guān)代碼:
public?abstract?class?AopConfigUtils?{
????public?static?final?String?AUTO_PROXY_CREATOR_BEAN_NAME?=
????????????"org.springframework.aop.config.internalAutoProxyCreator";
????
????//?AbstractAdvisorAutoProxyCreator實現(xiàn)類列表
????private?static?final?List>?APC_PRIORITY_LIST?=?new?ArrayList<>(3);
????static?{
????????//?添加AbstractAdvisorAutoProxyCreator實現(xiàn)類,?優(yōu)先級有小到大,?也就是說默認為最后添加的AnnotationAwareAspectJAutoProxyCreator
????????APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
????????APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
????????APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
????}
????//?引入AspectJAwareAdvisorAutoProxyCreator
????@Nullable
????public?static?BeanDefinition?registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry?registry)?{
????????return?registerAspectJAutoProxyCreatorIfNecessary(registry,?null);
????}
????@Nullable
????public?static?BeanDefinition?registerAspectJAutoProxyCreatorIfNecessary(
????????????BeanDefinitionRegistry?registry,?@Nullable?Object?source)?{
????????return?registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class,?registry,?source);
????}
????
????/**
?????*?此方法引入AbstractAdvisorAutoProxyCreator實現(xiàn)類到Spring?Boot中
?????*/?
????@Nullable
????private?static?BeanDefinition?registerOrEscalateApcAsRequired(
????????????Class>?cls,?BeanDefinitionRegistry?registry,?@Nullable?Object?source)?{
????????Assert.notNull(registry,?"BeanDefinitionRegistry?must?not?be?null");
????????if?(registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME))?{
????????????//?如果Spring?Boot中已經(jīng)有被引入的AbstractAdvisorAutoProxyCreator實現(xiàn)類,?則比對優(yōu)先級
????????????BeanDefinition?apcDefinition?=?registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
????????????if?(!cls.getName().equals(apcDefinition.getBeanClassName()))?{
????????????????
????????????????int?currentPriority?=?findPriorityForClass(apcDefinition.getBeanClassName());
????????????????int?requiredPriority?=?findPriorityForClass(cls);
????????????????if?(currentPriority?????????????????????apcDefinition.setBeanClassName(cls.getName());
????????????????}
????????????}
????????????return?null;
????????}
????????//?引入對應(yīng)的cls到Spring?Boot的Bean管理中,?且命名為AUTO_PROXY_CREATOR_BEAN_NAME變量值
????????RootBeanDefinition?beanDefinition?=?new?RootBeanDefinition(cls);
????????beanDefinition.setSource(source);
????????beanDefinition.getPropertyValues().add("order",?Ordered.HIGHEST_PRECEDENCE);
????????beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
????????registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME,?beanDefinition);
????????return?beanDefinition;
????}
}
所以我們要給PrivateProxyAdvisorAutoProxyCreator的Bean名也指定為AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME才能覆蓋:
@Component(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME)
public?class?PrivateProxyAdvisorAutoProxyCreator?extends?AnnotationAwareAspectJAutoProxyCreator?{
????...
}
這是由于AopConfigUtils在查找AbstractAdvisorAutoProxyCreator實現(xiàn)類的優(yōu)先級的時候要求必須是在AopConfigUtils.APC_PRIORITY_LIST有的才行.
private?static?int?findPriorityForClass(@Nullable?String?className)?{
????for?(int?i?=?0;?i?????????Class>?clazz?=?APC_PRIORITY_LIST.get(i);
????????if?(clazz.getName().equals(className))?{
????????????return?i;
????????}
????}
????throw?new?IllegalArgumentException(
????????????"Class?name?["?+?className?+?"]?is?not?a?known?auto-proxy?creator?class");
}
static?{
????try?{
????????Field?apc_priority_list?=?AopConfigUtils.class.getDeclaredField("APC_PRIORITY_LIST");
????????apc_priority_list.setAccessible(true);
????????List>?o?=?(List >)?apc_priority_list.get(AopConfigUtils.class);
????????o.add(PrivateProxyAdvisorAutoProxyCreator.class);
????}?catch?(Exception?e)?{
????????e.printStackTrace();
????}
}

因為中間在模仿JdkDynamicAopProxy實現(xiàn)PrivateAopProxy的時候, 由于JdkDynamicAopProxy的切面實現(xiàn)邏輯非常復(fù)雜, 我們直接把切面寫死成了TransactionalHandler.
但是本文的主要目的就是能夠在Spring Boot代理private方法, 只要能夠代理, 說明@Transactional事務(wù)生效也是完全能做到的.
感悟
從前文Service調(diào)用其他Service的private方法, @Transactional會生效嗎(上)閱讀Spring Boot動態(tài)代理的功能源碼實現(xiàn), 到本文親手實現(xiàn)"特殊功能"的動態(tài)代理,
不僅精通了Spring Boot動態(tài)代理的代碼實現(xiàn)流程, 還掌握了JDK的動態(tài)代理功能, 收益非常大!

