spring aop源码想到的代理模式
2020-04-20 09:40:49来源:博客园 阅读 ()
spring aop源码想到的代理模式
代理(pxoxy)无处不在,哪怕在现实生活中
在看源码的时候,看到了aop,
就以此引出代理的知识扩展。
为什么要有代理呢,主要是不改变原来代码的功能的前提下,增加一些特殊功能,比如记录日志,权限认证,事务相关。
代理有静态代理和动态代理,而动态代理有两种实现方式:jdk代理和cglib代理,下面分别介绍下其实现方式
0 静态代理
这是很古老的方式了,一开始入行时用的代理就是这样方式实现的。核心伪代码如下
/** * * @author dgm * @describe "产品接口" * @date 2020年4月20日 */ public interface ProductDao { Product createProduct(String name, String size); } public class ProductDaoImpl implements ProductDao { public ProductDaoImpl() { } public Product createProduct(String name, String size) { return new Product(name,size); } } /** * * @author dgm * @describe "静态代理" * @date 2020年4月20日 */ public class ProductStaticProxy implements ProductDao { private ProductDao target; public ProductStaticProxy(ProductDao target) { this.target = target; } @Override public Product createProduct(String name, String size) { System.out.println("代理执行,开始工地干活生产房子办公楼产品了..."); return target.createProduct(name,size); } } public class ProductStaticProxyTest { public static void main(String[] args) { // 目标对象 ProductDao dao = new ProductDaoImpl(); System.out.println("目标对象: " + dao.getClass()); // 获取代理对象 ProductDao proxy = new ProductStaticProxy(dao); System.out.println("代理对象: "+proxy.getClass()); // 代理生产产品 System.out.println(proxy.createProduct("手机屏幕", "4寸")); } }
执行结果图示
此种方式简单,但随着项目量越来越大,维护的代码也就越多,且接口改动也频繁,迫切需要一种新的方式,这时动态代理登场了
1. jdk动态代理(自带功能,不需要引入第三方包)
先介绍下java.lang.reflect.Proxy类,它提供的一个newProxyInstance方法用来创建一个对象的代理对象
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
newProxyInstance方法用来返回一个代理对象,这个方法总共有3个参数,ClassLoader loader用来指明生成代理对象使用哪个类装载器,Class<?>[] interfaces用来指明生成哪个对象的代理对象,通过接口指定,InvocationHandler h用来指明产生的这个代理对象要做什么事情。所以我们只需要调用newProxyInstance方法就可以得到某一个对象的代理对象了。
示例代码:
/** * * @author dgm * @describe "jdk动态代理" * @date 2020年4月20日 */ public class ProductJdkDynamicProxy { // 接收一个目标对象 private Object target; public ProductJdkDynamicProxy(Object target) { this.target = target; } // 返回对目标对象(target)代理后的对象(proxy) public Object getProxyInstance() { Object proxy = Proxy.newProxyInstance(target.getClass() .getClassLoader(), // 目标对象使用的类加载器 target.getClass().getInterfaces(), // 目标对象实现的所有接口 new InvocationHandler() { // 执行代理对象方法时候触发 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("原生jdk开启生产产品线,拼命加班中"); // 执行目标对象方法 Object result = method.invoke(target, args); System.out.println("原生jdk干的不错,结束生产产品"); return result; } }); return proxy; } } public class ProductJdkDynamicProxyTest { public static void main(String[] args) { // TODO Auto-generated method stub //目标对象 ProductDao target = new ProductDaoImpl(); System.out.println("目标对象: "+target.getClass()); //代理生产产品 ProductDao proxy = (ProductDao) new ProductJdkDynamicProxy(target).getProxyInstance(); System.out.println("代理对象: "+proxy.getClass()); //执行代理业务具体业务操作 System.out.println(proxy.createProduct("手机屏幕", "4寸")); } }
测试效果:
spring aop的实现方式之一就是它实现的
2. cglib代理
慢慢地工作到了一定阶段,时代在发展为了快速开发,项目化运作,开始大量引进框架和第三方库,真的很好用(特别是项目开发),比如cglib,由于它是针对类实现的代理,故类不能是final类型。
/** * * @author dgm * @describe "cglib动态代理" * @date 2020年4月20日 */ public class ProductCglibDynamicProxy implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { try { before(method);// 前置通知 Object ret = methodProxy.invokeSuper(obj, args);// 目标方法执行 after(method, ret);// 后置通知 return ret; } catch (Exception e) { exception();// 异常通知 } finally { afterReturning();// 方法返回通知 } return null; } // 前置增强 private void before(Method method) { System.out.printf("cglib 动态代理:%s", method.getName()); } // 后置增强 private void after(Method method, Object ret) { System.out.printf(",cglib动态代理:%s, ret:%s", method.getName(), ret); } // 异常增强 private void exception() { System.out.println(",程序出错了!"); } // after返回增强 private void afterReturning() { System.out.println(",产品成型"); } } /** * * @author dgm * @describe "测试cglib动态代理" * @date 2020年4月20日 */ public class ProductCglibDynamicProxyTest { public static void main(String[] args) { // TODO Auto-generated method stub //代理对象 ProductDao proxy = CglibProxyFactory.create(); System.out.println("代理对象: "+proxy.getClass()); //执行代理业务具体业务操作 System.out.println(proxy.createProduct("手机屏幕", "4寸")); } }
运行结果:
spring-aop的另一实现也是基于此
简单总结:
- 静态代理实现较简单,只要代理对象对目标对象进行包装,即可实现增强功能,但静态代理只能为一个目标对象服务,如果目标对象过多,则会产生很多代理类。
- JDK动态代理需要目标对象实现业务接口,代理类只需实现InvocationHandler接口。
- 静态代理在编译时产生class字节码文件,可以直接使用,效率高。
- 动态代理必须实现InvocationHandler接口,通过反射代理方法,比较消耗系统性能,但可以减少代理类的数量,使用更灵活。
- cglib代理无需实现接口,通过生成类字节码实现代理,比反射稍快,不存在性能问题,但cglib会继承目标对象,需要重写方法,所以目标对象不能为final类。
延伸阅读:
0. java动态代理原理及解析 https://www.sohu.com/a/246547051_132276
1. Spring AOP 实现原理与 CGLIB 应用 https://www.ibm.com/developerworks/cn/java/j-lo-springaopcglib/
2. 从动态代理到SpringAop以及AspectJ风格 https://segmentfault.com/a/1190000015262333
3. Java 动态代理机制分析及扩展,第 1 部分 https://www.ibm.com/developerworks/cn/java/j-lo-proxy1/index.html
4. spring AOP是什么?你都拿它做什么? https://zhuanlan.zhihu.com/p/28097563
原文链接:https://www.cnblogs.com/dongguangming/p/12735887.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- Spring系列.ApplicationContext接口 2020-06-11
- springboot2配置JavaMelody与springMVC配置JavaMelody 2020-06-11
- 给你一份超详细 Spring Boot 知识清单 2020-06-11
- SpringBoot 2.3 整合最新版 ShardingJdbc + Druid + MyBatis 2020-06-11
- 掌握SpringBoot-2.3的容器探针:实战篇 2020-06-11
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash