介紹
代理模式(Proxy Pattern)是指爲其他對象提供一種代理,以控制對這個對象的訪問。 代理對象在客服端和目標對象之間起到中介作用,代理模式屬於結構型設計模式。
在生活中,我們經常見到這樣的場景,如:租房中介、售票黃牛、婚介、經紀人、快遞、 事務代理、非侵入式日誌監聽等,這些都是代理模式的實際體現。
目的
1、保護目標對象
2、增強目標對象。
分類
1、靜態代理
2、動態代理
動態代理與靜態代理的區別
1、靜態代理只能通過手動完成代理操作,如果被代理類增加新的方法,代理類需要同步 新增,違背開閉原則。
2、動態代理採用在運行時動態生成代碼的方式,取消了對被代理類的擴展限制,遵循開 閉原則。
3、若動態代理要對目標類的增強邏輯擴展,結合策略模式,只需要新增策略類便可完成, 無需修改代理類的代碼。
優點
1、代理模式能將代理對象與真實被調用的目標對象分離。
2、一定程度上降低了系統的耦合度,擴展性好。
3、可以起到保護目標對象的作用。
4、可以對目標對象的功能增強。
缺點
1、代理模式會造成系統設計中類的數量增加。
2、在客戶端和目標對象增加一個代理對象,會造成請求處理速度變慢。
3、增加了系統的複雜度。
使用場景
1、日誌監聽
2、保護目標對象或則增強目標對象
3、Spring 利用動態代理實現 AOP 有兩個非常重要的類,一個是 JdkDynamicAopProxy 類 和 CglibAopProxy 類。
4、有分庫場景時,數據庫的動態選擇---可考慮這種模式去實現。
使用建議
具體實現
靜態代理(MVC模式就是一個典型的靜態代理)
(靜態代理實例一)老子幫兒子相親:
類圖:
代碼:
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.static_proxy;
public interface Person {
void findLove();
}
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.static_proxy;
/**
* @program: demo-pom
* @description:
* @author: bo.hu
* @create: 2020-01-23 14:12
**/
public class Son implements Person{
@Override
public void findLove() {
System.out.println("不傻就行");
}
}
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.static_proxy;
/**
* @program: demo-pom
* @description: 代理對象類
* @author: bo.hu
* @create: 2020-01-23 14:13
**/
public class Father {
private Son son;
public Father(Son son) {
this.son = son;
}
public void findLove(){
System.out.println("父母角度出發:選擇");
this.son.findLove();
System.out.println("雙方父母同意交往,確立關係。");
}
public static void main(String[] args) {
Father f=new Father(new Son());
f.findLove();
}
}
(靜態代理實例二)數據庫的動態選擇:
類圖:
代碼:
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.static_proxy_2;
import lombok.Data;
/**
* @program: demo-pom
* @description: 訂單實體類
* @author: bo.hu
* @create: 2020-01-23 14:38
**/
@Data
public class Order {
private Object orderInfo;
private Long createTime;
private String id;
}
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.static_proxy_2;
/**
* @program: demo-pom
* @description:
* @author: bo.hu
* @create: 2020-01-23 14:44
**/
public class OrderMapper {
public int insert(Order order){
System.out.println("OrderMapper 創建 Order 成功");
return 1;
}
}
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.static_proxy_2;
public interface OrderService {
int createOrder(Order order);
}
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.static_proxy_2;
/**
* @program: demo-pom
* @description:
* @author: bo.hu
* @create: 2020-01-23 14:47
**/
public class OrderServiceImpl implements OrderService {
private OrderMapper orderMapper;
public OrderServiceImpl(OrderMapper orderMapper) {
this.orderMapper = orderMapper;
}
@Override
public int createOrder(Order order) {
System.out.println("OrderService 調用 orderMapper 創建訂單");
return orderMapper.insert(order);
}
}
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.static_proxy_2;
import javax.xml.crypto.Data;
/**
* @program: demo-pom
* @description:
* @author: bo.hu
* @create: 2020-01-23 15:12
**/
public class DynamicDataSourceEntry {
public final static String DEFAULT = null;
private final static ThreadLocal<String> local = new ThreadLocal<>();
public DynamicDataSourceEntry() {
}
public static void clear() {
local.remove();
}
public static void get() {
local.get();
}
public static void restore() {
local.set(DEFAULT);
}
public static void set(String resource) {
local.set(resource);
}
public static void set(int year) {
local.set("DB_" + year);
}
}
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.static_proxy_2;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @program: demo-pom
* @description: 創建訂單靜態代理類
* @author: bo.hu
* @create: 2020-01-23 15:22
**/
public class CreateOrderProxy implements OrderService{
private SimpleDateFormat yearFormat = new SimpleDateFormat("yyyy");
private OrderService orderService;
public CreateOrderProxy(OrderService orderService) {
this.orderService = orderService;
}
public int createOrder(Order order){
before();
Long time = order.getCreateTime();
Integer dbRouter = Integer.valueOf(yearFormat.format(new Date(time)));
System.out.println("靜態代理類自動分配到【DB_" + dbRouter + "】數據源處理數據。");
DynamicDataSourceEntry.set(dbRouter);
orderService.createOrder(order);
after();
return 0;
}
private void before() {
System.out.println("Proxy before method.");
}
private void after() {
System.out.println("Proxy after method.");
}
public static void main(String[] args) {
Order order=new Order();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
Date date = null;
try {
date = sdf.parse("2017/02/01");
} catch (ParseException e) {
e.printStackTrace();
}
order.setCreateTime(date.getTime());
OrderService orderService = new CreateOrderProxy(new OrderServiceImpl(new OrderMapper()));
orderService.createOrder(order);
}
}
動態代理
JDK自帶的動態代理
類圖:
代碼:
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.static_proxy;
public interface Person {
void findLove();
}
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.dynamic_proxy_jdk;
import com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.static_proxy.Person;
/**
* @program: demo-pom
* @description: 顧客
* @author: bo.hu
* @create: 2020-01-23 16:19
**/
public class Customer implements Person {
@Override
public void findLove() {
System.out.println("不傻就行");
}
}
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.dynamic_proxy_jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @program: demo-pom
* @description: 動態代理類java實現方式
* @author: bo.hu
* @create: 2020-01-23 16:09
**/
public class JDKMeipo implements InvocationHandler {
private Object target;
public Object getIntence(Object object){
this.target=object;
Class<?>clazz=target.getClass();
return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object obj=method.invoke(this.target,args);
after();
return obj;
}
private void before() {
System.out.println("開始 物色人選");
}
private void after() {
System.out.println("結束 物色人選");
}
}
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.dynamic_proxy_jdk;
import com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.static_proxy.Person;
/**
* @program: demo-pom
* @description:
* @author: bo.hu
* @create: 2020-01-23 16:20
**/
public class Test {
public static void main(String[] args) {
// 動態代理類和被代理類必須繼承同一個接口。
// 動態代理只能對接口中聲明的方法進行代理。
// 每一個動態代理實例都有一個關聯的InvocationHandler。
// 通過代理實例調用方法,方法調用請求會被轉發給InvocationHandler的invoke方法。
// 只能代理聲明在接口中的方法。
Person obj=(Person)new JDKMeipo().getIntence(new Customer());
obj.findLove();
}
}
CGLIB實現的動態代理(Spring中同時使用了JDK與CGLIB這兩種代理)
類圖:
代碼:
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.static_proxy;
public interface Person {
void findLove();
}
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.dynamic_proxy_cglib;
import com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.static_proxy.Person;
public class Customer implements Person {
@Override
public void findLove() {
System.out.println("cglib findLove()");
}
}
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.dynamic_proxy_cglib;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CgLibMeipo implements MethodInterceptor {
public Object getInstence(Class<?> clazz){
Enhancer enhancer =new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object obj=methodProxy.invokeSuper(o,objects);
after();
return obj;
}
private void after() {
System.out.println("代理類前置處理");
}
private void before() {
System.out.println("代理類後置處理");
}
}
package com.knowledge.system.software_design_pattern.proxy_pattern.course_instance.dynamic_proxy_cglib;
public class Test {
public static void main(String[] args) {
Customer customer=(Customer)new CgLibMeipo().getInstence(Customer.class);
customer.findLove();
}
}