代理,其实在日常生活中很常见。像房屋的拥有者和中介,明星和经纪人,供货商和代理商。其中中介、经纪人、代理商的工作就可以看做是一种代理。
在Java软件开发过程中,可能经常会用到代理模式,如Spring的Aop等。代理模式,其实就是控制对实际对象(被代理对象)的访问。而代理模式又分为静态代理和动态代理。(UML图不会画,从网上找来的)
静态代理
在编译期就已经确立好代理对象的就是静态代理。
下面我以明星和经纪人举例,介绍静态代理。
首先,需要定义一个接口,定义一些功能(即方法),代理类和被代理类都需要实现这个接口
// 接口(代理类和被代理类均要实现此接口)
public interface Person {
void perform();
}
// 被代理类(演员)
public class Actor implements Person{
private String name;
public Actor(String name) {
this.name = name;
}
public void perform() {
System.out.println("我是演员" + this.name +",我要开始表演了。。");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
// 代理类(经纪人)
public class Agent implements Person{
// 被代理类(演员)
private Actor actor;
public Agent(Actor actor) {
this.actor = actor;
}
public void perform() {
System.out.println("我是" + actor.getName() + "的经纪人,找演员表演前先联系我洽谈");
actor.perform();
System.out.println("我是" + actor.getName() + "经纪人,表演完毕找我结算表演费用");
}
}
测试类测试:
// 客户
public class Customer {
// 开店,详情演员来表演
public void openStore(Person person){
person.perform();
}
}
// 静态代理测试类
public class StaticProxyTest {
public static void main(String[] args) {
// 找一个演员,可以真正表演的人
Actor actor = new Actor("sam");
// 演员的经纪人
Person agent = new Agent(actor);
// 客户有需求:需要找演员表演(找的是经纪人,真正表演的是演员)
new Customer().openStore(agent);
}
}
运行结果:
我是sam的经纪人,找演员表演前先联系我洽谈
我是演员sam,我要开始表演了。。
我是sam经纪人,表演完毕找我结算表演费用
可以看出,演员只需要准备好表演方面的工作,不需要关注那些零碎的跟核心任务无关的事情。这就是代理的优点,专业的事交给专业的人去做。
动态代理
动态代理,即代理类是在运行时动态生成的。在Java Api已提供Proxy,InvocationHandler来实现动态代理。
// 代理对象委托类
public class PerformInvocationHandler implements InvocationHandler {
private Actor actor;
public PerformInvocationHandler(Actor actor) {
this.actor = actor;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("proxy name is:"+proxy.getClass().getName()+",method name is:"+method.getName());
System.out.println("动态代理执行前");
method.invoke(actor, args);
System.out.println("动态代理执行后");
return null;
}
}
// 动态代理测试类
public class DynamicProxyTest {
public static void main(String[] args) {
// 开启代理类打印到本地磁盘
System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
// 被代理类
Actor actor = new Actor("新垣结衣");
// 创建动态代理委托类
InvocationHandler invocationHandler = new PerformInvocationHandler(actor);
// 生成代理类(经纪人)
Person agent = (Person) Proxy.newProxyInstance(actor.getClass().getClassLoader(), actor.getClass().getInterfaces(), invocationHandler);
// 客户开店请艺人表演
new Customer().openStore(agent);
}
}
使用System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"),会将生成的代理类的class文件保存到本地,保存路径为项目/com/sun/proxy/
运行结果:
动态代理执行前
我是演员新垣结衣,我要开始表演了。。
动态代理执行后
至此,就已经实现了代理