静态代理, 就是由程序员手动编写代理类或者用工具生成代理类的代码, 再进行编译生成 class 文件, 实现代理. 比如简单工厂模式.
用法:
代理类和目标类都实现相同接口.
代理类持有目标类的引用.
缺点: 静态代理要为每个目标类创建一个代理类, 当需要代理的对象太多, 那么代理类也变得很多. 代理类违背了可重复代理只写一次的原则.
动态代理
为了解决静态代理的缺点, 于是引入了动态代理. 它有一个好处, 那就是不用写很多代理类, 生成的代理类数量是固定的. 一般动态代理分为 2 种:
JDK 动态代理
JDK 动态代理是 JDK 自带的, 不依赖第三方框架. 它的实现原理, 就是利用 Java 的反射机制, 创建一个实现接口的代理类.
用法:
被代理对象必须实现接口.
代理对象由代理工厂自动生成.
下面贴个例子
接口类:
publicinterfaceSubject{publicvoiddoSomething(); }
实现类:
publicclassRealSubjectimplementsSubject{publicvoiddoSomething(){ System.out.println("do 了 some thing ..."); } }
代理工厂:
importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Method;importjava.lang.reflect.Proxy;publicclassProxyHandlerimplementsInvocationHandler {privateObjecttarget;// 绑定委托对象, 并返回代理类 publicObjectbind(Objecttarget) {this.target = target;// 绑定该类实现的所有接口, 取得代理类 returnProxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this); }@OverridepublicObjectinvoke(Objectproxy , Method method ,Object[] args)throws Throwable {Objectresult =null;// 这里就可以进行所谓的 AOP 编程了 // 在调用具体函数方法前, 执行功能处理 result = method.invoke(target, args);// 在调用具体函数方法后, 执行功能处理 returnresult; }}
测试类:
public class TestProxy { public static void main(String args[]) { ProxyHandler proxy = new ProxyHandler();// 绑定该类实现的所有接口 Subjectsub=(Subject) proxy.bind(new RealSubject());sub.doSomething(); }}
CGLIB 代理
使用 CGLIB 代理需要引入 CGLIB 库, 它使用字节码技术实现代理.
- importjava.lang.reflect.Method;importnet.sf.cglib.proxy.Enhancer;importnet.sf.cglib.proxy.MethodInterceptor;importnet.sf.cglib.proxy.MethodProxy;publicclassCGLibProxyimplementsMethodInterceptor {privateObjecttargetObject;// CGLib 需要代理的目标对象 publicObjectcreateProxyObject(Objectobj) {this.targetObject = obj; Enhancer enhancer =newEnhancer(); enhancer.setSuperclass(obj.getClass()); enhancer.setCallback(this);ObjectproxyObj = enhancer.create();returnproxyObj;// 返回代理对象 }publicObjectintercept(Objectproxy, Method method,Object[] args, MethodProxy methodProxy) throws Throwable {Objectobj =null;if("addUser".equals(method.getName())) {// 过滤方法 checkPopedom();// 检查权限 } obj = method.invoke(targetObject, args);returnobj; }privatevoidcheckPopedom() { System.out.println("检查权限 checkPopedom()!"); } }
- public class Test { public static void main(String[] args) { Subjectsub=(Subject) new CGLibProxy().createProxyObject(new RealSubject());sub.doSomething();}
2 种动态代理的区别
JDK 动态代理是利用反射机制生成一个实现代理接口的匿名类, 在调用具体方法前调用 InvokeHandler 来处理. 而 CGLIB 动态代理是利用 asm 开源包, 加载代理对象类的 class 文件, 修改其字节码生成子类来处理.
在 Spring 中,
如果目标对象实现了接口, 默认情况下会采用 JDK 动态代理实现 AOP
如果目标对象实现了接口, 可以强制使用 CGLIB 实现 AOP
如果目标对象没有实现了接口, 必须采用 CGLIB 库, Spring 会自动在 JDK 动态代理和 CGLIB 之间转换
如何强制使用 CGLIB 实现 AOP?
添加 CGLIB 依赖
在 Spring 配置文件中加入
如果是 SpringBoot, 在配置文件设置 spring.aop.proxy-target-class=true
JDK 动态代理和 CGLIB 字节码生成的区别?
JDK 动态代理只能对实现了接口的类生成代理, 而不能针对未实现接口的类
CGLIB 是针对类实现代理, 主要是对指定的类生成一个子类, 覆盖其中的方法
因为是继承, 所以该类或方法最好不要声明成 final
如果你想学好 JAVA 这门技术, 也想在 IT 行业拿高薪, 可以参加我们的训练营课程, 选择最适合自己的课程学习, 技术大牛亲授, 7 个月后, 进入名企拿高薪. 我们的课程内容有: Java 工程化, 高性能及分布式, 高性能, 深入浅出. 高架构. 性能调优, Spring,MyBatis,Netty 源码分析和大数据等多个知识点. 如果你想拿高薪的, 想学习的, 想就业前景好的, 想跟别人竞争能取得优势的, 想进阿里面试但担心面试不过的, 你都可以来, q 群号为: 779792048
注: 加群要求
1, 具有 1-5 工作经验的, 面对目前流行的技术不知从何下手, 需要突破技术瓶颈的可以加.
2, 在公司待久了, 过得很安逸, 但跳槽时面试碰壁. 需要在短时间内进修, 跳槽拿高薪的可以加.
3, 如果没有工作经验, 但基础非常扎实, 对 java 工作机制, 常用设计思想, 常用 java 开发框架掌握熟练的, 可以加.
4, 觉得自己很牛 B, 一般需求都能搞定. 但是所学的知识点没有系统化, 很难在技术领域继续突破的可以加.
5. 阿里 Java 高级大牛直播讲解知识点, 分享知识, 多年工作经验的梳理和总结, 带着大家全面, 科学地建立自己的技术体系和技术认知!
来源: http://www.jianshu.com/p/365a2a406bb5