前情提要:java
在Service调用其余Service的private方法, @Transactional会生效吗(上)中证实了动态代理不会代理private方法的, 并经过阅读源码证明了.git
可是咱们能够本身实现一个动态代理功能替代
Spring Boot
中原有的, 达到动态代理private方法的目的.github主要流程为:spring
- 从新实现一个
ProxyGenerator.generateClassFile()
方法, 输出带有private方法的代理类字节码数据- 把字节码数据加载到JVM中, 生成Class
- 替代
Spring Boot
中默认的动态代理功能, 换成咱们本身的动态代理.
首先, 要实现代理目标类的private方法的目标, 必需要能拿到被代理类的实例, 因此先改装切面InvocationHandler
, 把要被代理的类保存下来. .app
@Getter public abstract class PrivateProxyInvocationHandler implements InvocationHandler { private final Object subject; public PrivateProxyInvocationHandler(Object subject) { this.subject = subject; } }
前文的切面TransactionalAop
是Spring Boot
在JdkDynamicAopProxy
中扫描被@Aspect
注解的类, 而后解析类里面的方法以及切点等.
为了简便实现, 就不实现扫描解析的功能了, 这里直接模仿前文的TransactionalAop
的功能实现切面TransactionalHandler
.jvm
@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; } }
根据阅读ProxyGenerator.generateProxyClass()
方法生成字节码的代码能够知道, 动态代理的功能实际上就是动态的生成类的字节码, 经过新生成的字节码的类替代原有的类.ide
那咱们只要模仿generateProxyClass()
方法的功能, 实现本身的动态生成代码的功能, 而且在生成的时候把被代理类的private方法也一并生成了, 就能够实现private方法的动态代理功能.函数
另外ProxyGenerator.generateProxyClass()
方法是直接编写字节码数据的(即.class
文件), 为了方便咱们编写和查看生成的数据, 咱们就实现动态编写java数据, 而后再编译成字节码文件.工具
PrivateProxyGenerator是此次功能实现的核心代码, 迫于文章篇幅这里只放出重点部分, 如需完整代码可直接查看源码
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<Method> privateMethods = 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(); } ... }
这部分代码和JDK的ProxyGenerator.generateProxyClass()
方法流程相似, 主要就是保存一下被代理类及其方法的一些信息, 真正编写代码数据的功能在writeJavaSrc()
方法里完成.post
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(); // 参数类名 List<String> argClassNames = new ArrayList<>(); // 参数名 List<String> args = 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); }
writeJavaSrc()
大致上分为两部分, 第一部分是编写类的一些固定信息代码数据, 如包名、类声明、构造函数等, 生成大体相似于下面的代码:
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; } }
第二部分就是writeProxyMethod()
方法, 编写代理后的方法的代码数据, 生成大体相似于下面的代码:
// 代理的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); } }
以上就是咱们本身实现的支持private方法动态代理的"字节码"生成功能. 如今写个单元测试看一下效果
@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(); } } }
运行以后生成了一个$Proxy0.java
文件, 看一下文件内容(代码格式化了一下):
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); } } }
生成的$Proxy0
就是被代理类HelloServiceImpl
的代理类, 他实现了HelloServiceImpl
的全部interface
, 有个成员变量PrivateProxyInvocationHandler h
,
其全部public和private方法都被$Proxy0
从新实现了一遍, 经过PrivateProxyInvocationHandler.invoke()
来调用代理后的方法逻辑.
看来咱们本身实现的代理类字节码动态生成的功能挺成功的, 接下来就要考虑代理类生成的逻辑, 以及如何把.java文件加载到JVM里.
如今就模仿java.lang.reflect.Proxy.newProxyInstance()
方法, 编写本身的编译加载生成动态代理类对象的方法.
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(); } //三、将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(); // 四、将class加载进jvm Class<?> proxyClass = loader.loadClass(proxyName); // 经过构造方法生成代理对象 Constructor<?> constructor = proxyClass.getConstructor(PrivateProxyInvocationHandler.class); return constructor.newInstance(h); } catch (Exception e) { e.printStackTrace(); } return null; } }
PrivateProxy
经过调用PrivateProxyGenerator.generateProxyClass()
获取到代理类的.java文件的字符串, 而后输出到java文件中, 再编译成.class文件.
接着经过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); } }
从单元测试结果看到PrivateProxy.newProxyInstance()
方法成功生成了HelloServiceImpl
的代理类cn.zzzzbw.primary.proxy.reflect.$Proxy0
, 而且把public和private方法都代理了.
以上功能咱们经过实现PrivateProxyGenerator
和 PrivateProxy
两个类, 实现了JDK的动态代理功能, 而且还能代理private方法. 接下来就要考虑如何把Spring Boot
里的动态代理功能替换成咱们本身的.
Spring Boot
默认动态代理上面经过模仿JDK的动态代理, 本身实现了一个能代理private方法的动态代理功能.
如今为了让@Transactional
注解能对private方法生效, 就要把自定义的动态代理方法嵌入到Spring Boot
的代理流程中
Spring Boot
中自带的两种动态代理方式为JDK和Cglib, 对应的实现类是JdkDynamicAopProxy
和ObjenesisCglibAopProxy
, 这两个类都是实现AopProxy
接口, 实现其中的getProxy()
方法返回代理后的对象.
上文也分析了JdkDynamicAopProxy.getProxy()
方法是如何返回代理对象的, 这里咱们就模仿来实现一个本身的AopProxy
.
public class PrivateAopProxy implements AopProxy { private final AdvisedSupport advised; /** * 构造方法 * <p> * 直接复制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); } }
PrivateAopProxy.getProxy()
方法先经过advised
获取到目标代理类的接口, 并经过实例生成切面TransactionalHandler
, 而后返回刚才实现的PrivateProxy.newProxyInstance()
方法生成的代理类.
JdkDynamicAopProxy的切面是经过自身实现InvocationHandler接口的invoke()方法, 实现了一个切面的链式调用的功能, 逻辑较复杂就不去模仿了.
本文的目的主要是代理私有方法, 不怎么关注切面, 因此就直接固定用new TransactionalHandler().
实现了PrivateAopProxy
类, 再考虑如何把他替换掉Spring Boot
中的JdkDynamicAopProxy
和ObjenesisCglibAopProxy
.
这两种AopProxy
是经过DefaultAopProxyFactory.createAopProxy()
根据条件生成的, 那么如今就要替换掉DefaultAopProxyFactory
, 经过实现本身的AopProxyFactory
来生成PrivateAopProxy
.
由于不须要DefaultAopProxyFactory
里的那种判断动态代理方式, 自定义的AopProxyFactory
就直接new一个PrivateAopProxy
返回就好了.
class PrimaryAopProxyFactory implements AopProxyFactory { @Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { return new PrivateAopProxy(config); } }
实现了的PrimaryAopProxyFactory
, 如今要考虑怎么替换掉Spring Boot
中的DefaultAopProxyFactory
(是否是有点像套娃, 可是没办法, 就只能这样一步一步替换过去. 我我的以为Spring Boot
这部分设计的就不够优雅了, 使用了Factory工厂模式, 可是想要替换AopProxy
的时候却要把Factory也替换了.
多是开发者认为AOP这部分不必开放给使用者修改吧, 或者是我我的没找到更好的方式修改)
想要替换掉DefaultAopProxyFactory
, 就要找出哪里生成AopProxyFactory
, 那么就能够经过打断点的方式把断点打在createAopProxy()
上, 而后再看一下调用链.
观察到org.springframework.aop.framework.ProxyFactory.getProxy()
方法负责生成和控制AopProxyFactory.createAopProxy()
的逻辑. ProxyFactory
继承了ProxyCreatorSupport
类,
其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; } }
既然AopProxyFactory
是ProxyFactory
的一个变量, 那么如今看一下ProxyFactory
是由谁控制的, 怎么样才能修改成PrimaryAopProxyFactory
.
继续经过断点的方式, 发如今org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy()
方法中会new一个ProxyFactory
而且赋值一些属性, 而后调用ProxyFactory.getProxy()
方法返回生成的代理对象. 看一下源码
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()
作的事情就是new一个ProxyFactory
, 而后为其赋值, 最后调用ProxyFactory.getProxy()
返回代理对象.
因为ProxyFactory
是直接new出来的, 是一个局部变量, 因此没办法全局的修改ProxyFactory.aopProxyFactory
.
因此就考虑实现一个类继承AbstractAutoProxyCreator
而后重写createProxy()
方法, 在本身的createProxy()
方法中修改ProxyFactory.aopProxyFactory
的值.
AbstractAutoProxyCreator
是一个抽象类而且继承的类和实现的接口比较多, 因此这边我先查看了一下其整个的类结构图(只显示了重要的接口).
首先, 看一下其父类和父接口.
其实现了org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor
.SmartInstantiationAwareBeanPostProcessor
继承InstantiationAwareBeanPostProcessor
,而InstantiationAwareBeanPostProcessor
继承BeanPostProcessor
.
这三个接口是Spring
用于建立Bean时的加强功能, 是Spring
的IOC和AOP实现的核心思想, 建议你们都去了解一下, 这里就不详细讲解了,
只要知道AbstractAutoProxyCreator
实现了SmartInstantiationAwareBeanPostProcessor
的接口, 因此能在建立Bean的时候对其进行代理.
接着, 看一下其子类.
其直接子类有AbstractAdvisorAutoProxyCreator
和BeanNameAutoProxyCreator
.
这两个类的主要区别为切点的不一样, BeanNameAutoProxyCreator
是经过Bean名称等配置指定切点, AbstractAdvisorAutoProxyCreator
是基于Advisor
匹配机制来决定切点.
AbstractAdvisorAutoProxyCreator
又有三个子类, 分别为AnnotationAwareAspectJAutoProxyCreator(AspectJAwareAdvisorAutoProxyCreator)
, InfrastructureAdvisorAutoProxyCreator
, DefaultAdvisorAutoProxyCreator
.
一般使用的就是AnnotationAwareAspectJAutoProxyCreator
, 从名字上看就能够知道, 它会经过注解和Aspect
表达式来决定切面,
如上文实现的TransactionalAop
切面里的@Around("@within(org.springframework.transaction.annotation.Transactional)")
形式就是由AnnotationAwareAspectJAutoProxyCreator
处理的.
那么如今直接继承抽象类AbstractAutoProxyCreator
的子类AnnotationAwareAspectJAutoProxyCreator
, 而后重写createProxy()
方法.
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()); } }
直接把AbstractAutoProxyCreator.createProxy()
方法里的代码拷贝过来, 而后把一些调用private变量的地方改为调用其public的getter方法,
再加上设置ProxyFactory.aopProxyFactory
为PrimaryAopProxyFactory
的代码: proxyFactory.setAopProxyFactory(new PrimaryAopProxyFactory());
就完成了PrivateProxyAdvisorAutoProxyCreator
.
接下来就是把PrivateProxyAdvisorAutoProxyCreator
引入到Spring Boot
组件中, 由于其实现了SmartInstantiationAwareBeanPostProcessor
接口, 因此我想着直接在类上加@Component
注解就行了.
可是加上以后却没有生效, 就去看一下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<Class<?>> 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; } }
AopConfigUtils
工具类引入AbstractAdvisorAutoProxyCreator
的实现类的时候指定了Bean名,
因此咱们要给PrivateProxyAdvisorAutoProxyCreator
的Bean名也指定为AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME
才能覆盖:
@Component(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME) public class PrivateProxyAdvisorAutoProxyCreator extends AnnotationAwareAspectJAutoProxyCreator { ... }
可是这样还不够, 若是直接这样启动项目, 会爆出Class name [cn.zzzzbw.primary.proxy.spring.PrivateProxyAdvisorAutoProxyCreator] is not a known auto-proxy creator class
的错误.
这是因为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"); }
这下就比较麻烦了, APC_PRIORITY_LIST
是private属性, 且也没有开放public方法去修改, 大概Spring
官方也不想别人去修改这部分功能吧. 因此我只能经过反射的方式去修改了(若是是单元测试则写在单元测试里, 若是是启动项目则写在启动类里), 代码以下:
static { try { Field apc_priority_list = AopConfigUtils.class.getDeclaredField("APC_PRIORITY_LIST"); apc_priority_list.setAccessible(true); List<Class<?>> o = (List<Class<?>>) apc_priority_list.get(AopConfigUtils.class); o.add(PrivateProxyAdvisorAutoProxyCreator.class); } catch (Exception e) { e.printStackTrace(); } }
如今, 再跑一下最开头的单元测试!
从单元测试的结果看到, 切面TransactionalHandler
不只代理了HelloServiceImpl
的public方法hello()
, 也成功代理了private方法privateHello()
, 而且是由Spring Boot
来控制的!
通过一大长串的花里胡哨的操做, 终于实现了在private方法上使@Transactional
生效的效果了. 固然, 目前这只是理论上的生效,
由于中间在模仿JdkDynamicAopProxy
实现PrivateAopProxy
的时候, 因为JdkDynamicAopProxy
的切面实现逻辑很是复杂, 咱们直接把切面写死成了TransactionalHandler
.
可是本文的主要目的就是可以在Spring Boot
代理private方法, 只要可以代理, 说明@Transactional
事务生效也是彻底能作到的.
"Service调用其余Service的private方法, @Transactional会生效吗"
若是仅仅回答问题自己是很简单的, 只要了解Spring Boot
的AOP原理便可. 可是也能够深刻其中, 顺着这个问题继续研究,
从前文Service调用其余Service的private方法, @Transactional会生效吗(上)阅读Spring Boot
动态代理的功能源码实现, 到本文亲手实现"特殊功能"的动态代理,
不只精通了Spring Boot
动态代理的代码实现流程, 还掌握了JDK的动态代理功能, 收益很是大!
文中相关源码: private-proxy-source-code