代理模式
一、代理模式介紹
1、定義與類型
定義:為其他對象提供一種代理,以控制對這個對象的訪問
代理對象在客戶端和目標對象之間起到中介的作用
類型:結構型
2、適用場景
保護目標對象
增強目標對象
3、優點
代理模式能將代理對象與真實被調用的目標對象分離
一定程度上降低了系統的耦合度,擴展性好
保護目標對象
增強目標對象
4、缺點
代理模式會造成系統設計中類的數目增加
在客戶端和目標對象增加一個代理對象,會造成請求處理速度變慢
增加系統的複雜度
5、擴展
靜態代理
動態代理
CGLib代理
6、Spring代理選擇-擴展
當Bean有實現介面時,Spring就會用JDK的動態代理
當Bean沒有實現介面時,Spring使用CGlib
可以強制使用Cglib
在spring配置中加入<aop:aspectj-autoproxy proxy-target-class=”true”/>
參考資料:htpsi//docs.spring.io/spring/docs/current/spring-framework-reference/core.html
7、代理-相關設計模式
代理模式和裝飾者模式
實現上相似,但目的不同,裝飾者模式是為對象加上行為,而代理模式是為了控制訪問,代理模式更加註重通過增加代理人的方式來增強目標對象。
代理模式和適配器模式
適配器模式主要考慮改變目標對象的介面,而代理模式是不能改變代理類的介面的
二、程式碼示例
模擬場景:spring中,service調用dao前,需要先根據分庫策略,切換數據源,即AOP面向切面
實體訂單類:
public class Order {
private Object orderInfo;
private Integer userId;
public Object getOrderInfo() {
return orderInfo;
}
public void setOrderInfo(Object orderInfo) {
this.orderInfo = orderInfo;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
}
持久層dao介面:
public interface IOrderDao {
int insert(Order order);
}
持久層dao實現類:
public class OrderDaoImpl implements IOrderDao {
@Override
public int insert(Order order) {
System.out.println("Dao層添加Order成功");
return 1;
}
}
服務層service介面:
public interface IOrderService {
int saveOrder(Order order);
}
服務層service類:
public class OrderServiceImpl implements IOrderService {
private IOrderDao iOrderDao;
@Override
public int saveOrder(Order order) {
//模擬自動注入
iOrderDao = new OrderDaoImpl();
System.out.println("Service層調用Dao層添加Order");
return iOrderDao.insert(order);
}
}
1、靜態代理
靜態代理類:
public class OrderServiceStaticProxy {
private IOrderService iOrderService;
public int saveOrder(Order order){
beforeMethod(order);
// 模擬自動注入
iOrderService = new OrderServiceImpl();
int result = iOrderService.saveOrder(order);
afterMethod();
return result;
}
private void beforeMethod(Order order){
// 模擬分庫代理操作
int userId = order.getUserId();
int dbRouter = userId % 2;
System.out.println("靜態代理分配到【db"+dbRouter+"】處理數據");
//todo 設置dataSource;
DataSourceContextHolder.setDBType("db"+String.valueOf(dbRouter));
System.out.println("靜態代理 before code");
}
private void afterMethod(){
System.out.println("靜態代理 after code");
}
}
測試類:
public class Test {
public static void main(String[] args) {
Order order = new Order();
order.setUserId(2);
//直接調用代理類
OrderServiceStaticProxy orderServiceStaticProxy = new OrderServiceStaticProxy();
orderServiceStaticProxy.saveOrder(order);
}
}
2、動態代理
動態代理類:
public class OrderServiceDynamicProxy implements InvocationHandler {
private Object target;
public OrderServiceDynamicProxy(Object target) {
this.target = target;
}
public Object bind(){
Class cls = target.getClass();
return Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object argObject = args[0];
beforeMethod(argObject);
Object object = method.invoke(target,args);
afterMethod();
return object;
}
private void beforeMethod(Object obj){
int userId = 0;
System.out.println("動態代理 before code");
if(obj instanceof Order){
Order order = (Order)obj;
userId = order.getUserId();
}
int dbRouter = userId % 2;
System.out.println("動態代理分配到【db"+dbRouter+"】處理數據");
//todo 設置dataSource;
DataSourceContextHolder.setDBType("db"+String.valueOf(dbRouter));
}
private void afterMethod(){
System.out.println("動態代理 after code");
}
}
測試類:
public class Test {
public static void main(String[] args) {
Order order = new Order();
order.setUserId(1);
// 通過代理類取到service
IOrderService orderServiceDynamicProxy = (IOrderService) new OrderServiceDynamicProxy(new OrderServiceImpl()).bind();
orderServiceDynamicProxy.saveOrder(order);
}
}