码迷,mamicode.com
首页 > 其他好文 > 详细

设计模式课程 设计模式精讲 16-4 代理模式Coding-动态代理

时间:2019-09-21 17:03:09      阅读:116      评论:0      收藏:0      [点我收藏+]

标签:lang   contex   课程   赋值   print   ret   for   dbr   自己的   

1    代码演练

1.1  动态代理

2    疑难解答

2.1  动态代理invoke怎么执行的?

2.2  感觉这块理解的不是很好,下边有时间再看看

 

 

1    代码演练
1.1  动态代理

重点:

重点关注动态代理类

 

测试类:

package com.geely.design.pattern.structural.proxy.dynamicproxy;

import com.geely.design.pattern.structural.proxy.IOrderService;
import com.geely.design.pattern.structural.proxy.Order;
import com.geely.design.pattern.structural.proxy.OrderServiceImpl;

public class Test {
    public static void main(String [] args){
        Order order = new Order();
        order.setUserID(1);
        /**
         * new OrderServiceDynamicProxy(order) 该方法已经生成了一个新的代理类
         * 它的bind方法返回了原目标类,强转之后变成了原目标类。
         */
        IOrderService orderServiceDynamicProxy = (IOrderService) new OrderServiceDynamicProxy(new OrderServiceImpl()).bind();
        //注意,执行saveOrder方法,最终会执行invode方法。
        orderServiceDynamicProxy.saveOrder(order);
    }
}

 

动态代理类:

package com.geely.design.pattern.structural.proxy.dynamicproxy;


import com.geely.design.pattern.structural.proxy.Order;
import com.geely.design.pattern.structural.proxy.db.DataSourceContextHolder;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 目的:抽奖信息和订单等不同的类都可以通过这一个动态代理进行复用,不用每一个都写一个静态代理。
 * 这就是静态代理和动态代理的区别
 * 动态代理是自动生成的,静态代理需要显式的来描述和coding
 */
public class OrderServiceDynamicProxy implements InvocationHandler {
    //目标对象
    public Object target;

    //通过构造方法传入目标对象
    public OrderServiceDynamicProxy(Object target) {
        this.target = target;
    }

    /**
     * 主方法, 调用前置方法,主要方法,以及后置方法
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //取得目标对象,argObject是目标类,也就是静态代理demo中的订单类
        Object argObject = args[0];
        beforeMethod(argObject);
        Object object = method.invoke(target,args);
        afterMethod();
        return object;
    }

    public Object bind(){
        //得到目标对象的class类
        Class cls = target.getClass();
        //这里边有三个参数,classLoader,复数的interface,它的类型是class,第三个是invoccationHandler 因为本类本身实现了InvocationHandler,所以把本类自己传过去即可。
        return Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),this);
    }

    /**
     * 前置方法,用来取模运算
     * @param obj
     */
    private void beforeMethod(Object obj){
        int userID = 0;
        System.out.println("动态代理 before code");
        if(obj instanceof Order){//如果该对象属于Order类
            Order order = (Order) obj;//强转成Order 类
            userID = order.getUserID();
        }
        int dbRouter = userID%2;
        System.out.println("动态代理分配到 【db"+dbRouter+"】数据库进行处理数据!");
        DataSourceContextHolder.setDBType("db"+String.valueOf(dbRouter));
    }

    /**
     * 后置方法
     */
    private void afterMethod(){
        System.out.println("动态代理 after code");
    }

}

 

订单类:

package com.geely.design.pattern.structural.proxy;

/**
 * 建立订单实体类
 */
public class Order {
    private Object orderInfo;
    //之所以选择integer类型,是为了方便OrderServiceStaticProxy静态代理类进行分库
    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:

package com.geely.design.pattern.structural.proxy;

public interface IOrderDao {
    int insertOrder(Order order);
}

 

订单daoIMPL:

package com.geely.design.pattern.structural.proxy;

public class OrderDaoImpl implements IOrderDao{
    @Override
    public int insertOrder(Order order) {
        System.out.println("新增一条订单!");
        return 1;
    }
}

 

订单Service:

package com.geely.design.pattern.structural.proxy;

public interface IOrderService {
    int saveOrder(Order order);
}

 

订单ServiceIMPL:

package com.geely.design.pattern.structural.proxy;

public class OrderServiceImpl implements IOrderService {
    private IOrderDao orderDao;

    @Override
    public int saveOrder(Order order) {
        //Spring会自己注入,这里我们直接new了
        orderDao = new OrderDaoImpl();
        System.out.println("Service层调用dao层添加Order");
        return orderDao.insertOrder(order);
    }
}

 

打印日志:

Connected to the target VM, address: ‘127.0.0.1:12906‘, transport: ‘socket‘
动态代理 before code
动态代理分配到 【db1】数据库进行处理数据!
Disconnected from the target VM, address: ‘127.0.0.1:12906‘, transport: ‘socket‘
Service层调用dao层添加Order
新增一条订单!
动态代理 after code

Process finished with exit code 0

 

 

 

2    疑难解答
2.1  动态代理invoke怎么执行的?

1.Proxy.newProxyInstance(//参数省略了...)的部分源码

2.程序运行时产生一个类$proxyQ
3.Sproxy0类继承自Proxy类,实现了目标对象的父类接口(借鉴的百度提供的源码

4.Sproxy0类有多个Method成员变量,它的静态代码块给Method赋值为我们自己的接口的实现类的对应的Method对象
5.Sproxyo实现接口的方法调用了super.h.invoke(参数),这里的参数包括Method变量

 

这样就缕顺了,整体流程:
代理对象调接口中的方法---代理对象的真身是$proxy0 调用了对应的方法---此方法内部调用其父类的成员h调用h的invoke方法---就是调用传入了InvocationHandler的invoke方法,至于返回值,那就看我们的InvocationHandler的实现类怎么写了。

这部分参考:https://www.jianshu.com/p/774c65290218

 

设计模式课程 设计模式精讲 16-4 代理模式Coding-动态代理

标签:lang   contex   课程   赋值   print   ret   for   dbr   自己的   

原文地址:https://www.cnblogs.com/1446358788-qq/p/11563452.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!