深入解析java中的静态代理与动态代理
程序员文章站
2023-12-21 10:07:58
java编码中经常用到代理,代理分为静态代理和动态代理。其中动态代理可以实现spring中的aop。
一、静态代理:程序运行之前,程序员就要编写proxy,然后进行编译,...
java编码中经常用到代理,代理分为静态代理和动态代理。其中动态代理可以实现spring中的aop。
一、静态代理:程序运行之前,程序员就要编写proxy,然后进行编译,即在程序运行之前,代理类的字节码文件就已经生成了
被代理类的公共父类
复制代码 代码如下:
package staticproxy;
public abstract class baseclass {
public abstract void add();
}
被代理类
复制代码 代码如下:
package staticproxy;
public class a extends baseclass {
public void add() {
system.out.println("a add !");
}
}
代理类
复制代码 代码如下:
package staticproxy;
public class proxy {
baseclass baseclass;
public void add() {
baseclass.add();
}
public void setbaseclass(baseclass baseclass) {
this.baseclass = baseclass;
}
public static void main(string[] args) {
baseclass baseclass = new a();
proxy proxy = new proxy();
proxy.setbaseclass(baseclass);
proxy.add();
}
}
二、动态代理:实际的代码在编译期间并没有生成,而是在运行期间运用反射机制动态的生成
被代理类接口
复制代码 代码如下:
package jdkproxy;
public interface service {
public void add();
public void update();
}
被代理类a
复制代码 代码如下:
package jdkproxy;
public class aservice implements service {
public void add() {
system.out.println("aservice add>>>>>>>>>>>>>>>>>>");
}
public void update() {
system.out.println("aservice update>>>>>>>>>>>>>>>");
}
}
被代理类b
复制代码 代码如下:
package jdkproxy;
public class bservice implements service {
public void add() {
system.out.println("bservice add---------------");
}
public void update() {
system.out.println("bservice update---------------");
}
}
代理类
复制代码 代码如下:
package jdkproxy;
import java.lang.reflect.invocationhandler;
import java.lang.reflect.method;
public class myinvocationhandler implements invocationhandler {
private object target;
myinvocationhandler() {
super();
}
myinvocationhandler(object target) {
super();
this.target = target;
}
public object invoke(object proxy, method method, object[] args)
throws throwable {
// 程序执行前加入逻辑
system.out.println("before-----------------------------");
// 程序执行
object result = method.invoke(target, args);
//程序执行后加入逻辑
system.out.println("after------------------------------");
return result;
}
public object gettarget() {
return target;
}
public void settarget(object target) {
this.target = target;
}
}
测试类
复制代码 代码如下:
package jdkproxy;
import java.lang.reflect.proxy;
public class test {
public static void main(string[] args) {
service aservice = new aservice();
myinvocationhandler handler = new myinvocationhandler(aservice);
// proxy为invocationhandler实现类动态创建一个符合某一接口的代理实例
service aserviceproxy = (service) proxy.newproxyinstance(aservice
.getclass().getclassloader(), aservice.getclass()
.getinterfaces(), handler);
//由动态生成的代理对象来aserviceproxy 代理执行程序,其中aserviceproxy 符合service接口
aserviceproxy.add();
system.out.println();
aserviceproxy.update();
// 以下是对b的代理
// service bservice = new bservice();
// myinvocationhandler handler = new myinvocationhandler(bservice);
// service bserviceproxy = (service) proxy.newproxyinstance(bservice
// .getclass().getclassloader(), bservice.getclass()
// .getinterfaces(), handler);
// bserviceproxy.add();
// system.out.println();
// bserviceproxy.update();
}
}
输出结果:
before-----------------------------
aservice add>>>>>>>>>>>>>>>>>>
after------------------------------
before-----------------------------
aservice update>>>>>>>>>>>>>>>
after------------------------------
其中上述标红的语句是产生代理类的关键代码,可以产生一个符合service接口的代理对象,newproxyinstance这个方法会做这样一件事情,他将把你要代理的全部接口,用一个由代码动态生成的类来实现,该类中所有的接口中的方法都重写为调用invocationhandler.invoke()方法。
下面详细介绍是如何实现代理对象的生成的
proxy的newproxyinstance方法,其中,为了看起来方便,已经将该方法中的异常处理语句删减
下下面public static object newproxyinstance(classloader loader, class<?>[] interfaces,invocationhandler h) throws
复制代码 代码如下:
public static object newproxyinstance(classloader loader, class<?>[] interfaces,invocationhandler h) throws illegalargumentexception
{
if (h == null) {
throw new nullpointerexception();
}
//生成指定的代理类
class cl = getproxyclass(loader, interfaces);
constructor cons = cl.getconstructor(constructorparams);
// 生成代理类的实例,并把myinvocationhandler的实例传给它的构造方法,代理类对象实际执行都会调用myinvocationhandler的invoke方法,所以代理类对象中维持一个myinvocationhandler引用
return (object) cons.newinstance(new object[] { h });
} 其中getproxyclass方法返回代理类的实例
proxy的getproxyclass方法
复制代码 代码如下:
public static class<?> getproxyclass(classloader loader, class<?>... interfaces) throws illegalargumentexception
{
//前面省略很多缓存、异常处理、判断逻辑代码,为了使程序更加突出
byte[] proxyclassfile = proxygenerator.generateproxyclass(proxyname, interfaces);
proxyclass = defineclass0(loader, proxyname,proxyclassfile, 0, proxyclassfile.length);
proxyclasses.put(proxyclass, null);
return proxyclass;
}
下面看proxygenerator的generateproxyclass方法,该方法最终产生代理类的字节码文件:
复制代码 代码如下:
public static byte[] generateproxyclass(final string name, class[] interfaces)
{
proxygenerator gen = new proxygenerator(name, interfaces);
// 这里动态生成代理类的字节码
final byte[] classfile = gen.generateclassfile();
// 如果savegeneratedfiles的值为true,则会把所生成的代理类的字节码保存到硬盘上
if (savegeneratedfiles) {
java.security.accesscontroller.doprivileged(
new java.security.privilegedaction<void>() {
public void run() {
try {
fileoutputstream file =
new fileoutputstream(dottoslash(name) + ".class");
file.write(classfile);
file.close();
return null;
} catch (ioexception e) {
throw new internalerror(
"i/o exception saving generated file: " + e);
}
}
});
}
// 返回代理类的字节码
return classfile;
}
那么最终生成的代理类到底是什么样子呢,如下(省略了一下equals,hashcode,tostring等方法,只展示构造函数和add方法):
复制代码 代码如下:
public final class $proxy11 extends proxy implements service
{ // 构造方法,参数就是刚才传过来的myinvocationhandler类的实例
public $proxy11(invocationhandler invocationhandler)
{
super(invocationhandler);
}
/**
* 继承的add方法,重写,调用myinvocationhandler中的invoke方法
*/
public final void add()
{
try
{
// 实际上就是调用myinvocationhandler中的invoke方法
super.h.invoke(this, m3, null);
return;
}
catch(error _ex) { }
catch(throwable throwable)
{
throw new undeclaredthrowableexception(throwable);
}
}
}