2.代理模式
- 代理模式(Proxy pattern) 指为其他对象提供一种代理,以控制对这个对象的访问,属于结构设计模式。
- 在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端与目标对象之间起到中介的作用。
2.1 代理模式介绍
2.1.1 代理模式的应用场景
- 婚姻中介,事务代理,日志坚挺。
- 当不想直接引用某个对象或某个对象存在访问困难时,可以通过代理对象来间接访问。使用代理模式主要有两个目的:一、保护目标对象。二、增强目标对象。
2.1.2 代理模式的UML图

代理模式一般分三个角色
- 抽象角色(ISbject):抽象主题类的主要职责是生命真实主题和代理的共同接口方法,该类可以是接口,也可以是抽象类。
- 真实角色(RealSubject):也被称为被代理类,该类定义了代理所表示的真实对象,是负责执行系统的真正的逻辑业务对象。
- 代理角色(Proxy):代理类,其内部有RealSubject的引用,因此具备完全的对RealSubject的代理权,客户端调用代理对象的方法,也调用被代理对象的方法,但是会在代理对象前后增加一些逻辑代码。
- 代理模式被分为静态代理和动态代理。代理一般可以理解位代码增强。
2.1.3 代理模式通用写法
public class Client {
public static void main(String[] args) {
Proxy proxy = new Proxy(new RealSubject());
proxy.request();
}
interface ISbuject{
void request();
}
//代理角色
static class Proxy implements ISbuject{
private ISbuject sbuject;
public Proxy(ISbuject sbuject){
this.sbuject = sbuject;
}
public void request() {
before();
sbuject.request();
after();
}
private void after() {
System.out.println("Proxy After");
}
private void before() {
System.out.println("Proxy before");
}
}
static class RealSubject implements ISbuject{
public void request() {
System.out.println("real subject");
}
}
}

2.2 代理模式的实际问题解决
2.21 静态代理
一个代理对象对应一个被代理对象,不能代理其他被代理对象。
public interface IPerson {
void find();
}
- 被代理对象
public class Son implements IPerson {
public void find() {
System.out.println("符合要求");
}
}
- 代理对象
public class Monther implements IPerson {
private Son son;
public Monther(Son son){
this.son = son;
}
public void find() {
before();
son.find();
after();
}
private void after() {
System.out.println("开始相亲");
}
private void before() {
System.out.println("家长催婚,并寻找相亲对象");
}
}
- 结果:

2.2.2 动态代理
静态代理太过于浪费成本,因此采用动态代理,只要实现了IPerson都可以进行代理,面前有JDK自带的代理以及CGLib代理。
public class JdkMeipo implements InvocationHandler {
//获取字节码文件
private IPerson instance;
public IPerson getInstance(IPerson instance){
this.instance = instance;
Class<?> clazz = instance.getClass();
return (IPerson) Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(this.instance,args);
after();
return null;
}
private void after() {
System.out.println("找到对象,开始相亲");
}
private void before() {
System.out.println("媒婆收到需求,开始寻找对象");
}
}
public class Zhangsan implements IPerson{
public void find() {
System.out.println("符合张三需求");
}
//其他功能
}
- 测试
@Test
public void test1(){
JdkMeipo jdkMeipo = new JdkMeipo();
IPerson zhangsan = jdkMeipo.getInstance(new Zhangsan());
zhangsan.find();
}
- 结果

2.2.3 三层架构种的静态代理
- 在分布式业务场景种,通常对数据库进行分库分表,分库分表之后会使用Java操作就需要配置多个数据源,通过设置数据路由来动态切换数据源。
- Order类
public class Order {
private Object orderInfo;
private Long createTime;
private String id;
public Object getOrderInfo() {
return orderInfo;
}
public void setOrderInfo(Object orderInfo) {
this.orderInfo = orderInfo;
}
public Long getCreateTime() {
return createTime;
}
public void setCreateTime(Long createTime) {
this.createTime = createTime;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
- OrderDao类
public class OrderDao {
public int insert(Order order){
System.out.println("OrderDao创建Order成功");
return 1;
}
}
- IOrderService接口
public interface IOrderService {
int createOrder(Order order);
}
- Order实现类
public class OrderService implements IOrderService{
private OrderDao orderDao;
public OrderService(){
//Spring自动注入OrderDao
orderDao = new OrderDao();
}
public int createOrder(Order order) {
System.out.println("OrderService调用OrderDao创建订单");
return orderDao.insert(order);
}
}
- 静态代理,根据订单创建的时间自动由年进行分库,根据开闭原则,修改原来的代码逻辑,通过代理对象来完成。创建数据源路由对象,使用ThreadLocal的单例实现DynamicDataSourceEntry类
public class DynamicDataSourceEntry {
//默认数据源
public final static String DEFAULT_SOURCE=null;
private final static ThreadLocal<String> local = new ThreadLocal<String>();
private DynamicDataSourceEntry(){}
//清空数据源
public static void clear(){
local.remove();
}
//获取当前正在使用的数据库名字
public static String get(){
return local.get();
}
//还原当前切换的数据源
public static void restore(){
local.set(DEFAULT_SOURCE);
}
//设置已知名字的数据源
public static void set(String source){
local.set(source);
}
//根据年份动态设置数据源
public static void set(int year){
local.set("DB_"+year);
}
}
- 创建切换数据源的代理类OrderServiceStaticProxy
public class OrderServiceStaticProxy implements IOrderService {
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
private IOrderService orderService;
public OrderServiceStaticProxy(IOrderService orderService){
this.orderService = orderService;
}
private void after() {
System.out.println("Proxy after method");
}
private void before() {
System.out.println("Proxy before method");
}
public int createOrder(Order order) {
before();
Long time = order.getCreateTime();
Integer dbRouter = Integer.valueOf(sdf.format(new Date(time)));
System.out.println("静态代理类自动分配到【DB_"+dbRouter+"】数据源处理数据");
DynamicDataSourceEntry.set(dbRouter);
orderService.createOrder(order);
after();
return 0;
}
}
- 客户端测试代码
public class Test1 {
@Test
public void test(){
try{
Order order = new Order();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
Date date = sdf.parse("2011/11/11");
order.setCreateTime(date.getTime());
IOrderService orderService = new OrderServiceStaticProxy(new OrderService());
orderService.createOrder(order);
}catch (Exception e){
e.printStackTrace();
}
}
}
- 结果:

- UML图

2.2.4 三层架构动态代理
public class OrderServiceDynamicProxy implements InvocationHandler {
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
private Object target;
public Object getInstance(Object target){
this.target = target;
Class<?> clazz = target.getClass();
return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before(args[0]);
Object object = method.invoke(target,args);
after();
return object;
}
private void after() {
}
private void before(Object target) {
try {
System.out.println("Proxy before method");
Long time = (Long) target.getClass().getMethod("getCreateTime").invoke(target);
Integer dbRouter = Integer.valueOf(sdf.format(new Date(time)));
System.out.println("动态代理代理类自动分配到【DB_"+dbRouter+"】数据源处理数据");
DynamicDataSourceEntry.set(dbRouter);
}catch (Exception e){
e.printStackTrace();
}
}
}
- 结果

- 使用动态代理之后,不仅可以实现Order的数据源动态路由,还可以实现其他任何类的数据源路由,但是需要实现getCreateTime()方法,因为路由规则是按照时间来运算的。
网友评论