租房中介、代理律师、售票黄牛、中介、婚介、经纪人、快递等,都是代理模式的实际体现。
代理模式是指为其他对象提供一种代理,以控制对这个对象的访问。代理对象在客户端和目标对象
之间起到中介作用,代理模式属于结构型设计模式。
使用代理模式两个目的:一是保护目标对象,二是增强目标对象。
比如,父母为自己的孩子相亲,这个相亲的过程实现如下
顶层接口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
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();
- }
- }
- }
运行结果
动态代理和静态代理思路基本一致,只不过动态代理功能更加强大,随着业务的扩展适应性更强。
还以上面找对象为例,那么动态代理能适用复杂的业务场景。
不仅包括父亲给儿子找对象,还包括媒婆、婚介所等,所以需要一个更加通用的解决方案。
创建媒婆类
- 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();
- }
- }
- }
- }
还是 以上面媒婆为例
- 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();
- }
- }
- }