代理模式,顾名思义就是给一个类找个代理,让这个代理类去做一些事情,比如某明星要开演唱会,在开演唱会之前要布置场景,在开演唱会之后要收拾东西,这些事情明星是不需要做的,交给它的代理去做。
在Java中也会有这样的代理类,Java中的代理模式有三种,静态代理,JDK动态代理,GCLib代理
静态代理
所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和目标类的关系在运行前就确定了
使用静态代理的条件是:目标对象(要被代理的对象)和代理对象需要实现相同的接口或者是继承相同父类
定义共同接口
public interface TargetInterFace {
void save();
}
定义目标类并实现接口
public class Target implements TargetInterFace {
@Override
public void save() {
System.out.println("Target 中的save 执行了");
}
}
定义代理类并实现接口
public class TargetStaticProxy implements TargetInterFace{
//注意 这个地方要注入目标类的接口,以实现不同类的执行
private TargetInterFace targetInterFace;
public TargetStaticProxy(TargetInterFace targetInterFace ){
this.targetInterFace = targetInterFace;
}
@Override
public void save() {
System.out.println("目标方法执行之前的逻辑");
targetInterFace.save();
System.out.println("目标方法执行之后的逻辑");
}
}
测试类
public class ProxyTest {
public static void main(String[] args) {
//创建目标对象
Target target = new Target();
//创建代理类,并把目标对象交给代理类去代理
TargetStaticProxy targetStaticProxy = new TargetStaticProxy(target);
//通过执行代理的方法 从而去执行目标方法
//执行结果
//目标方法执行之前的逻辑
//Target 中的save 执行了
//目标方法执行之后的逻辑
targetStaticProxy.save();
}
}
从这个小例子可以看出,静态代理使用有限制, 因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护
JDK动态代理
动态代理的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以在运行前并不存在代理类的字节码文件
使用条件,目标类同样需要实现接口,代理类则不需要实现接口,而且代理类是由JVM动态的在内存中构建代理对象
目标类不变
public class Target implements TargetInterFace {
@Override
public void save() {
System.out.println("Target 中的save 执行了");
}
}
代理类
public class TargetDynamicProxy {
//注意 这个地方要注入目标类的接口,以实现不同类的执行
private TargetInterFace targetInterFace;
// 这里定义一个接口,这个接口里面定义一些代理类的执行逻辑
private Advice advice;
public TargetDynamicProxy(TargetInterFace targetInterFace,Advice advice) {
this.targetInterFace = targetInterFace;
this.advice = advice;
}
public Object getProxyInstance() {
//创建代理类对象
Object proxyInstance = Proxy.newProxyInstance(
targetInterFace.getClass().getClassLoader(),//类加载器
targetInterFace.getClass().getInterfaces(),//目标类实现接口
new MyInvocationHandler()//事件处理器
);
return proxyInstance;
}
class MyInvocationHandler implements InvocationHandler {
/**
* Processes a method invocation on a proxy instance and returns the result.
* This method will be invoked on an invocation handler when a method is invoked
* on a proxy instance that it is associated with.
* 处理代理对象上的方法调用并返回结果。当在与之关联的代理实例上调用方法时,将在调用处理程序上调用此方法。
* 每次代理对象调用方法都会执行这个回调
*
* 回调函数
* @param proxy 代理类
* @param method 被代理的方法
* @param args 被代理方法的参数数组
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// System.out.println("目标调用之前");替换成advice
advice.beforeMethod();
//执行目标对象方法,返回方法的返回值
Object invoke = method.invoke(targetInterFace, args);
// System.out.println("目标调用之后"); 替换成advice
advice.afterMethod();
return invoke;
}
}
}
添加一个切面类,里面封装执行逻辑,也就是spring AOP 的原理模拟
public interface Advice {
void beforeMethod();
void afterMethod();
}
测试类
public class ProxyTest {
public static void main(String[] args) {
//创建目标对象
Target target = new Target();
//创建切面类
Advice advice = new Advice() {
@Override
public void beforeMethod() {
System.out.println("我是动态代理 目标方法执行前");
}
@Override
public void afterMethod() {
System.out.println("我是动态代理 目标方法执行后");
}
};
//创建代理类,并把目标对象交给代理类去代理
TargetDynamicProxy dynamicProxy = new TargetDynamicProxy(target, advice);
TargetInterFace proxyInstance = (TargetInterFace) dynamicProxy.getProxyInstance();
//执行结果
//我是动态代理 目标方法执行前
//Target 中的save 执行了
//我是动态代理 目标方法执行后
proxyInstance.save();
}
}
Gclib代理
Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展。
使用条件:目标类和代理类都可以不用实现接口,目标类不能是final的,目标对象的代理方法也不能是final或static,需要引入GCLIb.jar
目标类
public class Person {
public void speak() {
System.out.println("目标类说话。。。。");
}
}
代理类
public class GclibProxy implements MethodInterceptor {
private Person person;
private Advice advice;
public GclibProxy(Person person, Advice advice) {
this.person = person;
this.advice = advice;
}
/**
* 通过GCLib实现
*
* @return
*/
public Object getGCLibProxyInstance() {
//1.工具类
Enhancer en = new Enhancer();
//2.设置目标父类
en.setSuperclass(person.getClass());
//3.设置回调函数 intercept
en.setCallback(this);
//4.创建子类(代理对象)
return en.create();
}
@Override
public Object intercept(Object target, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
advice.beforeMethod();
//执行目标对象的方法
Object o = method.invoke(target, objects);
advice.afterMethod();
return o;
}
}
测试类
public class ProxyTest {
public static void main(String[] args) {
//创建目标对象
Target target = new Target();
//创建切面类
Advice advice = new Advice() {
@Override
public void beforeMethod() {
System.out.println("我是动态代理 目标方法执行前");
}
@Override
public void afterMethod() {
System.out.println("我是动态代理 目标方法执行后");
}
};
//创建代理类,并把目标对象交给代理类去代理
TargetDynamicProxy dynamicProxy = new TargetDynamicProxy(target, advice);
TargetInterFace proxyInstance = (TargetInterFace) dynamicProxy.getProxyInstance();
//执行结果
//我是动态代理 目标方法执行前
//Target 中的save 执行了
//我是动态代理 目标方法执行后
// proxyInstance.save();
//
Person person = new Person();
GclibProxy gclibProxy = new GclibProxy(person, advice);
Person personProxyInstance = (Person) gclibProxy.getGCLibProxyInstance();
personProxyInstance.speak();
}
}