一、什么叫代理?
广义上,代理指受委托代表当事人进行某种活动,和现实生活中的中介含义几乎一致。
Java中,代理指创建一个对象的代理对象,代表该对象执行相关方法。Java代理分为静态代理和动态代理。
二、代理场景
相亲公司安排一个男孩和一个女孩相亲,由于男孩自己不太想去,现在需要找一个替代者,如何用java实现呢?
三、实现模式1——静态代理
代理模式是常用设计模式的一种,我们在软件设计时常用的代理一般是指静态代理,也就是在代码中显式指定的代理。
静态代理由 业务实现类、业务代理类 两部分组成。业务实现类 负责实现主要的业务方法,业务代理类负责对调用的业务方法作拦截、过滤、预处理,主要是在方法中首先进行预处理动作,然后调用业务实现类的方法,还可以规定调用后的操作。我们在需要调用业务时,不是直接通过业务实现类来调用的,而是通过业务代理类的同名方法来调用被代理类处理过的业务方法。
1、定义男孩接口
package proxydemo.book.facade;
/**
* 男孩facade接口类
* @author 0200759
*/
public interface IBoyFacade {
/**
* 新增书籍接口
*/
public void date();
}
2、定义男孩实现类
package proxydemo.book.facade.impl;
import proxydemo.book.facade.IBoyFacade;
/**
* 男孩facade实现类
* @author 0200759
*
*/
public class BoyFacade implements IBoyFacade{
@Override
public void date() {
System.out.println("I'm dating with a girl now!");
}
}
3、定义静态代理类
package proxydemo.book.staticproxy;
import proxydemo.book.facade.IBoyFacade;
import proxydemo.book.facade.impl.BoyFacade;
public class BoyStaticProxy implements IBoyFacade{
private BoyFacade bookFacade;
/**
* 构造函数,定义bookFacade
* @param bookFacade
*/
public BoyStaticProxy(BoyFacade bookFacade){
this.bookFacade = bookFacade;
}
@Override
public void date() {
//调用成员变量bookFacade的方法
bookFacade.date();
System.out.println("I'm dating a girl instead of you");
}
}
实际上就是把目标对象作为代理类的成员变量,代理类和目标类实现同一接口,代理类的方法通过成员变量访问目标对象的方法
4、定义测试类
package proxydemo.book.staticproxy;
import proxydemo.book.facade.impl.BoyFacade;
/**
* 静态代理测试类
* @author 0200759
*
*/
public class BoyStaticProxyTest {
public static void main(String[] args) {
//创建目标对象
BoyFacade boyFacade = new BoyFacade();
//创建代理对象
BoyStaticProxy bookStaticProxy = new BoyStaticProxy(boyFacade);
//通过代理对象执行目标对象的方法
bookStaticProxy.date();
}
}
四、实现模式2——JDK动态代理
静态代理已经实现了替代男孩相亲的方案,可相亲公司既不想暴露自己的身份信息也不想每次都定义一个代理类,该如何解决呢?
1、定义jdk动态代理类
package proxydemo.book.dynamicproxy.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 男孩jdk动态代理类
* @author 0200759
*
*/
public class BoyJdkProxy implements InvocationHandler {
private Object target;//这其实业务实现类对象,用来调用具体的业务方法
/**
* 绑定业务对象并返回一个代理类
*/
public Object bind(Object target) {
this.target = target; //接收业务实现类对象参数
//通过反射机制,创建一个代理类对象实例并返回。用户进行方法调用时使用
//创建代理对象时,需要传递该业务类的类加载器(用来获取业务实现类的元数据,在包装方法是调用真正的业务方法)、接口、handler实现类
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this); }
/**
* 包装调用方法:进行预处理、调用后处理
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result=null;
System.out.println("预处理操作——————");
//调用真正的业务方法
result=method.invoke(target, args);
System.out.println("调用后处理——————");
return result;
}
}
2、测试类
package proxydemo.book.dynamicproxy.jdk;
import proxydemo.book.facade.IBoyFacade;
import proxydemo.book.facade.impl.BoyFacade;
/**
* 男孩jdk代理测试类
* @author 0200759
*
*/
public class BoyJdkProxyTest {
public static void main(String[] args) {
//创建目标对象
BoyFacade boyFacadeImpl = new BoyFacade();
//创建代理对象
BoyJdkProxy boyJdkProxy = new BoyJdkProxy();
//代理对象绑定目标对象生成代理实例
IBoyFacade boyFacade = (IBoyFacade) boyJdkProxy.bind(boyFacadeImpl);
//执行目标方法
boyFacade.date();
}
}
五、 实现模式3——cglib代理
jdk代理满足相亲公司的基本需求,可相亲公司觉得必须定义一个相亲的接口方法类太麻烦。。。
1、实现MethodInterceptor生成代理类
package proxydemo.book.dynamicproxy.cglib;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* 男孩Cglib代理
* @author 0200759
*
*/
public class BoyCglibProxy implements MethodInterceptor{
private Object target;//业务类对象,供代理方法中进行真正的业务方法调用
//相当于JDK动态代理中的绑定
public Object getInstance(Object target) {
this.target = target; //给业务对象赋值
Enhancer enhancer = new Enhancer(); //创建加强器,用来创建动态代理类
enhancer.setSuperclass(this.target.getClass()); //为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
//设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
enhancer.setCallback(this);
// 创建动态代理类对象并返回
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("预处理——————");
Object object = proxy.invokeSuper(obj, args); //调用业务类(父类中)的方法
System.out.println("调用后操作——————");
return object;
}
}
2、测试类
package proxydemo.book.dynamicproxy.cglib;
import proxydemo.book.facade.impl.BoyFacade;
/**
* 男孩Cglib代理测试类
* @author 0200759
*
*/
public class BoyCglibProxyTest {
public static void main(String[] args) {
//创建目标对象
BoyFacade boyFacade = new BoyFacade();
//创建代理对象
BoyCglibProxy boyCglibProxy = new BoyCglibProxy();
//生成代理实例
BoyFacade boyCglibFacade = (BoyFacade) boyCglibProxy.getInstance(boyFacade);
//执行目标对象的方法
boyCglibFacade.date();
}
}
六、总结
静态代理是通过在代码中显式定义一个业务实现类作为代理类,在代理类中对同名的业务方法进行包装,用户通过代理类调用被包装过的业务方法;
JDK动态代理是通过接口中的方法名,在动态生成的代理类中调用业务实现类的同名方法;
CGlib动态代理是通过继承业务类,生成的动态代理类是业务类的子类,通过重写业务方法进行代理;