静态代理&动态代理
静态代理
我们可以使用类的包装来实现静态代理
接口
public interface Flyable {
void fly();
String eat(String food);
}
实现类(目标类)
public class Bird implements Flyable {
@Override
public void fly() {
System.out.println("Bird is flying...");
try {
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public String eat(String food) {
// TODO Auto-generated method stub
System.out.println("Bird is eating..."+food);
return "eat返回值:吃饱了";
}
}
静态代理类
public class BirdTimeProxy implements Flyable {//在fly方法前后执行一个计时功能
private Flyable flyable;
public BirdTimeProxy(Flyable flyable) {
this.flyable = flyable;
}
@Override
public void fly() {
long start = System.currentTimeMillis();
System.out.println("time-start:"+start);
flyable.fly();
long end = System.currentTimeMillis();
System.out.println("time-over:"+end);
System.out.println("Fly time = " + (end - start));
}
@Override
public String eat(String food) {
return flyable.eat(food);
}
}
可以看出,这里使用了包装的方法
静态代理测试
@Test
public void fun(){
Bird bird = new Bird();
BirdTimeProxy p = new BirdTimeProxy(bird);
p.fly();
p.eat("苹果");
}
结果:
time-start:1590666159624
Bird is flying...................
time-over:1590666160072
Fly time = 448
Bird is eating.................苹果
静态代理的缺点
1.接口中如果有很多个方法,那么这些方法都必须在包装类里面实现,会很麻烦
2.一个代理对象只能代理接口的一个类,如果上述flyable接口有其他的类,比如鸟、昆虫、飞机等等,就需要一个个地去为他们实现代理类,过于麻烦
3.如果接口要增加某个方法,那么不仅实现类要增加方法,相应的代理也要增加方法,就麻烦
动态代理
public static Object newProxyInstance(
ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
主要是使用这个方法来生成动态代理,
第一个参数是类加载器,
第二个参数是要目标类的接口(一个类不止实现一个接口),
第三个参数就是InvocationHandler
的实现类;
其中InvocationHandler 的实现类需要实现的函数就是public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
而这里的Object proxy表示的就是目标类,也就是被代理的类
Method method表示正在执行的方法
Object[] args)表示的是方法传进来的参数
实现一
@Test
public void fun4(){
Flyable flyable=(Flyable) Proxy.newProxyInstance(demo.class.getClassLoader(),
Bird.class.getInterfaces(),
new InvocationHandler() {
//这里生成了InvocationHandler接口的一个匿名类
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//proxy:在这里就没用到,按理说应该是method.invoke(proxy, args);但是下面对应的是new 类
//method:代表正在执行的方法
//args:代表正在执行的方法中的参数
//Object:代表方法执行完毕之后的返回值
System.out.println("正在invoke"+method.getName());
//代表每个方法执行完毕之后返回对象
Object obj=null;
if(method.getName().equalsIgnoreCase("fly")){
System.out.println("起飞前做一些准备");
//打印args中的内容
System.out.println("args:"+Arrays.toString(args));
obj=method.invoke(new Bird(), args);//执行当前的方法
System.out.println("起飞后做一些放松");
}else{
System.out.println("args:"+Arrays.toString(args));
obj=method.invoke(new Bird(), args);//执行当前的方法
}
return obj;
}
});
flyable.fly();
flyable.eat("苹果");
}
测试结果
正在invoke eat
args:[青菜]
Bird is eating.................青菜
正在invoke fly
起飞前做一些准备
args:null
Bird is flying...................
起飞后做一些放松
缺点
可以看到,这样生成的代理,每次代理目标类的方法时,调用 method的public Object invoke(Object obj, Object... args)
都要再new一个目标类,这显然不合理
改进思路
所以可以通过包装的方式,包装类实现InvocationHandler,将目标类作为包装类的一个私有变量,并且重写public Object invoke(Object proxy, Method method, Object[] args)
方法,在这个方法内部调用method的invoke方法时,只要使用一下私有变量就可以啦,其他的和方式一一致。
方式二
public class MyInvocationHandler implements InvocationHandler{
private Object target;
public MyInvocationHandler() {
super();
}
public MyInvocationHandler(Object target) {
super();
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {//method:代表正在执行的方法
//args:代表正在执行的方法中的参数
//Object:代表方法执行完毕之后的返回值
System.out.println("正在invoke"+method.getName());
//代表每个方法执行完毕之后返回对象
Object obj=null;
if(method.getName().equalsIgnoreCase("fly")){
System.out.println("起飞前做一些准备");
//打印args中的内容
System.out.println("args:"+Arrays.toString(args));
obj=method.invoke(target, args);//执行当前的方法
System.out.println("起飞后做一些放松");
}else{
System.out.println("args:"+Arrays.toString(args));
obj=method.invoke(target, args);//执行当前的方法
}
return obj;
}
}
测试
@Test
public void fun5(){
Flyable target=new Bird();//target类
InvocationHandler invocationHandler=new MyInvocationHandler(target);//改写的
Flyable flyableProxy=(Flyable) Proxy.newProxyInstance(demo.class.getClassLoader(), Bird.class.getInterfaces(), invocationHandler);
flyableProxy.eat("青菜");
flyableProxy.fly();
}
上一篇: 代理-->静态代理&动态代理
下一篇: 多线程、进程锁机制的作用