代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。
比如我们想请一个电影明星(目标类)演电影,不直接找明星来,而是联系他的经纪人(代理类),代理会在明星表演的基础上增加功能,比如安排行程、谈薪资、收钱等。
1. 静态代理
在静态代理中,要求目标类和代理类实现同一个接口或者继承同一个父类。
//演员接口
public interface Actor {
void play();//表演
}
//电影明星类
public class MovieActor implements Actor {
@Override
public void play() {
System.out.println("电影演员演电影");
}
}
//经纪人类
public class Agent implements Actor{
private Actor actor;//经纪人代理的明星
public Agent() {
super();
this.actor = new MovieActor();
}
@Override
public void play() {
System.out.println("经纪人安排酒店住宿谈薪资");
actor.play();//目标对象的方法
System.out.println("经纪人收钱");
}
}
//测试方法
public static void main(String[] args) {
Actor agent=new Agent();//通过经纪人去联系
agent.play();
}
测试方法中不直接使用演员类,而是通过经纪人的类,我们在演员表演的基础上增加了安排酒店和收钱的环节。它的好处是在不改变目标类的基础上增加额外的功能。但缺点是代理类和目标类必须实现同样的接口,当接口中增加方法时要同时修改目标类和代理类。
2. 动态代理
2.1 JDK代理
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKProxy {
private MovieActor target;
public JDKProxy() {
super();
this.target = new MovieActor();
}
public Object getProxyInstance() {
Class clazz = target.getClass();//使用反射
return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("谈薪资");
// 执行目标对象方法
Object returnValue = method.invoke(target, args);
System.out.println("收钱");
return returnValue;
}
});
}
}
// 测试方法
public static void main(String[] args) {
JDKProxy proxy = new JDKProxy();
Actor actor=(Actor) proxy.getProxyInstance();
actor.play();
}
2.2 Cglib代理
如果目标对象没有实现接口,就不能使用JDK代理,可以使用Cglib代理,也叫做子类代理。使用Cglib需要引入额外的jar包。
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CglibProxy implements MethodInterceptor{
//维护目标对象
private Object target;
public CglibProxy() {
this.target = new MovieActor();
}
//给目标对象创建一个代理对象
public Object getProxyInstance(){
Enhancer en = new Enhancer();//1.工具类
en.setSuperclass(target.getClass());//2.设置父类
en.setCallback(this);//3.设置回调函数
return en.create(); //4.创建子类(代理对象)
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("谈薪资...");
//执行目标对象的方法
Object returnValue = method.invoke(target, args);
System.out.println("收钱...");
return returnValue;
}
}
// 测试方法
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
Actor actor=(Actor) proxy.getProxyInstance();
actor.play();
}