Service调用其他Service的private方法, @Transactional会生效吗
共 29972字,需浏览 60分钟
·
2020-10-30 03:55
作者:zzzzbw
来源:SegmentFault 思否社区
省流大师:
一个Service调用其他Service的private方法, @Transactional会生效吗 正常流程不能生效 经过一番操作, 达到理论上可以
疑问
验证
@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);
}
// 被代理类没有实现接口, 使用Cglib代理
return new ObjenesisCglibAopProxy(config);
}
else {
// 默认JDK代理
return new JdkDynamicAopProxy(config);
}
}
}
则用JDK代理(JdkDynamicAopProxy), 否则用CGlib代理(ObjenesisCglibAopProxy).
假如想要强制使用JDK代理模式, 可以设置配置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. 反射获取构造方法生成代理对象实例
*/
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");
}
/*
* 如果代理类已经生成则直接返回, 否则通过ProxyClassFactory创建新的代理类
*/
return proxyClassCache.get(loader, interfaces);
}
不过我们只要知道, 这个缓存在get时如果存在值, 则返回这个值, 如果不存在, 则调用ProxyClassFactory的apply()方法.
public Class> apply(ClassLoader loader, Class>[] interfaces) {
...
// 上面是很多校验, 这里先不看
/*
* 为新生成的代理类起名:proxyPkg(包名) + proxyClassNamePrefix(固定字符串"$Proxy") + num(当前代理类生成量)
*/
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* 生成定义的代理类的字节码 byte数据
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
/*
* 把生成的字节码数据加载到JVM中, 返回对应的Class
*/
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch ...
}
代理类字节码生成流程
public static byte[] generateProxyClass(final String name,
Class[] interfaces)
{
ProxyGenerator gen = new ProxyGenerator(name, interfaces);
// 实际生成字节码
final byte[] classFile = gen.generateClassFile();
// 访问权限操作, 这里省略
...
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 < interfaces.length; i++) {
Method[] methods = interfaces[i].getMethods();
for (int j = 0; j < methods.length; j++) {
addProxyMethod(methods[j], interfaces[i]);
}
}
// 校验是否有重复的方法
for (Listsigmethods : proxyMethods.values()) {
checkReturnTypes(sigmethods);
}
/* ============================================================
* 步骤二:组装需要生成的代理类字段信息(FieldInfo)和方法信息(MethodInfo)
*/
try {
// 添加构造方法
methods.add(generateConstructor());
for (Listsigmethods : proxyMethods.values()) {
for (ProxyMethod pm : sigmethods) {
// 由于代理类内部会用反射调用目标类实例的方法, 必须有反射依赖, 所以这里固定引入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文件
*/
// 这部分就是根据上面组装的信息编写字节码
...
return bout.toByteArray();
}
组装需要生成的代理类的字段信息和方法信息. 这里会根据步骤一添加的方法, 生成实际的代理类的方法的实现. 比如:
如果目标代理类实现了一个HelloService接口, 且实现其中的方法hello, 那么生成的代理类就会生成如下形式方法:
public Object hello(Object... args){
try{
return (InvocationHandler)h.invoke(this, this.getMethod("hello"), args);
} catch ...
}把上面添加和组装的信息通过流拼接出最终的java class字节码数据
不过想一下也知道, 私有方法在正常情况下外部也无法调用, 即使代理了也没法使用, 所以也没必要去代理.**
结论
重新实现一个ProxyGenerator.generateClassFile()方法, 输出带有private方法的代理类字节码数据 把字节码数据加载到JVM中, 生成Class 替代Spring Boot中默认的动态代理功能, 换成我们自己的动态代理.
前情提要: 在Service调用其他Service的private方法, @Transactional会生效吗(上)中证明了动态代理不会代理private方法的, 并通过阅读源码证实了. 但是我们可以自己实现一个动态代理功能替代Spring Boot中原有的, 达到动态代理private方法的目的. 主要流程为:
重新实现一个ProxyGenerator.generateClassFile()方法, 输出带有private方法的代理类字节码数据 把字节码数据加载到JVM中, 生成Class 替代Spring Boot中默认的动态代理功能, 换成我们自己的动态代理.
前置代码
@Getter
public abstract class PrivateProxyInvocationHandler implements InvocationHandler {
private final Object subject;
public PrivateProxyInvocationHandler(Object subject) {
this.subject = subject;
}
}
为了简便实现, 就不实现扫描解析的功能了, 这里直接模仿前文的TransactionalAop的功能实现切面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;
}
}
生成字节码数据
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();
ListprivateMethods = Arrays.stream(declaredMethods)
.filter(method -> method.getModifiers() == Modifier.PRIVATE)
.collect(Collectors.toList());
this.privateMethods.addAll(privateMethods);
// 4. 校验方法的签名等@see sun.misc.ProxyGenerator.checkReturnTypes
// 这里省略
// 5. 添加类里的字段信息和方法数据
// 如静态方法、构造方法、字段等
// TODO 这里省略, 在编写java字符串(步骤7)时直接写入
// 6. 校验一下方法长度、字段长度等
// 这里省略
// 7. 把刚才添加的数据真正写到class文件里
// TODO 这里我们根据逻辑写成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);
// 必须要的属性和构造函数
/**
* 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();
}
/**
* 编写代理方法数据
*/
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("(");
// 参数类
Class>[] parameterTypes = proxyMethod.getParameterTypes();
// 参数类名
ListargClassNames = new ArrayList<>();
// 参数名
Listargs = new ArrayList<>();
for (int i = 0; i < parameterTypes.length; i++) {
Class> parameterType = parameterTypes[i];
argClassNames.add(parameterType.getTypeName());
args.add("var" + i);
}
// 写入参数的声明
for (int i = 0; i < args.size(); 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方法, 设置访问权限
sb.append("m.setAccessible(true);").append(WRAP);
}
// 4. InvocationHandler中调用代理方法逻辑, 例:
// return this.h.invoke(this, m, new Object[]{var0});
if (!proxyMethod.getReturnType().equals(Void.class) && !proxyMethod.getReturnType().equals(void.class)) {
// 有返回值则返回且强转
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重新实现了一遍, 通过PrivateProxyInvocationHandler.invoke()来调用代理后的方法逻辑.
加载到JVM, 生成动态代理类
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 讲源码输出到java文件中
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);
// 通过构造方法生成代理对象
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默认动态代理
现在为了让@Transactional注解能对private方法生效, 就要把自定义的动态代理方法嵌入到Spring Boot的代理流程中
AopProxy
上文也分析了JdkDynamicAopProxy.getProxy()方法是如何返回代理对象的, 这里我们就模仿来实现一个自己的AopProxy.
public class PrivateAopProxy implements AopProxy {
private final AdvisedSupport advised;
/**
* 构造方法
*
* 直接复制JdkDynamicAopProxy构造方法逻辑
*/
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);
}
}
本文的目的主要是代理私有方法, 不怎么关注切面, 所以就直接固定用new TransactionalHandler().
AbstractAdvisorAutoProxyCreator
这两种AopProxy是通过DefaultAopProxyFactory.createAopProxy()根据条件生成的, 那么现在就要替换掉DefaultAopProxyFactory, 通过实现自己的AopProxyFactory来生成PrivateAopProxy.
class PrimaryAopProxyFactory implements AopProxyFactory {
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
return new PrivateAopProxy(config);
}
}
其getProxy()方法会调用ProxyCreatorSupport中的aopProxyFactory变量, 而aopProxyFactory默认就是DefaultAopProxyFactory, 相关源码如下:
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);
}
// 调用Factory工厂方法返回代理类对象
return proxyFactory.getProxy(getProxyClassLoader());
}
所以就考虑实现一个类继承AbstractAutoProxyCreator然后重写createProxy()方法, 在自己的createProxy()方法中修改ProxyFactory.aopProxyFactory的值.
SmartInstantiationAwareBeanPostProcessor继承InstantiationAwareBeanPostProcessor,而InstantiationAwareBeanPostProcessor继承BeanPostProcessor.
这两个类的主要区别为切点的不同, BeanNameAutoProxyCreator是通过Bean名称等配置指定切点, AbstractAdvisorAutoProxyCreator是基于Advisor匹配机制来决定切点.
通常使用的就是AnnotationAwareAspectJAutoProxyCreator, 从名字上看就可以知道, 它会通过注解和Aspect表达式来决定切面,
如上文实现的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方法, 且与本文功能无关, 这里就不作改造, 直接注释掉
/*
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
*/
ProxyFactory proxyFactory = new ProxyFactory();
// 设置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());
}
}
再加上设置ProxyFactory.aopProxyFactory为PrimaryAopProxyFactory的代码: proxyFactory.setAopProxyFactory(new PrimaryAopProxyFactory());就完成了PrivateProxyAdvisorAutoProxyCreator.
引入到Bean中
但是加上之后却没有生效, 就去看一下AnnotationAwareAspectJAutoProxyCreator, 这个类上是没有加@Component注解的, 那么它是怎么引入到Spring Boot的?
为了查明原因, 我就查一下哪里调用了AnnotationAwareAspectJAutoProxyCreator类, 找到了一个AopConfigUtils这么一个工具类, 上文提到的几种AbstractAdvisorAutoProxyCreator的实现类就是这里引入的,
且设置Bean名为"org.springframework.aop.config.internalAutoProxyCreator", 看一下相关代码:
public abstract class AopConfigUtils {
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
"org.springframework.aop.config.internalAutoProxyCreator";
// AbstractAdvisorAutoProxyCreator实现类列表
private static final List> APC_PRIORITY_LIST = new ArrayList<>(3);
static {
// 添加AbstractAdvisorAutoProxyCreator实现类, 优先级有小到大, 也就是说默认为最后添加的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实现类到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中已经有被引入的AbstractAdvisorAutoProxyCreator实现类, 则比对优先级
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 < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
// 引入对应的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实现类的优先级的时候要求必须是在AopConfigUtils.APC_PRIORITY_LIST有的才行.
private static int findPriorityForClass(@Nullable String className) {
for (int i = 0; i < APC_PRIORITY_LIST.size(); 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实现PrivateAopProxy的时候, 由于JdkDynamicAopProxy的切面实现逻辑非常复杂, 我们直接把切面写死成了TransactionalHandler.
但是本文的主要目的就是能够在Spring Boot代理private方法, 只要能够代理, 说明@Transactional事务生效也是完全能做到的.
感悟
从前文Service调用其他Service的private方法, @Transactional会生效吗(上)阅读Spring Boot动态代理的功能源码实现, 到本文亲手实现"特殊功能"的动态代理,
不仅精通了Spring Boot动态代理的代码实现流程, 还掌握了JDK的动态代理功能, 收益非常大!