代理模式(Proxy Pattern),23个经典模式中的一个,又称之为委托模式,就是为目标对象提供了一个代理,这个代理可以控制对目标对象的访问。代理对象可以在被代理对象的基础上添加额外功能。
为什么要使用代理?
某人要找对象,但是由于某些原因(如工作太忙)不能直接去找,于是委托一个中介机构去完成这一过程,如婚姻介绍所,在这里婚姻介绍所就是一个代理,与此相类似的还有房屋中介、职业中介,它们充当的都是一个代理的角色。所谓代理,就是一个人或者一个机构代表另一个或者另一个机构采取行动。
静态代理
静态代理要求被代理类和代理类同时实现相应的一套接口,通过代理类调用重写接口的方法,实际上调用的是原始对象的同样的方法。
代码实现:
TargetInteface 接口
public interface TargetInteface {
void method1();
void method2();
int method3(Integer i);
}
被代理类
public class Target implements TargetInteface {
@Override
public void method1() {
System.out.println("method1 running ...");
}
@Override
public void method2() {
System.out.println("method2 running ...");
}
@Override
public int method3(Integer i) {
System.out.println("method3 running ...");
return i;
}
}
代理类
public class TargetProxy implements TargetInteface {
@Override
public void method1() {
System.out.println("执行方法前...");
new Target().method1();
System.out.println("执行方法后...");
}
@Override
public void method2() {
System.out.println("执行方法前...");
new Target().method2();
System.out.println("执行方法后...");
}
@Override
public int method3(Integer i) {
System.out.println("执行方法前...");
int method3 = new Target().method3(i);
System.out.println("执行方法后...");
return method3;
}
}
测试类
public class TargetUser {
public static void main(String[] args) {
TargetInteface target = new TargetProxy();
target.method1();
System.out.println("-----------------------------");
target.method2();
System.out.println("-----------------------------");
System.out.println(target.method3(3));
}
}
执行结果如下
静态代理还是比较容易理解的,代理类在执行被代理对象方法前后执行了打印操作,增强了功能。这便是代理模式的用途之一。
动态代理
假如一个类需要代理许多的对象,那么这个代理类将会同时实现许多个接口,这种办法不易被使用,所有就加入了新的代理模式—动态代理。
动态代理的代理类并不需要去实现各个接口,提供了一种新的代理形式。
动态代理有俩种实现方式:jdk代理和cglib代理
代码实现:
(1)jdk代理
TargetInteface 接口
public interface TargetInteface {
void method1();
void method2();
int method3(Integer i);
}
被代理类
public class Target implements TargetInteface {
@Override
public void method1() {
System.out.println("method1 running ...");
}
@Override
public void method2() {
System.out.println("method2 running ...");
}
@Override
public int method3(Integer i) {
System.out.println("method3 running ...");
return i;
}
}
代理类
public class TargetProxy {
public static <T> Object getTarget(T t) {
return Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// proxy就是目标对象t,method就是调用目标对象中方法,args就是调用目标对象中方法的参数。
//比如说:代理对象.method1(),这时proxy就是目标类,method1就是method,args就是method1方法参数。
System.out.println("执行方法前...");
Object invoke = method.invoke(t, args);
System.out.println("执行方法后...");
return invoke;
}
});
}
}
测试类
public class TargetUser {
public static void main(String[] args) {
TargetInteface target = (TargetInteface) TargetProxy.getTarget(new Target());
target.method1();
System.out.println("-----------------------------");
target.method2();
System.out.println("-----------------------------");
System.out.println(target.method3(3));
}
}
结果如下
可以看到这个执行结果和上面哪一种是一样的。但是jdk代理代理类中并不需要去实现接口。而是采用了Proxy类的newProxyInstance()方法,仔细观察这个方法,可以看到方法参数内实现了一个匿名类,这是一个调用处理器。
调用处理器是实现了 InvocationHandler 接口的类对象,在这个接口中只有一个方法:
Object invoke(Object proxy, Method method, Object [] args)
无论何时调用代理对象的方法,调用处理器的 invoke 方法都会被调用, 并向其传递Method 对象和原始的调用参数。 调用处理器通过反射的形式调用被代理类的方法。
(2)cglib代理
cglib代理并不需要接口,而是采用类的方式去实现。可以说jdk代理是对实现接口的类的代理,而cglib代理是针对类的代理。
代码实现:
被代理类
public class Target {
public void method1() {
System.out.println("method1 running ...");
}
public void method2() {
System.out.println("method2 running ...");
}
public int method3(Integer i) {
System.out.println("method3 running ...");
return i;
}
}
代理类
public class TargetProxy {
static <T> Object getProxy(T t) {
Enhancer en = new Enhancer(); //帮我们生成代理对象
en.setSuperclass(t.getClass());//设置要代理的目标类
en.setCallback(new MethodInterceptor() {//代理要做什么
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("执行方法前。。。");
//调用原有方法
Object invoke = methodProxy.invokeSuper(object, args);
// Object invoke = method.invoke(t, args);// 作用等同与上面。
System.out.println("执行方法后。。。");
return invoke;
}
});
return en.create();
}
}
测试类
public class TargetUser {
public static void main(String[] args) {
Target target = (Target) TargetProxy.getProxy(new Target());
target.method1();
target.method2();
target.method3(1);
}
}
执行结果
在代码中可以看出cglib代理与jdk代理不同之处在于是否有接口需要实现,并且cglib在代理实现的方式上也有所不同,cglib引用了Enhancer对象,通过Enhancer对象帮我们生成代理对象,用Enhancer的setCallback()方法执行被代理类的方法。
这里实现了MethodInterceptor接口,该接口中只有一个方法:
Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable;
方法的调用会被转移到这个方法中执行。
总结一下cglib代理实现步骤:
Cglib子类代理实现方法:
1.需要引入cglib的jar文件,但是Spring的核心包中已经包括了Cglib功能,所以直接引入pring-core-3.2.5.jar即可.
2.引入功能包后,就可以在内存中动态构建子类
3.代理的类不能为final,否则报错
4.目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法.