代理模式为另外一个对象提供一个替身或占位符以控制对这个对象的访问
举个例子来说明代理的作用: 一般我们想邀请明星来当我们的代言人,我们并不能直接联系到明星,而是通过其经纪人,来告诉经纪人我们需要和明星进行合作,然后通过经纪人来转达给明星。明星只需要做好代言工作就好,其他繁琐的事情就交于经纪人就可以。这里的经经纪人就是一个代理对象,明星就是一个目标对象
代理分为静态代理和动态代理
来看一个静态代理的例子
假设现在有一个商家想找一个明星拍一则广告,这个商家找到明星的经纪人就广告费合同之类的进行谈判,谈判通过后明星就进行广告拍摄,广告拍摄完毕后,再由商家给经纪人付款,在这个过程中,经纪人就是于明星的代理,负责与商家接触,并且与明星进行沟通,而明星才是最终拍广告的人
1 创建一个拍广告的动作主题
public interface Subject {
void advertise();
}
2 明星本人执行拍广告行为
public class RealStar implements Subject{
@Override
public void advertise() {
System.out.println("------明星拍广告------");
}
}
3 经纪人负责谈判,收付款之类的行为
public class Proxy implements Subject{
Subject subject;
public Proxy(Subject subject) {
this.subject = subject;
}
@Override
public void advertise() {
System.out.println("------经纪人谈判------");
subject.advertise();
System.out.println("------经纪人收费------");
}
}
4 测试
public static void main(String[] args) {
// 明星
Subject subject = new RealStar();
// 经纪人
Subject proxy = new Proxy(subject);
// 拍广告
proxy.advertise();
}
总结:静态代理可以在不改变对象的前提下扩展新功能,但是静态代理必须自己实现代理类实现相应的代理逻辑
Java动态代理允许我们在运行时动态生成代理类而无需手动编写代码实现
Java动态代理有两种实现方式
JDK动态代理
利用反射机制生成一个实现代理接口的匿名类,被代理的对象必须实现接口
Cglib动态代理
利用asm第三方开源包,通过修改字节码生成子类来处理,不要求对象必须实现接口,可以对非接口类方法进行代理
仍然以第2节例子来看通过JDK动态代理和Cglib动态代理如何实现
2.1 和 2.1 Subject 接口 还有明星本人实现类不变
1 实现InvocationHandler,用于创建代理类
public class JdkProxyInvocationHandler implements InvocationHandler {
private Object target;
/**
*
* @param o 代理对象
* @param method 代理方法
* @param objects 方法参数列表
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
System.out.println("------经纪人谈判------");
Object result = method.invoke(target,objects);
System.out.println("------经纪人收费------");
return result;
}
//定义获取代理对象方法
public Object getJDKProxy(Object targetObject){
//为目标对象target赋值
this.target = targetObject;
//JDK动态代理只能针对实现了接口的类进行代理,newProxyInstance 函数所需参数就可看出
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
}
}
2 测试
public static void main(String[] args) {
Subject star = new RealStar();
JdkProxyInvocationHandler jdkProxyInvocationHandler = new JdkProxyInvocationHandler();
Subject proxy = (Subject) jdkProxyInvocationHandler.getJDKProxy(star);
proxy.advertise();
}
如上例子所示,实现JDK动态代理不需要手动去实现一个代理类,代理通过Proxy.newProxyInstance()方法生成,当调用被代理方法时会调用JdkProxyInvocationHandler 的invoke方法进行处理
2.1 和 2.1 Subject 接口 还有明星本人实现类不变
1 实现MethodInterceptor用于实现代理类
public class CglibProxyMethodInterceptor implements MethodInterceptor {
private Object target;//需要代理的目标对象
/**
*
* @param obj 代理对象
* @param method 代理方法
* @param arr 参数列表
* @param proxy
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object obj, Method method, Object[] arr, MethodProxy proxy) throws Throwable {
System.out.println("------经纪人谈判------");
Object invoke = method.invoke(target, arr);
System.out.println("------经纪人收费------");
return invoke;
}
/**
*
* @param objectTarget 目标对象
* @return
*/
public Object getCglibProxy(Object objectTarget){
//为目标对象target赋值
this.target = objectTarget;
Enhancer enhancer = new Enhancer();
//设置父类,因为Cglib是针对指定的类生成一个子类,所以需要指定父类
enhancer.setSuperclass(objectTarget.getClass());
enhancer.setCallback(this);// 设置回调
Object result = enhancer.create();//创建并返回代理对象
return result;
}
}
2 测试
public static void main(String[] args) {
Subject star = new RealStar();
CglibProxyMethodInterceptor cglibProxyMethodInterceptor = new CglibProxyMethodInterceptor();
Subject proxy = (Subject) cglibProxyMethodInterceptor.getCglibProxy(star);
proxy.advertise();
}
如上例子所示,实现Cglib动态代理也不需要手动去实现一个代理类,代理会通过asm修改class文件字节码动态生成