代理模式
一、介绍
代理模式:为其他对象(目标对象)创建一个代理对象,控制对目标对象的访问,在行使目标对象的方法时,可以增强其功能。也就是说代理模式其实就是增强了目标对象的功能,同时在使用这些功能的时候,将原来的目标对象隐藏起来。
举个例子:像玄幻小说中的拍卖行(代理对象),客户(目标对象或者称为被代理对象)要卖一个东西(做的事情或者理解为这个对象的方法),但是客户又不想让其他人知道这个东西是他卖的并且想让更多人来买这个东西,让这个东西卖个好价钱。这个时候,客户找到了拍卖行,拍卖行邀请了很多人来竞拍这件东西并且来竞拍的人都不知道物主是谁。这边,拍卖行不仅把东西卖了出去,还让东西卖了个好价钱并且隐藏了客户的身份。(也就是加强了方法)
二、java中的代理模式
2.1 静态代理模式
静态代理模式在使用时得定义接口或者父类,目标对象和代理对象都得实现或者继承它。我们用上面的例子写一段代码
接口:
public interface ProxyInterTest {
public void sellGoods();
}
目标对象(客户类):
/**
*实现ProxyInterTest 接口
*/
public class ProxyTargetTest implements ProxyInterTest {
@Override
public void sellGoods() {
System.out.println("客户卖东西");
}
}
代理对象(拍卖行类):
/**
*实现ProxyInterTest 接口
*/
public class ProxyObjectTest implements ProxyInterTest{
//传入目标对象
public ProxyTargetTest proxyTargetTest;
public ProxyObjectTest(ProxyTargetTest proxyTargetTest){
this.proxyTargetTest=proxyTargetTest;
}
@Override
public void sellGoods() {
System.out.println("拍卖行邀请人来竞拍");
proxyTargetTest.sellGoods();
System.out.println("拍卖结束,客户获得了更多的收获");
}
}
测试类:
public class ProxyMainTest {
public static void main(String[] args) {
ProxyTargetTest proxyTargetTest=new ProxyTargetTest();
ProxyObjectTest proxyObjectTest=new ProxyObjectTest(proxyTargetTest);
proxyObjectTest.sellGoods();
}
}
输出结果:
拍卖行邀请人来竞拍
客户卖东西
拍卖结束,客户获得了更多的收获
可以看到,在输出结果中客户卖东西之前,拍卖行邀请人来参加,也就是功能的加强。
2.2 动态代理模式
2.2.1 动态代理模式介绍
动态代理指的是,在程序运行的时候才去根据代码的“指示”去动态生成的,而不是像上面的静态模式,是我们在代码中已经定义好的。
java中代理模式有两种,一种是JDK代理模式,一种是Cglib代理模式。
2.2.2 JDK动态代理
JDK代理:实现了InvocationHandler接口,要求必须实现接口
接口:
public interface JdkProxyInter {
public void test();
}
目标对象(委托类):
/**
*实现了JdkProxyInter接口
*/
public class JdkProxyInstance implements JdkProxyInter{
@Override
public void test() {
System.out.println("jdk代理的委托类");
}
}
(关键!!!)代理对象:
public class JDKDemo implements InvocationHandler {
//传入了目标对象,Object是关键
private Object target;
public JDKDemo(Object target){
this.target=target;
}
//获取代理对象
public Object getProxy(){
/**
*返回代理对象
*this.getClass().getClassLoader():当前类的类加载器
*target.getClass().getInterfaces():目标对象实现的接口
*/
Object obj= Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
return obj;
}
//关键
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("进入jdk代理");
method.invoke(target,args);
System.out.println("结束jdk代理");
return null;
}
}
测试类:
public class JDKProxyMain {
public static void main(String[] args) {
JdkProxyInstance jdkProxyInstance=new JdkProxyInstance();
JDKDemo jdkDemo=new JDKDemo(jdkProxyInstance);
JdkProxyInter jdkProxyInter= (JdkProxyInter) jdkDemo.getProxy();
jdkProxyInter.test();
}
}
输出结果:
进入jdk代理
jdk代理的委托类
结束jdk代理
2.2.3 Cglib动态代理
Cglib代理:不需要实现接口,实现了MethodInterceptor接口
目标对象(委托类):
public class CglibProxyInstance{
public void test(){
System.out.println("cglib目标类");
}
}
(关键!!!)代理对象:
public class CglibDemo implements MethodInterceptor {
//传入目标对象
private Object target;
public CglibDemo(Object target){
this.target=target;
}
//返回代理对象
public Object getProxy(){
//实例化Enhancer类,Enhancer继承AbstractClassGenerator
Enhancer enhancer=new Enhancer();
//根据传入的对象为代理对象设置父类
enhancer.setSuperclass(target.getClass());
/**
*setCallback(Callback callback){this.setCallbacks(new Callback[]{callback});}
*CallBack有六个子接口
*/
enhancer.setCallback(this);//代理类的方法被调用时执行
return enhancer.create();
}
/**
*当代理对象的方法执行时触发
*o:代理对象
*method:被代理对象的方法
*objects:方法参数
*methProxy:代理对象方法
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("准备进入cglib代理");
methodProxy.invoke(target,objects);
System.out.println("结束cglib代理");
return null;
}
}
测试类:
public class CglibProxyMain {
public static void main(String[] args) {
CglibProxyInstance cglibProxyInstance=new CglibProxyInstance();
CglibDemo cglibDemo=new CglibDemo(cglibProxyInstance);
CglibProxyInstance cglibProxyInter2= (CglibProxyInstance) cglibDemo.getProxy();
cglibProxyInter2.test();
}
}
输出结果:
准备进入cglib代理
cglib目标类
结束cglib代理
总结:
静态代理和动态代理的主要区别:
静态代理在编译的时候就明确了代理对象,而动态代理不是,动态代理是在代码运行期间指定了代理对象。所以当要实现很多不同的类的代理的时候,就需要更多的代理类,这不适合业务的扩展。
动态代理中,JDK代理和Cglib代理的区别:
①前者只能代理实现了接口类,所以当要代理没实现接口的类的时候就可以用到后者;
②前者是基于接口实现的,而后者是基于继承的,它为目标对象生成一个子类。