我们看一下里边都做了什么,这里先打一个断点,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);
}
}