Java 静态代理
静态代理通常用于对原有业务逻辑的扩充。比如持有二方包的某个类,并调用了其中的某些方法。然后出于某种原因,比如记录日志、打印方法执行时间,但是又不好将这些逻辑写入二方包的方法里。所以可以创建一个代理类实现和二方方法相同的方法,通过让代理类持有真实对象,然后在原代码中调用代理类方法,来达到添加我们需要业务逻辑的目的。
这其实也就是代理模式的一种实现,通过对真实对象的封装,来实现扩展性。
一个典型的代理模式通常有三个角色,这里称之为**代理三要素**
package singleton;
public class TestProxy {
public static void main(String[] args) {
Subject subject = new ProxySubject();
subject.request();
}
}
抽象角色
abstract class Subject {
public abstract void request();
}
真实角色
class RealSubject extends Subject {
@Override
public void request() {
System.out.println("From real subject");
}
}
代理角色
class ProxySubject extends Subject {
private RealSubject realSubject;// 代理角色内部引用了真是角色
@Override
public void request() {
this.preRequest();// 在真实角色操作之前所附加的操作
if (null == realSubject) {
realSubject = new RealSubject();
}
realSubject.request();// 真实角色锁完成的事情
this.postRequest();// 在真实角色操作之后所附加的操作
}
private void preRequest() {
System.out.println("pre request");
}
private void postRequest() {
System.out.println("post request");
}
}
运行结果:
pre request
From real subject
post request
也可以用接口表示抽象角色
共同接口
public interface Action {
public void doSomething();
}
真实对象
public class RealObject implements Action{
public void doSomething() {
System.out.println("do something");
}
}
代理对象
public class Proxy implements Action {
private Action realObject;
public Proxy(Action realObject) {
this.realObject = realObject;
}
public void doSomething() {
System.out.println("proxy do");
realObject.doSomething();
}
}
运行代码
Proxy proxy = new Proxy(new RealObject());
proxy.doSomething();
这种代理模式也最为简单,就是通过proxy持有realObject的引用,并进行一层封装。
静态代理的优点和缺点
先看看代理模式的优点: 扩展原功能,不侵入原代码。
再看看这种代理模式的缺点:
假如有这样一个需求,有十个不同的RealObject,同时我们要去代理的方法是不同的,比要代理方法:doSomething、doAnotherThing、doTwoAnotherThing,添加代理前,原代码可能是这样的:
realObject.doSomething();
realObject1.doAnotherThing();
realObject2.doTwoAnother();
为了解决这个问题,我们有方案一:
为这些方法创建不同的代理类,代理后的代码是这样的:
proxy.doSomething();
proxy1.doAnotherThing();
proxy2.doTwoAnother();
当然,也有方案二:
通过创建一个proxy,持有不同的realObject,实现Action1、Action2、Action3接口,来让代码变成这样:
proxy.doSomething();
proxy.doAnotherThing();
proxy.doTwoAnother();
于是你的代理模型会变成这样:
毫无疑问,仅仅为了扩展同样的功能,在方案一种,我们会重复创建多个逻辑相同,仅仅RealObject引用不同的Proxy。
而在方案二中,会导致proxy的膨胀,而且这种膨胀往往是无意义的。此外,假如方法签名是相同的,更需要在调用的时候引入额外的判断逻辑。
package Test;
public class TestProxy {
public static void main(String[] args) {
Action1 action1 = new ProxySubject();
action1.requestFirstThing();
Action2 action2 = new ProxySubject();
action2.requestSecondThing();
Action3 action3 = new ProxySubject();
action3.requestThirdThing();
}
}
interface Action1 {
void requestFirstThing();
}
interface Action2 {
void requestSecondThing();
}
interface Action3 {
void requestThirdThing();
}
class RealSubject1 implements Action1 {
@Override
public void requestFirstThing() {
System.out.println("From real subject1");
}
}
class RealSubject2 implements Action2 {
@Override
public void requestSecondThing() {
System.out.println("From real subject2");
}
}
class RealSubject3 implements Action3 {
@Override
public void requestThirdThing() {
System.out.println("From real subject3");
}
}
class ProxySubject implements Action1, Action2, Action3 {
private RealSubject1 realSubject1;// 代理角色内部引用了真是角色
private RealSubject2 realSubject2;// 代理角色内部引用了真是角色
private RealSubject3 realSubject3;// 代理角色内部引用了真是角色
@Override
public void requestFirstThing() {
this.preRequest();// 在真实角色操作之前所附加的操作
if (null == realSubject1) {
realSubject1 = new RealSubject1();
}
realSubject1.requestFirstThing();// 真实角色锁完成的事情
this.postRequest();// 在真实角色操作之后所附加的操作
}
private void preRequest() {
System.out.println("pre request");
}
private void postRequest() {
System.out.println("post request");
}
@Override
public void requestThirdThing() {
this.preRequest();// 在真实角色操作之前所附加的操作
if (null == realSubject2) {
realSubject2 = new RealSubject2();
}
realSubject2.requestSecondThing();// 真实角色锁完成的事情
this.postRequest();// 在真实角色操作之后所附加的操作
}
@Override
public void requestSecondThing() {
this.preRequest();// 在真实角色操作之前所附加的操作
if (null == realSubject3) {
realSubject3 = new RealSubject3();
}
realSubject3.requestThirdThing();// 真实角色锁完成的事情
this.postRequest();// 在真实角色操作之后所附加的操作
}
}
运行结果:
pre request
From real subject1
post request
pre request
From real subject3
post request
pre request
From real subject2
post request