Dynamic proxies proxy mode coding-

我们看一下里边都做了什么,这里先打一个断点,F6,我们在这个方法的最下边先打一个断点,

防止出现问题的时候直接跳过去了,					

    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }
	
    public static <T> T requireNonNull(T obj) {
        if (obj == null)
            throw new NullPointerException();
        return obj;
    }
	
final SecurityManager sm = System.getSecurityManager();

也就是里面传的this,这里面对传入的接口进行安全的检查,
	
这里就是动态代理的核心方法,动态代理的核心思路,生成一个新类,CGLib是生成一个子类,通过这个名字能够看出来

获取一个代理的Proxy0,就是动态的,我们进入这个方法来看一下

Class<?> cl = getProxyClass0(loader, intfs);
	
    /**
     * Generate a proxy class.  Must call the checkProxyAccess method
     * to perform permission checks before calling this.
     */
    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

        // If the proxy class defined by the given loader implementing
        // the given interfaces exists, this will simply return the cached copy;
        // otherwise, it will create the proxy class via the ProxyClassFactory
        return proxyClassCache.get(loader, interfaces);
    }	
	
首先对接口的数量进行了一个判断,	if (interfaces.length > 65535) 

如果一个接口的数量操作65535个,就会报错,提示非法的参数异常,当然这个种情况非常少见,

这个类也是在是太厉害了,可以写6万5千个接口,接着往下看,
	
return proxyClassCache.get(loader, interfaces);

这里面可以看出来,在代理类生成的Class,里面是有一个Cache的,也就是说代理类的缓存,那如果缓存里有这个代理类,

就直接返回,如果没有我们看一下,get里面又做了什么

    public V get(K key, P parameter) {
        Objects.requireNonNull(parameter);

        expungeStaleEntries();

        Object cacheKey = CacheKey.valueOf(key, refQueue);

        // lazily install the 2nd level valuesMap for the particular cacheKey
        ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
        if (valuesMap == null) {
            ConcurrentMap<Object, Supplier<V>> oldValuesMap
                = map.putIfAbsent(cacheKey,
                                  valuesMap = new ConcurrentHashMap<>());
            if (oldValuesMap != null) {
                valuesMap = oldValuesMap;
            }
        }

        // create subKey and retrieve the possible Supplier<V> stored by that
        // subKey from valuesMap
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        Supplier<V> supplier = valuesMap.get(subKey);
        Factory factory = null;

        while (true) {
            if (supplier != null) {
                // supplier might be a Factory or a CacheValue<V> instance
                V value = supplier.get();
                if (value != null) {
                    return value;
                }
            }
            // else no supplier in cache
            // or a supplier that returned null (could be a cleared CacheValue
            // or a Factory that wasn't successful in installing the CacheValue)

            // lazily construct a Factory
            if (factory == null) {
                factory = new Factory(key, parameter, subKey, valuesMap);
            }

            if (supplier == null) {
                supplier = valuesMap.putIfAbsent(subKey, factory);
                if (supplier == null) {
                    // successfully installed Factory
                    supplier = factory;
                }
                // else retry with winning supplier
            } else {
                if (valuesMap.replace(subKey, supplier, factory)) {
                    // successfully replaced
                    // cleared CacheEntry / unsuccessful Factory
                    // with our Factory
                    supplier = factory;
                } else {
                    // retry with current supplier
                    supplier = valuesMap.get(subKey);
                }
            }
        }
    }

这里使用了CocurrentMap,然后对他进行一系列的判断,接着往下走,注意看这里边,这里有一个Factory,就是工厂模式的工厂,

如果Cat里面没有这个代理类的话,就走到while (true)这一行,这里面是while true循环,只有在return value;这里进行返回,

那如果if里面没有进行返回的话,就开始返回这个工厂

factory = new Factory(key, parameter, subKey, valuesMap);

然后把工厂赋值给supplier,然后在上边对工厂进行循环

if (supplier != null) {
	// supplier might be a Factory or a CacheValue<V> instance
	V value = supplier.get();
	if (value != null) {
		return value;
	}
}	
	
这样就获取了这个代理类,接着回到Proxy里面,我们把里面的断点先去掉,F6单步,在try这一片区域呢,我们可以看到,就是根据

生成的Class,通过反射获取对应的构造参数,然后根据这个构造参数呢,生成对应的实例,
	
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            return cons.newInstance(new Object[]{h});
        }	
	
也是通过对应的构造器生成对应的实例,F6单步走,	
	
Class<?> cl = getProxyClass0(loader, intfs);	
	
我们开始讲了有一个getProxyClass0,他们是对应的,所以生成的这个类,就是刚刚那个方法创建的代理类,我们也可以展开来看一下,

他代理的什么类,target,那接下类我们就要调用代理类的saveOrder方法,
	
public interface InvocationHandler {

    /**
     * Processes a method invocation on a proxy instance and returns
     * the result.  This method will be invoked on an invocation handler
     * when a method is invoked on a proxy instance that it is
     * associated with.
     *
     * @param   proxy the proxy instance that the method was invoked on
     *
     * @param   method the {@code Method} instance corresponding to
     * the interface method invoked on the proxy instance.  The declaring
     * class of the {@code Method} object will be the interface that
     * the method was declared in, which may be a superinterface of the
     * proxy interface that the proxy class inherits the method through.
     *
     * @param   args an array of objects containing the values of the
     * arguments passed in the method invocation on the proxy instance,
     * or {@code null} if interface method takes no arguments.
     * Arguments of primitive types are wrapped in instances of the
     * appropriate primitive wrapper class, such as
     * {@code java.lang.Integer} or {@code java.lang.Boolean}.
     *
     * @return  the value to return from the method invocation on the
     * proxy instance.  If the declared return type of the interface
     * method is a primitive type, then the value returned by
     * this method must be an instance of the corresponding primitive
     * wrapper class; otherwise, it must be a type assignable to the
     * declared return type.  If the value returned by this method is
     * {@code null} and the interface method's return type is
     * primitive, then a {@code NullPointerException} will be
     * thrown by the method invocation on the proxy instance.  If the
     * value returned by this method is otherwise not compatible with
     * the interface method's declared return type as described above,
     * a {@code ClassCastException} will be thrown by the method
     * invocation on the proxy instance.
     *
     * @throws  Throwable the exception to throw from the method
     * invocation on the proxy instance.  The exception's type must be
     * assignable either to any of the exception types declared in the
     * {@code throws} clause of the interface method or to the
     * unchecked exception types {@code java.lang.RuntimeException}
     * or {@code java.lang.Error}.  If a checked exception is
     * thrown by this method that is not assignable to any of the
     * exception types declared in the {@code throws} clause of
     * the interface method, then an
     * {@link UndeclaredThrowableException} containing the
     * exception that was thrown by this method will be thrown by the
     * method invocation on the proxy instance.
     *
     * @see     UndeclaredThrowableException
     */
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}	
	
invoke方法的最上边,关于Proxy对象的一个描述,可以看到这个注释说的还是比较清楚的,代理的对象,

@param   proxy the proxy instance that the method was invoked on

也就是说这个方法是属于proxy instance的,那我们接着回来

动态代理是比较核心的,Spring AOP也是建立在JDK的动态代理之上的,当然呢还有CGLib,Spring的AOP也是依赖于JDK

的动态代理的,所以动态代理还是非常重要的,那现在我们通过JDK的动态代理,对AOP进行了一个简单的实现,在目标对象的

方法执行之前,和执行之后呢,都进行了增强,那Spring的AOP也使用到了Proxy这个类,同时他也会使用InvocationHandler这个类,

他也是在这个基础之上,当然这里说的是对接口的代理,CGLib是单独的,那么回到测试类里面,代理模式可以说是AOP非常重要的

一个基础,也是重点来讲了一下,例如说单例模式,代理模式,这种对于我们以后提高非常重要的知识点呢,会重点来讲,希望对静态

代理和动态代理呢,这两块有深刻的认识,同时可以对他们进行一个对比理解	
package com.learn.design.pattern.structural.proxy.dynamicproxy;

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

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

/**
 * 在这里创建一个类
 * OrderServiceDynamicProxy
 * 让他来实现InvocationHandler
 * 然后写一下他的实现方法
 * 
 * 
 * 
 * @author Leon.Sun
 *
 */
public class OrderServiceDynamicProxy implements InvocationHandler {

	/**
	 * 目标对象
	 * 那这个目标对象如何放进来呢
	 * 
	 * 
	 */
    private Object target;

    /**
     * 我们通过构造器
     * 
     * target是目标类
     * 目标类就是OrderService的实现
     * 那里面的DAO没有注入成功
     * 这个忽略就可以了
     * 因为我们是显示而写的
     * 只有saveOrder的时候才会生成
     * 这个忽略就行
     * target目标类已经在这里了
     * 于是给目标代理类target类进行赋值
     * 
     * 
     * 
     * @param target
     */
    public OrderServiceDynamicProxy(Object target) {
        this.target = target;
    }

    /**
     * 然后我们再写一个绑定的方法
     * 这里面就要获取proxy的代理对象
     * 这么一个静态方法
     * 怎么写呢
     * 
     * 他通过Proxy
     * newProxyInstance
     * 来返回代理类
     * 所以这里面分号是不行的
     * 我们还要调用一下他的bind方法
     * 然后对他进行强转
     * 他就是一个IOrderService类型
     * 然后调用它的Order.saveOrder方法
     * 
     * bind打上断点
     * 这个时候就调用了bind这个方法
     * 首先把目标对象的Class拿到
     * 
     * 
     * 
     * @return
     */
    public Object bind(){
    	/**
    	 * 首先获取一个class
    	 * 这个class是目标类的class
    	 * 也就是target的getClass
    	 * 然后return一个对象
    	 * 这个对象通过Proxy.newProxyInstance
    	 * 静态方法
    	 * 来进行生成
    	 * target里面获得ClassLoader
    	 * 从这里面获得接口的一个复数
    	 * 返回值是class类型
    	 * 还有自己
    	 * 这样绑定之后
    	 * 就通过Proxy的newProxyInstance
    	 * 把这个Object就返回回去了
    	 * 那在这个类里面叫OrderService
    	 * 那如果使用动态代理的话
    	 * 这里面可以补充一些判断逻辑
    	 * 如果使用静态代理
    	 * 例如Order在分库的时候
    	 * 我们要写一个Order的静态代理
    	 * 如果这个时候要是有其他的类
    	 * 要做分库的时候
    	 * 还要对那个类写一个静态代理
    	 * 而动态代理不仅仅是针对Order这么一个实体
    	 * 比如说针对这个用户的抽奖信息
    	 * 我们也可以通过userId进行分库
    	 * 都可以通过这一个动态代理进行复用
    	 * 而不用每一个类都写一套静态代理
    	 * 那这个就是动态代理和静态代理很大的一个区别
    	 * 那因为动态代理是动态生成的
    	 * 静态代理要显示的来描述
    	 * 来coding
    	 * 那接下来我们接着写
    	 * 
    	 * 
    	 * 
    	 */
        Class cls = target.getClass();
        /**
         * 然后看一下这行
         * 这行是动态代理的核心
         * 把这个class的ClassLoader
         * 声明的接口
         * 注意这里面是复数
         * 还有他本身自己传进来
         * 那我们就进来看一下
         * 
         */
        return Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),this);
        
    }
//    InvocationHandler h;




    /**
     * 这个方法三个参数
     * 第一个参数在我们平时写动态代理invoke方法的时候
     * 几乎用不上他
     * 那第二个参数是method
     * 也就是说要被增强的方法对象
     * 第三个是具体的method的参数
     * 那我们再说以proxy
     * proxy在这个方法实现里边
     * 很少使用这个对象
     * 那为什么还要传过来呢
     * 一会我们debug的时候
     * 也会来说一下proxy这个对象
     * 我们先写
     * 一会debug的时候
     * 来讲解一下
     * 首先我们声明一个对象
     * 
     * 那在invoke的时候
     * 我们也说了
     * beforeMethod
     * 还有afterMethod
     * 
     * 接着我们回到invoke方法中
     * invoke很简单
     * 我们首先把argument参数拿出来
     * 那因为我们这里面比较简单
     * 对于说这个方法就一个参数
     * 后续逻辑复杂的时候
     * 我们可以自己完善这个逻辑
     * 
     * invoke也打上断点
     * 现在进入到invoke方法里面了
     * invoke有三个参数
     * proxy也就是这个代理类
     * method就是要增强的哪个方法呢
     * saveOrder
     * OrderService这个类的saveorder这个方法
     * 那后边的arguments呢
     * 自然是参数
     * 参数是Order
     * saveOrder的时候传入的参数呢
     * 正是Order
     * 那刚刚我前面有说
     * proxy在invoke的实现里面呢
     * 很少用到他
     * 但是他要传过来
     * 后面的method
     * 和arguments
     * 正来自对应的proxy
     * 很简单
     * 这个proxy代理类
     * 他呢是动态生成的
     * 那有兴趣的可以把这个动态生成的类
     * 进行持久化
     * 然后通过反编译
     * 看一下这个$符的class文件
     * 反编译的过来的代码
     * 里面有获取method
     * 因为这个method是proxy的method
     * 他通过Class.forName
     * 也就是method这个反射包下的method
     * 只有在proxy的这个实例
     * 在我们现在实现的这个接口
     * InvocationHandler
     * 加载之后才能产生对应的method
     * 所以这个生成的proxy
     * 传给invoke方法
     * 我们看一下InvocationHandler接口里面的声明
     * 
     * 现在就要调用method的invoke方法
     * 
     * 
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    	/**
    	 * 首先我们创建一个对象
    	 * argObject等于什么呢
    	 * 等于argument的第0个元素
    	 * 
    	 * 
    	 */
        Object argObject = args[0];
        /**
         * 然后调用beforeMethod
         * 把Order传进去
         * 也就是把这个参数传进去
         * 因为我们在调用saveOrder方法的时候
         * 传的参数正是Order类型
         * 
         * 进入beforeMethod
         * 
         * 
         */
        beforeMethod(argObject);
        /**
         * 那这个时候我们声明一个Object
         * 就是要被增强的方法的返回值
         * 因为增强不同的方法
         * 返回值不一定一样
         * 但是他们的父类都是Object
         * 所以用Object来接他
         * method.invoke
         * invoke什么呢
         * 目标对象target
         * 把参数传进去
         * 
         * 代理哪个类呢
         * target
         * 参数传进来
         * F6单步
         * 这个时候可以看到
         * 进入了真正的目标类的saveOrder方法里边
         * 
         * 
         */
        Object object = method.invoke(target,args);
        /**
         * 我们再调用一下afterMethod
         * 
         * 
         */
        afterMethod();
        /**
         * 最后把方法的返回值返回回去
         * 那这个动态代理就写完了
         * 非常简单
         * 我们现在写一个Test来run一下
         * 
         * 
         */
        return object;
    }

    /**
     * 我们先写一个beforeMethod
     * 用动态代理来实现
     * 这里我们就把调用方法的参数
     * 传进来
     * 传进来干嘛呢
     * 进行取模运算
     * 
     * 我们就要把数据库确定了
     * 我们现在写一下
     * 
     * 通过obj的一个类型
     * instanceof这么一个判断
     * 然后进行相同的取模逻辑
     * 确定目标DB
     * 
     * 到这里边单步走
     * 
     * 
     * @param obj
     */
    private void beforeMethod(Object obj){
    	/**
    	 * 首先初始化一个userId等于0
    	 * 那我们就要在beforeMethod里面
    	 * 对userId进行取模
    	 * 然后确定分配到哪个db上
    	 * 当然分配到哪个db上
    	 * 我们可以把里面的实现
    	 * 写到invoke里边
    	 * 
    	 * 动态代理
    	 * 
    	 * 
    	 */
        int userId = 0;
        System.out.println("动态代理 before code");
        /**
         * 如果obj是Order类型
         * 刚刚说了
         * 那我们也可以在这里进行判断
         * 抽奖信息这个类
         * 我们只有Order这个类
         * 
         * 然后进行类型判断
         * 
         * 
         */
        if(obj instanceof Order){
        	/**
        	 * 如果是这个类型就对他进行强转
        	 * obj强转成Order
        	 * 
        	 * 
        	 */
            Order order = (Order)obj;
            /**
             * 然后把userId赋值
             * 通过order的getUserId
             * 接下来就和静态代理是一样的
             * 我们把这里面的拿过来
             * copy到这里面
             * 
             * 对userId进行赋值
             * 
             * 
             */
            userId = order.getUserId();
        }
        /**
         * 取模
         */
        int dbRouter = userId % 2;
        /**
         * 这里面是动态代理db
         * 
         * 
         * 
         */
        System.out.println("动态代理分配到【db"+dbRouter+"】处理数据");

        //todo 设置dataSource;
        DataSourceContextHolder.setDBType("db"+String.valueOf(dbRouter));
    }

    private void afterMethod(){
    	/**
    	 * 这里面是动态代理after code
    	 * 
    	 * 
    	 */
        System.out.println("动态代理 after code");
    }
}
package com.learn.design.pattern.structural.proxy.staticproxy;

import com.learn.design.pattern.structural.proxy.IOrderService;
import com.learn.design.pattern.structural.proxy.Order;
import com.learn.design.pattern.structural.proxy.OrderServiceImpl;
import com.learn.design.pattern.structural.proxy.db.DataSourceContextHolder;

/**
 * 这个类是静态代理类
 * OrderService的静态代理
 * 这里面也很简单
 * 我们首先在这个静态代理类里边
 * 
 * 
 * @author Leon.Sun
 *
 */
public class OrderServiceStaticProxy {
	/**
	 * 来注入目标对象
	 * 那这里面的IOrderService
	 * 是目标对象
	 * 我们要对saveOrder方法
	 * 进行增强
	 * 那我们来到orderService里边
	 * 
	 * 
	 */
    private IOrderService iOrderService;

    /**
     * 当然使用不同的方法名也是OK的
     * 这里面并没有严格的限制
     * 写一个before和after
     * 那后面我们讲源码解析的时候
     * 也会领着大家来看一下
     * 那就是Spring里面的beforeAdvice
     * 在AOP包下的
     * 还有afterAdvice
     * 只不过我们通过静态代理
     * 非常简单的一个实现
     * 所以我们声明两个方法
     * 一个beforeMethod
     * 还有一个
     * afterMethod
     * 直接输出
     * 输出什么呢
     * 
     * 
     * @param order
     * @return
     */
    public int saveOrder(Order order){
    	/**
    	 * 首先调用beforeMethod
    	 * 
    	 * 
    	 */
        beforeMethod(order);
        /**
         * 先把这个Service new出来
         * 这里面和DAO层一样
         * 如果使用Spring容器的话就不需要显示的来new了
         * 那现在我们获取userId
         * 
         * service的实现
         * 如果使用Spring容器的话
         * 这里面不需要显示的来new他
         * 
         * 
         */
        iOrderService = new OrderServiceImpl();
        /**
         * 调用saveOrder方法
         * 然后把Order传进来
         * Spring的分库实现
         * 首先我们创建一个包
         * 这个包叫db
         * 这里面我们创建一个类
         * DynamicDataSource
         * 动态的数据源
         * 
         * 
         */
        int result = iOrderService.saveOrder(order);
        /**
         * 这个after我们要拿到对应的saveOrder之后
         * 也就是我们增强的是saveOrder
         * 怎么办呢
         * 在这里面再优化一下
         * 然后调用afterMethod
         * 这里面的界限怎么划分呢
         * 很简单
         * saveOrder是为了增强OrderService的saveOrder
         * 所以我们要把saveOrder这一行
         * 单独领出来
         * 那执行完saveOrder之后
         * 这个才是比较符合代理模式
         * 那像刚才这种实现方案
         * afterMetho和beforeMethod
         * 都在saveOrder前面
         * 都是一个beforeMethod
         * 所以这里埋了一个伏笔
         * 就是要对这一段要印象深刻
         * 那现在这种实现
         * 通过before就把目标数据库
         * 已经确定了
         * 那这块大家肯定都理解了
         * 
         * 
         * 
         */
        afterMethod();
        return result;
    }

    /**
     * 执行saveOrder之前要执行的
     * 
     * 那首先在saveOrder之前
     * 我们调用一下beforeMethod
     * 对saveOrder进行一个增强
     * 
     * beforeMethod里面并没有写实现
     * 而是把分库的实现写到saveOrder里边
     * 所以这个时候静态代理
     * 我们就要改进一下了
     * 如何改进呢
     * 很简单
     * 例如beforeMethod把order传进来
     * 我们要把方法的界限划清楚
     * 执行代理模式的时候
     * 很容易划分不清楚
     * 埋了一个伏笔
     * 那这个初始化还是放到这里边
     * 我们把下边拿走
     * 拿到beforeMethod这里边
     * 然后调用的时候传进来
     * 但是我们又想一下
     * 
     * 
     * 
     * @param order
     */
    private void beforeMethod(Order order){
    	/**
    	 * order获取userId
    	 * 
    	 * 
    	 * 
    	 */
        int userId = order.getUserId();
        /**
         * 获得DB的路由编号
         * 用userId对2进行取模
         * 这样只会得到0或者1
         * 
         * 在这里取完模之后呢
         * 我们就要写一段代码
         * 设置dataSource
         * 怎么设置呢
         * 
         * 然后对2取模
         * 2对2取余余数是0
         * 所以dbRouter是0
         * 
         * 
         */
        int dbRouter = userId % 2;
        /**
         * 然后我们输出一下
         * 静态代理增强了OrderService的实现
         * 把DB切到DB Router这个上
         * db0或者db1
         * 
         * 输出这一行
         * 
         * 
         */
        System.out.println("静态代理分配到【db"+dbRouter+"】处理数据");

        //todo 设置dataSource;
        /**
         * 我们直接调用DataSourceContextHolder
         * 我们自己写的
         * 然后setDBType
         * 把什么传进来呢
         * 把dbRouter
         * 只不过我们现在这里没有和Spring容器集成
         * String类型的
         * String.valueOf
         * 那这个静态代理类就写完了
         * 根据userId的不同
         * 插入到不同的DB当中
         * 一个是db0
         * 一个是db1
         * 那我们现在来到静态代理这个包下
         * 写一个Test
         * 
         * 然后把DataSourceContextHolder里面的DBType
         * 设置为0
         * 当然这里讲代理模式的时候
         * 这一行执不执行都没关系
         * 只不过这里面只是为了扩展
         * 所以分库的一些知识点
         * 调一下他的getDBType
         * 可以看到这里面是0
         * 那这里面是有问题的
         * 这里面要存的是db0
         * 也就是说在写分库的时候
         * 这里很容易忽略
         * 里面的dbType和我们配置文件里面的是一样
         * 这里不要出bug
         * 而我在这里面就做了一个反面教材
         * 
         * 
         * 
         */
        DataSourceContextHolder.setDBType("db"+String.valueOf(dbRouter));
        System.out.println("静态代理 before code");
    }
    /**
     * 这个是执行saveOrder之后要执行的代码
     * 
     * 
     */
    private void afterMethod(){
        System.out.println("静态代理 after code");
    }
}
package com.learn.design.pattern.structural.proxy.dynamicproxy;

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

/**
 * 我们看到结果和预期是一样的
 * 动态代理before code
 * 然后动态代理分配到db0上处理数据
 * service层调用DAO层
 * 添加Order
 * DAO层添加Order成功
 * 动态代理after code
 * 这里和预期完全一致
 * 分配到db1上处理数据
 * 和预期是一样的
 * 那接下来我们debug来跑一下
 * 同时进行讲解
 * 那我们直接在这里面打上两个断点
 * 然后debug来跑一下
 * 首先进入这个动态代理类的构造器
 * 我们进来
 * 
 * 
 * 
 * @author Leon.Sun
 *
 */
public class Test {
	/**
	 * 写一个主函数
	 * 如何测试呢
	 * 
	 * 这里和静态的测试类差不多
	 * 我们先拿过来
	 * 
	 * 
	 * @param args
	 */
    public static void main(String[] args) {
    	/**
    	 * 声明一个Order
    	 * new一个Order出来
    	 * 
    	 * 
    	 */
        Order order = new Order();
        /**
         * 注意1对2取模的时候
         * 余数是1
         * 2对2取余的时候
         * 余数是0
         * 所以我们在run的时候
         * 这里面应该是db0数据库
         * 我们run一下
         * 结果已经出来了
         * 和我们预期是一样的
         * 那我们现在debug来运行一下
         * 我们一起来体会一下
         * 流程是怎么走的
         * 直接debug
         * 
         * 
         */
        order.setUserId(2);
        /**
         * 现在我们设置userId
         * 为1
         * 
         * 
         */
//        order.setUserId(1);
        /**
         * 然后获取静态代理类
         * 我们就直接new一个好了
         * 那在实际的项目当中
         * 我们可以在这个代理类上增加注解
         * 比如说Component
         * 来表示这个类是一个组件
         * 这样的话我们直接使用就可以了
         * 那这里面我们采用new的方式
         * 是为了讲解方便
         * 
         * 我们进到这个静态代理类里边
         * 
         * 我们使用OrderService这么一个接口
         * 我们现在是动态代理
         * 我们直接代理这个接口就OK了
         * 所以用接口来接收他
         * orderServiceDynamicProxy这个不是静态代理
         * 而是动态代理
         * 看一下后边
         * 后边要怎么写呢
         * 我们首先要new一个动态代理这个类
         * 然后传入一个参数
         * 我们要增强哪个类呢
         * 当然是要增强service的实现
         * 也就是OrderServiceImpl
         * 这么一个类
         * 但是呢并没有结束
         * 注意我们在动态代理里面写的
         * 返回值bind这个方法
         * 
         * 可以看到现在这个代理类
         * 我们来看一下这个类型
         * 他呢是一个$Proxy0
         * 是这么一个类型
         * 但是它是用IOrderService进行引用声明的
         * 
         * 
         */
        IOrderService orderServiceDynamicProxy = (IOrderService) new OrderServiceDynamicProxy(new OrderServiceImpl()).bind();

        /**
         * 然后我们调用它的saveOrder方法
         * order传进来
         * 我们直接run一下
         * 我们看一下结果
         * 首先静态执行了beforeMethod
         * 然后把它分配到db1上处理数据
         * 然后执行了afterCode
         * 也就是afterMethod里面的内容
         * 然后service层调用了DAO层
         * 添加Order
         * DAO层添加order成功
         * 那我们现在把它改成2
         * 
         * 
         */
        orderServiceDynamicProxy.saveOrder(order);
    }
}
package com.learn.design.pattern.structural.proxy;

/**
 * @author Leon.Sun
 *
 */
public interface IOrderService {
	/**
	 * 这里面有一个方法
	 * saveOrder
	 * 里面传一个实体Order
	 * 保存这个订单
	 * 再写一个DAO层的接口
	 * 
	 * 我们要增强这个方法
	 * 所以我们使用同样的方法名
	 * 
	 * 
	 * 
	 * @param order
	 * @return
	 */
    int saveOrder(Order order);
}
package com.learn.design.pattern.structural.proxy;

/**
 * 他来实现IOrderService
 * 实现IOrderService里的方法
 * 当然我们现在这个分层比较简单
 * Service下边是DAO
 * 那在Service之上是Controller
 * 那也有业务逻辑复杂的情况下呢
 * 加一个Manager层
 * Manager位于DAO层之上
 * 
 * 
 * @author Leon.Sun
 *
 */
public class OrderServiceImpl implements IOrderService {
	/**
	 * 把DAO层注入进来
	 * 只不过我们这里并没有集成Spring
	 * 所以像@Autowired和@Resource我们并不用加
	 * 然后我们会通过人工注入的方式
	 * 把OrderDao注入进来
	 * 那我们写一个Service的实现
	 * 
	 */
    private IOrderDao iOrderDao;


    @Override
    public int saveOrder(Order order) {
        //Spring会自己注入,我们课程中就直接new了
    	/**
    	 * 我们课程中就直接new了
    	 * 直接new出来
    	 * DAO层的implement
    	 * 当然如果这一行使用Spring容器管理的话
    	 * 我们就不用显示的来写了
    	 * 或者在应用层使用set方法注入进来
    	 * 或者通过构造器注入也是OK的
    	 * 我们为了简单
    	 * 直接在这里new了
    	 * 但是我们实际在也业务的时候
    	 * 是不应该这么写的
    	 * 因为这样DAO层会new很多对象
    	 * 那对于DAO层来说
    	 * 保持一个单例是OK的
    	 * 
    	 * 这里面创建了一个DAO层
    	 * 
    	 * 
    	 */
        iOrderDao = new OrderDaoImpl();
        /**
         * 然后我们输出
         * service层调用DAO添加Order
         * 
         * 
         */
        System.out.println("Service层调用Dao层添加Order");
        /**
         * DAO层调用insert方法
         * 把Order传进来
         * 那这个Service实现就写完了
         * 那我们再看一下包
         * 这个包的类是非常的common的
         * 实体
         * DAO层
         * service层
         * 只不过我们讲设计模式都放在这个包下了
         * 下面我们就不分包了
         * 那现在我们要进行分库了
         * 怎么分库呢
         * 我们看一下Order
         * 
         * 调用DAO的insert方法
         * 
         * 
         */
        return iOrderDao.insert(order);
    }
}

 

Guess you like

Origin blog.csdn.net/Leon_Jinhai_Sun/article/details/91385274