代理模式
1 静态代理
1、角色分析
- 抽象角色:一般会使用接口或者抽象类来解决。
- 真实角色:被代理的角色。
- 代理角色:代理真实角色,一般会做一些附属操作。
- 客户:访问代理对象的人。
2、好处
- 可以使真实角色的操作更加纯粹,不用去关注一些公共的业务。
- 公共业务交给代理角色,实现分工。
- 公共业务发生扩展的时候,方便集中管理。
3、缺点
- 一个真实角色就会产生一个代理角色,代码量翻倍,开发效率降低。
4、代码示例
接口
package proxy; /** * 租房 */ public interface Rent { void rent(); }
真实角色
package proxy; /** * 房东 */ public class Host implements Rent { @Override public void rent() { System.out.println("房东要出租房子!"); } }
代理角色
package proxy; public class Proxy implements Rent { private Host host; public Proxy() { } public Proxy(Host host) { this.host = host; } @Override public void rent() { seeHouse(); host.rent(); hetong(); fare(); } /** * 看房 */ public void seeHouse() { System.out.println("中介带你看房"); } /** * 收中介费 */ public void fare() { System.out.println("收中介费"); } /** * 签合同 */ public void hetong() { System.out.println("签合同"); } }
客户
package proxy; import org.junit.Test; /** * 房客 */ public class Client { @Test public void test() { // 1、房东 Host host = new Host(); // 2、房东找中介代理 Proxy proxy = new Proxy(host); // 3、代理出租房子,可以进行额外看房、签合同等操作 proxy.rent(); } }
5、静态代理与AOP
UserService
package proxy.demo02; public interface UserService { void add(); void delete(); void update(); void query(); }
UserServiceImpl
package proxy.demo02; /** * 真实对象 */ public class UserServiceImpl implements UserService { @Override public void add() { System.out.println("增加了一个用户"); } @Override public void delete() { System.out.println("删除了一个用户"); } @Override public void update() { System.out.println("修改了一个用户"); } @Override public void query() { System.out.println("查询了一个用户"); } }
UserServiceProxy
package proxy.demo02; public class UserServiceProxy implements UserService { private UserServiceImpl userService; public void setUserService(UserServiceImpl userService) { this.userService = userService; } @Override public void add() { log("add"); userService.add(); } @Override public void delete() { log("delete"); userService.delete(); } @Override public void update() { log("update"); userService.update(); } @Override public void query() { log("query"); userService.query(); } public void log(String msg) { System.out.println("[日志]:使用了" + msg + "方法"); } }
Client
package proxy.demo02; import org.junit.Test; public class Client { @Test public void test() { UserServiceImpl userService = new UserServiceImpl(); UserServiceProxy proxy = new UserServiceProxy(); proxy.setUserService(userService); proxy.add(); } }
2 动态代理
1、角色分析
- 动态代理的角色与静态代理相同。
- 动态代理的代理类是动态生成的,不是直接写好的!
2、分类
- 基于接口:JDK动态代理。
- 基于类:cglib。
- Java字节码实现:Javasist(JBoss服务器)。
3、两个重要的类
- InvocationHandler
- Proxy
4、InvocationHandler
- 代理实例的调用处理程序实现的接口。
- 每个代理实例都有一个关联的调用处理程序,当在代理实例上调用方法时,方法调用将被编码并分派到其调用处理程序的invoke方法。
package java.lang.reflect; public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
5、Proxy
- 提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。
InvocationHandler handler = new MyInvocationHandler(...); Foo f = (Foo)Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class<?>[]{Foo.class}, handler);
6、代码示例
Rent
package proxy.demo03; /** * 租房 */ public interface Rent { void rent(); } }
ProxyInvocationHandler
package proxy.demo03; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 使用这个类,自动生成代理类 */ public class ProxyInvocationHandler implements InvocationHandler { // 被代理的接口 private Rent rent; public void setRent(Rent rent) { this.rent = rent; } /** * 生成代理对象 */ public Object getProxy() { return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this); } /** * 处理代理实例,并返回结果 * @param proxy 代理对象 * @param method 被代理类的方法 * @param args 方法的参数 * @return 方法返回值 * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { seeHouse(); // 动态代理的本质,就是使用反射机制实现! Object result = method.invoke(rent, args); fare(); return result; } public void seeHouse() { System.out.println("看房子"); } public void fare() { System.out.println("收中介费"); } }
Host
package proxy.demo03; /** * 房东 */ public class Host implements Rent { @Override public void rent() { System.out.println("房东要出租房子!"); } }
Client
package proxy.demo03; import org.junit.Test; public class Client { @Test public void test() { // 1、真实角色 Host host = new Host(); // 2、获取代理角色 ProxyInvocationHandler handler = new ProxyInvocationHandler(); handler.setRent(host); Rent proxy = (Rent) handler.getProxy(); // 动态生成 // 3、使用 proxy.rent(); } }
7、万能的动态代理类
package proxy.demo04; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyInvocationHandler implements InvocationHandler { private Object target; public void setTarget(Object target) { this.target = target; } public Object getProxy() { return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = method.invoke(target, args); return result; } }
8、动态代理的好处
- 包含所有静态代理的好处。
- 一个动态代理类代理的是一个接口,一般就是对应的一类业务。
- 一个动态代理类可以代理多个类,只要是实现了同一个接口即可。