程序员之家程序员Java 杂谈

谈谈Java中的代理!

2018-05-16  本文已影响72人  cb9841112785

静态代理

静态代理,就是由程序员手动编写代理类或者用工具生成代理类的代码,再进行编译生成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高级大牛直播讲解知识点,分享知识,多年工作经验的梳理和总结,带着大家全面、科学地建立自己的技术体系和技术认知!

上一篇下一篇

猜你喜欢

热点阅读