一.什么是代理?
代理是不直接通过代理类访问方法,而是通过被代理类的代理对象,间接访问代理类里面的方法。
就好比:(被代理类)相亲女——婚介所(代理类)这种模式,直接通过婚介所(代理类),知道相亲女的择偶要求(被代理类)。
1.代理有几种?
一.代理分为静态代理和动态代理
静态代理:是在编译期时,知道哪个是被代理的类,那么使用类的静态代理。
动态代理:在编译期时,不知道哪个是被代理的类,那么使用类的动态代理。
二.静态代理的实现
创捷一个接口类(女孩)
public interface Girl {
void date();
void watchMovie();
}
王美丽,重写方法(作为被代理类)
public class WangMeiLi implements Girl {
@Override
public void date() {
System.out.println("王美丽说:跟你约会好开心啊");
}
@Override
public void watchMovie() {
System.out.println("王美丽说:这个电影我不喜欢看");
}
}
婚介所(代理类),传入被代理类girl,重写date和watch方法,调用被代理类girl里面的方法(此步骤实际为增强此方法内容)
public class hunjiesuo implements Girl{
private Girl girl;
public hunjiesuo(Girl girl) {
this.girl=girl;
}
@Override
public void date() {
System.out.println("准备约会");
girl.watchMovie();
}
@Override
public void watchMovie() {
System.out.println("准备看电影");
girl.watchMovie();
}
}
测试此方法
public class Demo {
public static void main(String[] args) {
Girl girl= new WangMeiLi();
hunjiesuo hjs= new hunjiesuo(girl);
hjs.date();
hjs.watchMovie();
}
}
输出结果
D:\Java\jdk-13.0.1\bin\java.exe -Dvisualvm.id=27764171229000 "-javaagent:D:\idea\IntelliJ IDEA 2020.1\lib\idea_rt.jar=49787:D:\idea\IntelliJ IDEA 2020.1\bin" -Dfile.encoding=UTF-8 -classpath D:\IdeaProjects\basic-code\out\production\day04-code;C:\Users\Administrator\.m2\repository\org\junit\jupiter\junit-jupiter\5.4.2\junit-jupiter-5.4.2.jar;C:\Users\Administrator\.m2\repository\org\junit\jupiter\junit-jupiter-api\5.4.2\junit-jupiter-api-5.4.2.jar;C:\Users\Administrator\.m2\repository\org\apiguardian\apiguardian-api\1.0.0\apiguardian-api-1.0.0.jar;C:\Users\Administrator\.m2\repository\org\opentest4j\opentest4j\1.1.1\opentest4j-1.1.1.jar;C:\Users\Administrator\.m2\repository\org\junit\platform\junit-platform-commons\1.4.2\junit-platform-commons-1.4.2.jar;C:\Users\Administrator\.m2\repository\org\junit\jupiter\junit-jupiter-params\5.4.2\junit-jupiter-params-5.4.2.jar;C:\Users\Administrator\.m2\repository\org\junit\jupiter\junit-jupiter-engine\5.4.2\junit-jupiter-engine-5.4.2.jar;C:\Users\Administrator\.m2\repository\org\junit\platform\junit-platform-engine\1.4.2\junit-platform-engine-1.4.2.jar DD1.Demo
准备约会
王美丽说:这个电影我不喜欢看
准备看电影
王美丽说:这个电影我不喜欢看
Process finished with exit code 0
结论:此方法是不改变被代理类的基础上,通过代理类扩展,进行功能的延伸与增加。要注意的是,代理类要与被代理类对象实现同一个接口。
三.动态代理的实现
静态代理时,我们手动创建代理类hunjiesuo,而动态代理时在程序运行时,自动生成代理类,并实现Girl接口。
public interface Girl {
void date();
void watchMovie();
}
public class WangMeiLi implements Girl {
@Override
public void date() {
System.out.println("王美丽说:跟你约会好开心啊");
}
@Override
public void watchMovie() {
System.out.println("王美丽说:这个电影我不喜欢看");
}
}
前两个步骤相同,不同之处在于代理类的实现,
public class WangMeiLiProxy implements InvocationHandler {
创建代理对象的类需要继承 InvocationHandler
private Girl girl;
public WangMeiLiProxy(Girl girl){
this.girl=girl;
}
重写接口InvocationHandler的invoke方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("嘻嘻嘻嘻");
Object ret= method.invoke(girl,args);
return ret;
}
创建代理对象(Proxy.newProxyInstance)
第一个参数是类加载器,第二个参数是被代理类实现的接口,第三个参数是 InvocationHandler
public Object getProxyInstance(){
return Proxy.newProxyInstance(girl.getClass().getClassLoader(),girl.getClass().getInterfaces(),this);
}
}
测试方法
public class test {
public static void main(String[] args) {
Girl girl = new WangMeiLi();
WangMeiLiProxy wa = new WangMeiLiProxy(girl);
Girl gir = (Girl) wa.getProxyInstance();
gir.watchMovie();
当wa.getProxyInstance时,开始创建代理类对象,此时传入girl里面的方法,下面是生产代理对象时,里面的编码(不完整,只取部分)
public class OProxyO extends Proxy implements Girl {
//girl传入的方法,用m1,2.3接收
private static Method m1;
private static Method m2;
private static Method m3;
public final String watchMovie(String varl) throws {
super.h是InvocationHandler,m3是传入的方法,即watchMovie
try {
return (String)super.h.invoke(this,m3,new Object[] {varl})
}catch (RuntimeException| Error var3){
throw var3;
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
代理对象创建后,执行watchMoive方法,此时里面会执行invoke方法,而在WangMeiLiProxy中,我们重写了invoke方法,此中的Object ret= method.invoke(girl,args) 是执行WangMeiLi的wachMoive方法
测试结果如下
嘻嘻嘻嘻
王美丽说:这个电影我不喜欢看
Process finished with exit code 0
结论:代理对象程序是在运行时,调用getProxyInstance()方法,通过类加载加载,才会产生的。当调用代理对象里面的方法,此方法会在实现自己的方法的同时,又回调被代理对象的方法,从而达到增强和扩展的目的。