java编码中经常用到代理,代理分为静态代理和动态代理。其中动态代理可以实现spring中的aop。
一、静态代理:程序运行之前,程序员就要编写proxy,然后进行编译,即在程序运行之前,代理类的字节码文件就已经生成了
被代理类的公共父类
packagestaticproxy;
publicabstractclassBaseClass{
publicabstractvoidadd();
}
被代理类
packagestaticproxy;
publicclassAextendsBaseClass{
publicvoidadd(){
System.out.println("Aadd!");
}
}
代理类
packagestaticproxy;
BaseClassbaseClass;
publicvoidadd(){
baseClass.add();
}
publicvoidsetBaseClass(BaseClassbaseClass){
this.baseClass=baseClass;
}
publicstaticvoidmain(String[]args){
BaseClassbaseClass=newA();
Proxyproxy=newProxy();
proxy.setBaseClass(baseClass);
proxy.add();
}
}
二、动态代理:实际的代码在编译期间并没有生成,而是在运行期间运用反射机制动态的生成
被代理类接口
packagejdkproxy;
publicinterfaceService{
publicvoidadd();
publicvoidupdate();
}
被代理类A
packagejdkproxy;
publicclassAServiceimplementsService{
publicvoidadd(){
System.out.println("AServiceadd>>>>>>>>>>>>>>>>>>");
}
publicvoidupdate(){
System.out.println("AServiceupdate>>>>>>>>>>>>>>>");
}
}
被代理类B
packagejdkproxy;
publicclassBServiceimplementsService{
publicvoidadd(){
System.out.println("BServiceadd---------------");
}
publicvoidupdate(){
System.out.println("BServiceupdate---------------");
}
}
代理类
packagejdkproxy;
importjava.lang.reflect.InvocationHandler;
importjava.lang.reflect.Method;
publicclassMyInvocationHandlerimplementsInvocationHandler{
privateObjecttarget;
MyInvocationHandler(){
super();
}
MyInvocationHandler(Objecttarget){
super();
this.target=target;
}
publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)
throwsThrowable{
//程序执行前加入逻辑
System.out.println("before-----------------------------");
//程序执行
Objectresult=method.invoke(target,args);
//程序执行后加入逻辑
System.out.println("after------------------------------");
returnresult;
}
publicObjectgetTarget(){
returntarget;
}
publicvoidsetTarget(Objecttarget){
this.target=target;
}
}
测试类
packagejdkproxy;
importjava.lang.reflect.Proxy;
publicclassTest{
publicstaticvoidmain(String[]args){
ServiceaService=newAService();
MyInvocationHandlerhandler=newMyInvocationHandler(aService);
//Proxy为InvocationHandler实现类动态创建一个符合某一接口的代理实例
ServiceaServiceProxy=(Service)Proxy.newProxyInstance(aService
.getClass().getClassLoader(),aService.getClass()
.getInterfaces(),handler);
//由动态生成的代理对象来aServiceProxy代理执行程序,其中aServiceProxy符合Service接口
aServiceProxy.add();
System.out.println();
aServiceProxy.update();
//以下是对B的代理
//ServicebService=newBService();
//MyInvocationHandlerhandler=newMyInvocationHandler(bService);
//ServicebServiceProxy=(Service)Proxy.newProxyInstance(bService
//.getClass().getClassLoader(),bService.getClass()
//.getInterfaces(),handler);
//bServiceProxy.add();
//System.out.println();
//bServiceProxy.update();
}
}
输出结果:
before-----------------------------
AServiceadd>>>>>>>>>>>>>>>>>>
after------------------------------
before-----------------------------
AServiceupdate>>>>>>>>>>>>>>>
after------------------------------
其中上述标红的语句是产生代理类的关键代码,可以产生一个符合Service接口的代理对象,newProxyInstance这个方法会做这样一件事情,他将把你要代理的全部接口,用一个由代码动态生成的类来实现,该类中所有的接口中的方法都重写为调用InvocationHandler.invoke()方法。
下面详细介绍是如何实现代理对象的生成的
Proxy的newProxyInstance方法,其中,为了看起来方便,已经将该方法中的异常处理语句删减
下下面public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h) throws
publicstaticObjectnewProxyInstance(ClassLoaderloader,Class<?>[]interfaces,InvocationHandlerh)throwsIllegalArgumentException
{
if(h==null){
thrownewNullPointerException();
}
//生成指定的代理类
Classcl=getProxyClass(loader,interfaces);
Constructorcons=cl.getConstructor(constructorParams);
//生成代理类的实例,并把MyInvocationHandler的实例传给它的构造方法,代理类对象实际执行都会调用MyInvocationHandler的invoke方法,所以代理类对象中维持一个MyInvocationHandler引用
return(Object)cons.newInstance(newObject[]{h});
}
其中getProxyClass方法返回代理类的实例
Proxy的getProxyClass方法
publicstaticClass<?>getProxyClass(ClassLoaderloader,Class<?>...interfaces)throwsIllegalArgumentException
{
//前面省略很多缓存、异常处理、判断逻辑代码,为了使程序更加突出
byte[]proxyClassFile=ProxyGenerator.generateProxyClass(proxyName,interfaces);
proxyClass=defineClass0(loader,proxyName,proxyClassFile,0,proxyClassFile.length);
proxyClasses.put(proxyClass,null);
returnproxyClass;
}
下面看ProxyGenerator的generateProxyClass方法,该方法最终产生代理类的字节码文件:
publicstaticbyte[]generateProxyClass(finalStringname,Class[]interfaces)
{
ProxyGeneratorgen=newProxyGenerator(name,interfaces);
//这里动态生成代理类的字节码
finalbyte[]classFile=gen.generateClassFile();
//如果saveGeneratedFiles的值为true,则会把所生成的代理类的字节码保存到硬盘上
if(saveGeneratedFiles){
java.security.AccessController.doPrivileged(
newjava.security.PrivilegedAction<Void>(){
publicVoidrun(){
try{
FileOutputStreamfile=
newFileOutputStream(dotToSlash(name)+".class");
file.write(classFile);
file.close();
returnnull;
}catch(IOExceptione){
thrownewInternalError(
"I/Oexceptionsavinggeneratedfile:"+e);
}
}
});
}
//返回代理类的字节码
returnclassFile;
}
那么最终生成的代理类到底是什么样子呢,如下(省略了一下equals,hashcode,toString等方法,只展示构造函数和add方法):
-
publicfinalclass$Proxy11extendsProxyimplementsService
-
{
-
-
public$Proxy11(InvocationHandlerinvocationhandler)
-
{
-
super(invocationhandler);
-
}
-
-
-
-
-
publicfinalvoidadd()
-
{
-
try
-
{
-
-
super.h.invoke(this,m3,null);
-
return;
-
}
-
catch(Error_ex){}
-
catch(Throwablethrowable)
-
{
-
thrownewUndeclaredThrowableException(throwable);
-
}
-
}
-
}
注意:java的jdk中得动态代理有一个限制条件,就是必须要被代理的类基于统一的接口,否则不能够实现。如果必须要使代理突破这个限制,那么可以尝试运用cglib来实现动态代理。cglib能够使方法执行更加高效,但是可能在动态创建类的过程中效率会稍微低一些,缓存该过程生成的类即可。
分享到:
相关推荐
JAVA静态代理和动态代理
Java静态代理和动态代理
Java设计模式——代理设计模式(静态代理和动态代理) 各种情况例子源码
Java中提供了一个java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口来实现动态代理。代理类在运行时会根据被代理接口自动生成,并且可以通过InvocationHandler接口对方法进行增强。
这里提供了静态代理和动态代理的入门写法~一看即懂!
Java中的代理模式--静态代理和动态代理 Java中的代理模式--静态代理和动态代理
JAVA JDK静态代理、动态代理、CGlib代理的代码演示 为对象增加功能
java提高-动态代理与静态代理.docx
java static proxy dynamic proxy
- 静态代理与动态代理 - 常见的动态代理实现 - JDK Proxy - CGLIB - JDK Proxy 和 CGLIB 的对比 - 动态代理的实际应用 - Spring AOP 说在前面:今天我们来聊一聊 Java 中的代理,先来聊聊故事背景: 小明想...
NULL 博文链接:https://871656094.iteye.com/blog/2355335
利用一个Car接口详细介绍了静态代理技术和JDK动态动态代理技术
Java 静态代理
资源列举了设计模式中的静态代理和动态代理的简单java实现,jdk1.8版本经过测试验证,对于想学习设计模式的童靴应该有所帮助
静态代理代理模式,顾名思义就是提供一个代理类,可以访问原对象并且替原对象进行一些操作。 优点:使用代理模式可以在保证不修改原有类的同时(即满足对扩展开放,对修改关闭的原则),对原有类增加一些功能实现。
1:静态代理出现的实际背景,静态代理时如何演化成动态代理 2: 动态代理demo 举例实际应用场景(载入数据库驱动的时候,使用AIDL与系统Servic进行通信) 3: 动态代理使用到基础理论:ClassLoader 加载.class字节码...
Java 动态代理详解(代理模式+静态代理+JDK动态代理+CGLIB动态代理)