场景
代理模式(Proxy Pattern)
租房中介、代理律师、售票黄牛、中介、婚介、经纪人、快递等,都是代理模式的实际体现。
代理模式是指为其他对象提供一种代理,以控制对这个对象的访问。代理对象在客户端和目标对象
之间起到中介作用,代理模式属于结构型设计模式。
使用代理模式两个目的:一是保护目标对象,二是增强目标对象。
静态代理
比如,父母为自己的孩子相亲,这个相亲的过程实现如下
顶层接口Person代码实现
package com.ruoyi.demo.designPattern.staticProxy;
/**
* 人有很多行为,比如下面的谈恋爱、找对象
*/
public interface Person {
public void findLove();
}
儿子要找对象,实现Son类
package com.ruoyi.demo.designPattern.staticProxy;
public class Son implements Person{
@Override
public void findLove() {
System.out.println("儿子要求:白富美");
}
}
父亲要帮儿子相亲,实现Father类
package com.ruoyi.demo.designPattern.staticProxy;
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("双方同意,确定关系");
}
}
注意这里:
父亲通过构造方法获取儿子的引用,并且在findLove中进行了增强,给儿子安排了相亲,然后再
促使儿子去谈恋爱,调用findLove方法。
测试代码
package com.ruoyi.demo.designPattern.staticProxy;
public class fatherTest {
public static void main(String[] args) {
Father father = new Father(new Son());
father.findLove();
}
}
注:
博客:
霸道流氓气质的博客_CSDN博客-C#,架构之路,SpringBoot领域博主
关注公众号
霸道的程序猿
获取编程相关电子书、教程推送与免费下载。
静态代理业务场景举例
看一个实际的业务场景。
在分布式业务中,需要分库分表,分库分表之后使用Java操作时可能需要配置多个数据源。
通过设置数据源路由来动态切换数据源。
创建Order订单类
package com.ruoyi.demo.designPattern.staticProxy;
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;
}
}
创建Order持久层操作类
package com.ruoyi.demo.designPattern.staticProxy;
public class OrderDao {
public int insert(Order order){
System.out.println("OrderDao创建order成功!");
return 1;
}
}
创建IOrderService接口
package com.ruoyi.demo.designPattern.staticProxy;
public interface IOrderService {
int createOrder(Order order);
}
创建OrderService实现类
package com.ruoyi.demo.designPattern.staticProxy;
public class OrderService implements IOrderService{
private OrderDao orderDao;
public OrderService(){
//如果使用Spring应该是自动注入的,这里为方便,直接在构造方法中初始化
orderDao = new OrderDao();
}
@Override
public int createOrder(Order order) {
System.out.println("OrderService 调用orderDao创建订单");
return orderDao.insert(order);
}
}
然后进行静态代理,主要完成的功能是:根据订单创建时间自动按年进行分库。
先创建数据源路由对象,使用ThreadLocal的单例实现DynamicDataSourceEntry
package com.ruoyi.demo.designPattern.staticProxy;
//动态切换数据源
public class DynamicDataSourceEntry {
//默认数据源
public final static String DEFAULT_SOURCE = null;
private final static ThreadLocal<String> local = new ThreadLocal<>();
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
package com.ruoyi.demo.designPattern.staticProxy;
import java.text.SimpleDateFormat;
import java.util.Date;
public class OrderServiceStaticProxy implements IOrderService{
private SimpleDateFormat yearFormat = new SimpleDateFormat("yyyy");
private IOrderService orderService;
public OrderServiceStaticProxy(IOrderService orderService){
this.orderService = orderService;
}
@Override
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");
}
}
来看测试代码
package com.ruoyi.demo.designPattern.staticProxy;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class StaticProxyTest {
public static void main(String[] args) {
try {
Order order = new Order();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
Date date = sdf.parse("2022/10/29");
order.setCreateTime(date.getTime());
IOrderService orderService = new OrderServiceStaticProxy(new OrderService());
orderService.createOrder(order);
}catch (ParseException e) {
e.printStackTrace();
}
}
}
运行结果
动态代理-JDK实现方式
动态代理和静态代理思路基本一致,只不过动态代理功能更加强大,随着业务的扩展适应性更强。
还以上面找对象为例,那么动态代理能适用复杂的业务场景。
不仅包括父亲给儿子找对象,还包括媒婆、婚介所等,所以需要一个更加通用的解决方案。
创建媒婆类
package com.ruoyi.demo.designPattern.jdkDynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKMeipo implements InvocationHandler {
//被代理的对象,把引用保存下来
private Object target;
public Object getInstance(Object target) throws Exception{
this.target = target;
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.ruoyi.demo.designPattern.jdkDynamicProxy;
import com.ruoyi.demo.designPattern.staticProxy.Person;
public class Customer implements Person {
@Override
public void findLove() {
System.out.println("高富帅单身优质对象");
}
}
测试代码
package com.ruoyi.demo.designPattern.jdkDynamicProxy;
import com.ruoyi.demo.designPattern.staticProxy.Person;
public class jdkDynamicProxy {
public static void main(String[] args) {
try {
Person obj = (Person) new JDKMeipo().getInstance(new Customer());
obj.findLove();
} catch (Exception e) {
e.printStackTrace();
}
}
}
为加深印象,用JDK动态代理修改上面数据源动态路由的业务
创建动态代理的类
package com.ruoyi.demo.designPattern.jdkDynamicProxy;
import com.ruoyi.demo.designPattern.staticProxy.DynamicDataSourceEntry;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.text.SimpleDateFormat;
import java.util.Date;
public class OrderServiceDynamicProxy implements InvocationHandler {
private SimpleDateFormat yearFormat = 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);
}
@Override
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 before(Object target){
System.out.println("Proxy before method");
try {
Long time = (Long) target.getClass().getMethod("getCreateTime").invoke(target);
Integer dbRouter = Integer.valueOf(yearFormat.format(new Date(time)));
System.out.println("动态代理类自动分配到【DB_"+dbRouter+"】数据源处理数据");
DynamicDataSourceEntry.set(dbRouter);
} catch (Exception e) {
e.printStackTrace();
}
}
private void after(){
System.out.println("Proxy after method");
}
}
测试代码如下
package com.ruoyi.demo.designPattern.jdkDynamicProxy;
import com.ruoyi.demo.designPattern.staticProxy.IOrderService;
import com.ruoyi.demo.designPattern.staticProxy.Order;
import com.ruoyi.demo.designPattern.staticProxy.OrderService;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DyDataDyProTest {
public static void main(String[] args) {
Order order = new Order();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
Date date;
{
try {
date = sdf.parse("2022/10/31");
order.setCreateTime(date.getTime());
IOrderService orderService = (IOrderService) new OrderServiceDynamicProxy().getInstance(new OrderService());
orderService.createOrder(order);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
}
动态代理-CGLib方式
还是 以上面媒婆为例
package com.ruoyi.demo.designPattern.cglibDynamicProxy;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibMeipo implements MethodInterceptor {
public Object getInstance(Class<?> clazz) throws Exception{
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 before(){
System.out.println("我是媒婆:要按照你的要求给你找对象");
}
private void after(){
System.out.println("如果觉得合适你们就谈恋爱吧");
}
}
创建单身客户类
package com.ruoyi.demo.designPattern.cglibDynamicProxy;
public class Customer {
public void findLove(){
System.out.println("白富美");
}
}
测试代码
package com.ruoyi.demo.designPattern.cglibDynamicProxy;
public class CGlibProxyTest {
public static void main(String[] args) {
try {
Customer obj = (Customer) new CglibMeipo().getInstance(Customer.class);
obj.findLove();
} catch (Exception e) {
e.printStackTrace();
}
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/135880.html