1 spring 5.0 默认使用的 代理方式 依旧是 jdk 动态代理(之前的版本也是)
2 springboot 2.X 开始 默认使用代理方式 cglib(springboot 2.X 默认使用 spring 5,给人的感觉是 spring 5.0 开始默认使用的 cglib 代理)
3 可以使用 spring.aop.proxy-target-class=false 切换成 jdk 动态代理(spring boot 默认是true),spring xml 方式使用 <aop:aspectj-autoproxy proxy-target-class="true"/>
4 spring aop默认使用的代理方式是 jdk 代理 的意思是,有父类接口的就使用jdk 动态代理,没有的还是只能使用 cglib
/** * jdk 动态代理 */ @Test public void t1(){ ReadWriteInfo writeInfo = new ReadWriteInfo(); writeInfo.setInfo("我的信息"); InvocationHandler renterHandler = new InvocationHandler(){ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代理类参数:" + proxy.getClass() ); System.out.println("调用的方法名字:" + method.getName() ); System.out.println("参数:" + JSONObject.toJSONString( args ) ); return method.invoke(writeInfo,args); } }; CanRead canRead = (CanRead)Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{CanRead.class, CanWrite.class},renterHandler); CanWrite canWrite = (CanWrite)canRead; System.out.println("代理类:" + canWrite.getClass() ); System.out.println("代理类的接口:" + JSONObject.toJSONString( canWrite.getClass().getAnnotatedInterfaces() ) ); System.out.println("代理类类型判断 CanRead :" + (canWrite instanceof CanRead) ); System.out.println("代理类类型判断 CanWrite:" + (canWrite instanceof CanWrite) ); System.out.println("代理类类型判断 ReadWriteInfo:" + (canWrite instanceof ReadWriteInfo) ); System.out.println( canRead.getInfo( 1L )); canWrite.setInfo( "新的信息" ); System.out.println( canRead.getInfo( 1L ) ); logger.info("取到的goods 名字:{}", "1111111111" ); }
值得注意的是,可以指定多个 增强实现,但是多个增强实现的时候必须指定 拦截器 ,返回使用的增强逻辑下标
/** * cgLib 的 动态代理 */ @Test public void t2(){ ReadWriteInfo writeInfo = new ReadWriteInfo(); writeInfo.setInfo("我的信息"); org.springframework.cglib.proxy.InvocationHandler renterHandler = new org.springframework.cglib.proxy.InvocationHandler(){ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代理类参数:" + proxy.getClass() ); System.out.println("调用的方法名字:" + method.getName() ); System.out.println("参数:" + JSONObject.toJSONString( args ) ); return method.invoke(writeInfo,args); } }; org.springframework.cglib.proxy.InvocationHandler renterHandler2 = new org.springframework.cglib.proxy.InvocationHandler(){ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代理类参数2:" + proxy.getClass() ); System.out.println("调用的方法名字2:" + method.getName() ); System.out.println("参数2:" + JSONObject.toJSONString( args ) ); return method.invoke(writeInfo,args); } }; CallbackFilter callbackFilter = new CallbackFilter() { @Override public int accept(Method method) { return 1; } }; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass( writeInfo.getClass() ); enhancer.setCallbacks(new Callback[]{renterHandler,renterHandler2}); enhancer.setCallbackFilter(callbackFilter ); ReadWriteInfo rwInfo = (ReadWriteInfo) enhancer.create(); logger.info("代理类信息:{}", rwInfo.getClass() ); rwInfo.getInfo(1L); rwInfo.setInfo( "new info" ); rwInfo.getInfo(1L); }
/** * 静态代理 */ @Test public void t3(){ ReadWriteInfo writeInfo = new ReadWriteInfo(); writeInfo.setInfo("我的信息"); StaticProxy staticProxy = new StaticProxy(); staticProxy.inti(writeInfo,writeInfo); staticProxy.setInfo("静态代理信息"); System.out.println( staticProxy.getInfo(1L) ); } /** * 静态代理类 */ class StaticProxy implements CanRead,CanWrite { private CanRead canRead ; private CanWrite canWrite; public void inti( CanRead canRead ,CanWrite canWrite ){ this.canRead = canRead; this.canWrite = canWrite; } @Override public String getInfo(Long id) { System.out.println("静态代理工作getInfo......"); return canRead.getInfo(id); } @Override public void setInfo(String info) { System.out.println("静态代理工作setInfo......"); canWrite.setInfo(info); } }
1 动态代理和静态代理的区别在于 代理类是硬编码产生的还是通过 java 反射产生的
2 动态代理的优势有两个 第一是代理类动态产生,第二是增强的逻辑动态替换
3 静态代理 如果使用 InvocationHandler 接口也可以实现 增强逻辑的动态替换,但是不能实现代理类的动态生成
4 代理类的动态生指的是 不需要硬编码就能实现一个包含一个或者多个接口的代理实现类,这是动态代理最大的优势
5 当前调用方法名字 可以通过当前线程 调用记录得到 Thread.currentThread().getStackTrace()[1]
6 单个类指定代理模式可以通过设置 BeanDifination的 proxyTargetClass 属性来设置 definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
/** * 获取当前调用的方法名字 * Thread.currentThread().getStackTrace() 里面有当前调用的调用栈追踪记录 * Thread.currentThread().getStackTrace()[0] 是追踪方法本身, Thread.currentThread().getStackTrace()[1] 是当前方法 * */ @Test public void t4(){ String methodName = Thread.currentThread().getStackTrace()[1].getMethodName(); logger.info("获取当前方法的名字:{}",methodName ); logger.error("当前占信息:{}", JSONObject.toJSONString( Thread.currentThread().getStackTrace() ) ); }