一、静态代理
所谓 静态 就是程序运行 前 就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
缺陷:
需要为每一个被代理的类和方法都要重写一份。
代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,要为每一种方法都进行代理,在程序规模稍大时就无法胜任了,如果 接口增加一个方法,除了所以实现类需要实现这个方法外,所有代理类也需要实现此方法。
目标对象(被代理的类)
// 目标对象
public class Life implements ILife{
@Override
public void subway() {
System.out.println("乘地铁");
try {
Thread.sleep(1000*5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void shopping() {
System.out.println("购物");
try {
Thread.sleep(1000*10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void work() {
System.out.println("上班");
}
public void eat() {
System.out.println("吃饭");
}
}
接口
/**
* 基于接口的代理
* 声明了 需要被代理 的方法
* @author chao
*
*/
public interface ILife {
void subway();
void shopping();
void work();
}
代理类
/**
* 静态
* 代理类
* 缺陷:为每一个被代理的类和方法都要重写一份
* @author chao
*
*/
public class HealthCodeProxy implements ILife{
// 依赖
// 维持一个委托对象
ILife real;
public HealthCodeProxy(ILife real) {
this.real = real;
}
@Override
public void subway() {
System.out.println("乘地铁 :前:检查健康码");
real.subway();
}
@Override
public void shopping() {
System.out.println("购物 :前:检查健康码");
real.shopping();
}
@Override
public void work() {
System.out.println("上班 :前:检查健康码");
real.work();
}
}
测试调用
package static_proxy;
public class App {
public static void main(String[] args) {
ILife life ;
// 方案一,不代理
life = new Life();
life.shopping();
life.subway();
System.out.println("----------------------------");
// 方案二,代理
life = new Life();
life = new HealthCodeProxy(life);
life.shopping();
life.subway();
life.work();
}
}
查看控制台输出
二、动态代理
JDK 动态代理。
所谓 动态 就是在程序运行期间由JVM根据反射等机制动态的生成,代理类和委托类的关系是在程序运行时确定的。
相比于静态代理类:
与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke),这样接口方法数量比较多的时候,不需要像静态代理那样每一个方法进行中转。
定义一个 HealthCodeHandler 类,实现 InvocationHandler 接口,重写invoke 方法,在其中定义具体如何代理。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import static_proxy.ILife;
import static_proxy.Life;
/**
* 定义具体如何代理
*/
public class HealthCodeHandler implements InvocationHandler{
// 维持一个委托对象
ILife life;
public HealthCodeHandler(ILife life) {
this.life = life;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置
System.out.printf("%s 开启事务\n",method.getName());
// 方法调用,在特定的实例上
Object result = method.invoke(life, args);
// 后置
System.out.printf("%s 提交事务\n",method.getName());
return result;
}
}
测试调用
import java.lang.reflect.Proxy;
import static_proxy.ILife;
import static_proxy.Life;
public class App {
public static void main(String[] args) {
/** 参数列表
* 1)被代理的类,获得类加载器
* 2)要代理的接口 - 动态代理是基于接口的代理
* 3)处理器,具体描述了如何实现代理功能
*/
ILife proxy = (ILife)Proxy.newProxyInstance(
Life.class.getClassLoader(),
new Class[] {ILife.class},
new HealthCodeHandler(new Life()));
proxy.shopping();
proxy.subway();
}
}
查看控制台输出
三、cglib代理
JDK 动态代理 只能对实现了 接口 的类生成代理,而不能针对类。
cglib 是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,因为是继承关系,所以该类或方法最好不要声明成 final。