一、定义与类型:
》定义:为其他对象提供一种代理,以控制对这个对象的访问;
》代理对象在客户端和目标对象之间起到中介的作用;例如:我们通过房产中介租房。
》类型;结构型
二、适用场景:
》保护目标对象。比如不知道真实房东是谁
》增强目标对象。控制客户端对目标对象的访问
租房前草拟合同就相当于对目标对象进行增强,相当于spring AOP中的before
租房子相当于目标对象
而租房到期后,计算水电费等后续工作,就相当于Spring AOP中的after,后续增强
三、代理模式的优点:
》代理模式能将代理对象与真实被调用的目标对象分离;
》一定程度上降低了系统的耦合度,扩展性好;
》保护目标对象;客户端对象不会直接了解到目标对象信息
》增强目标对象
四、缺点:
》代理模式会造成系统设计中类的数目增加,即代理类的添加
》在客户端和目标对象之间增加一个对象,会造成请求处理速度变慢。压测、大批量测试、
多线程等会检测出该问题
》增加系统的复杂度
五、代理——扩展:
》静态代理:在代码中通过代理类显式地看到代理类
》动态代理:jdk中的动态代理只能对实现接口的类生成代理类。动态代理无法代理类,只能代理接口。jdk中的动态代理是在程序调用到代理类对象时,才由jvm动态创建一个代理类的class文件,进而产生对象等。另外一种case,如果一个接口中有两个方法,也写了这个接口的实现,若在接口实现(代理类)中增加了新方法,而接口中没有该方法,那新方法也是无法被代理的。
》CGLib代理:CGLib相较于动态代理,是说该代理方式可以代理类.CGLib就是针对类实现进行代理。该代理原理是,继承要代理的类,然后重写其中的方法,进而实现代理。因为该方案是通过继承实现的,所以受限于final修饰符的使用。因为final修饰类,则该类无法被继承。如果final修饰方法,方法不可被重写,则该方案无法使用。故特别注意final修饰符。
六、spring代理选择——扩展:
》当Bean有实现接口时,spring就会用jdk的动态代理。
》当Bean没有实现接口时,spring使用CGLib
》可以强制使用CGLib
>在spring配置中加入:<aop:aspectj-autoproxy proxy-target-class="true"/>
七、代理速度对比——扩展:
CGlib是通过底层asm实现的,如果使用cglib代理,会比静态代理快
jdk的动态代理,在10000次运算时,jdk7/jdk8的动态代理速度比CGLib大约快20%
八、代理模式的相关设计模式:
》代理模式和装饰者模式:实现方案类似,但目标不同。装饰者模式是为对象加上行为,而
代理模式是控制访问,更加倾向于通过设置代理人的方式增强目标对象。增强目标对象的方式
一般是增强对象的行为
》代理模式和适配器模式:适配器模式主要考虑改变代理对象的接口,而代理模式不会改变代理对象的接口。
九、代码实践:
代码场景以添加订单到数据库为例,分基础最经典的三层dao service 业务层为例
添加数据到数据库的代码为基础代码,然后分别使用静态代理和动态代理两种方式演示
代理模式的使用,来实现简单的spring框架中的aop原理讲解
共用代码:
package pattern.structural.Proxy;
/**
* Created by Administrator on 2019/8/18.
*/
public class Order {
private String orderInfo;
//用于作为后面分库分表演示的一个判断属性
private Integer userId;
public String getOrderInfo() {
return orderInfo;
}
public void setOrderInfo(String orderInfo) {
this.orderInfo = orderInfo;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
}
package pattern.structural.Proxy;
/**
* Created by Administrator on 2019/8/18.
*/
public interface IOrderDao {
int insertOrder(Order order);
}
package pattern.structural.Proxy;
/**
* Created by Administrator on 2019/8/18.
*/
public class OrderDaoImpl implements IOrderDao {
public int insertOrder(Order order) {
System.out.println("添加order成功");
return 1;
}
}
package pattern.structural.Proxy;
/**
* Created by Administrator on 2019/8/18.
*/
public interface IOrderService {
int saveOrder(Order order);
}
package pattern.structural.Proxy;
/**
* Created by Administrator on 2019/8/18.
*/
public class OrderServiceImpl implements IOrderService {
private IOrderDao iOrderDao;//如果用spring自动注入,此处要添加相应注解
public int saveOrder(Order order) {
//Spring会自动注入,此处因为没有spring环境,就直接new对象了
iOrderDao = new OrderDaoImpl();
System.out.println("Service层调用Dao层添加order方法");
return iOrderDao.insertOrder(order);
}
}
》》》静态代理模式演示:
package pattern.structural.Proxy.staticProxy;
import pattern.structural.Proxy.IOrderService;
import pattern.structural.Proxy.Order;
import pattern.structural.Proxy.OrderServiceImpl;
/**
* Created by Administrator on 2019/8/18.
*/
public class OrderServiceStaticProxy {
private IOrderService iOrderService;
public OrderServiceStaticProxy(IOrderService iOrderService) {
this.iOrderService = iOrderService;
}
public int saveOrder(Order order){
beforeMethod(order);
iOrderService = new OrderServiceImpl();
int res = iOrderService.saveOrder(order);
aftgerMethod();
return res;
}
private void beforeMethod(Order order){
//代理模式之增强目标对象,如下演示了,在此可以做比如为mysql数据库添加数据时,
//可以在此进行分库分表的逻辑判断操作。此处只是简单示意。
int userId = order.getUserId();
int dbRouter = userId % 2;
System.out.println("静态代理分配到[db"+dbRouter+"进行处理");
System.out.println("静态代理 befor code");
}
private void aftgerMethod(){
System.out.println("静态代理 after code");
}
}
package pattern.structural.Proxy.staticProxy;
import pattern.structural.Proxy.Order;
import pattern.structural.Proxy.OrderServiceImpl;
/**
* Created by Administrator on 2019/8/18.
*/
public class Test {
public static void main(String[] args) {
Order order = new Order();
order.setUserId(1);
OrderServiceStaticProxy orderServiceStaticProxy = new OrderServiceStaticProxy(new OrderServiceImpl());
orderServiceStaticProxy.saveOrder(order);
}
}
"D:\Program Files\Java\jdk1.8.0_102\bin\java" "-javaagent:D:\InteliijIDea\IntelliJ IDEA 2017.1.4\lib\idea_rt.jar=61656:D:\InteliijIDea\IntelliJ IDEA 2017.1.4\bin" -Dfile.encoding=UTF-8 -classpath "D:\Program Files\Java\jdk1.8.0_102\jre\lib\charsets.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\deploy.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\access-bridge-64.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\cldrdata.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\dnsns.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\jaccess.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\jfxrt.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\localedata.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\nashorn.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\sunec.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\sunjce_provider.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\sunmscapi.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\sunpkcs11.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\zipfs.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\javaws.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\jce.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\jfr.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\jfxswt.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\jsse.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\management-agent.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\plugin.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\resources.jar;D:\Program Files\Java\jdk1.8.0_102\jre\lib\rt.jar;E:\JavaDesignMode\target\classes" pattern.structural.Proxy.staticProxy.Test
静态代理分配到[db1进行处理
静态代理 befor code
Service层调用Dao层添加order方法
添加order成功
静态代理 after code
Process finished with exit code 0
》》》动态代理演示:
package pattern.structural.Proxy.dynamicproxy;
import pattern.structural.Proxy.Order;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* Created by Administrator on 2019/8/18.
*/
public class OrderServiceDynamixProxy implements InvocationHandler {
private Object target;
public OrderServiceDynamixProxy(Object target) {
this.target = target;
}
public Object bind(){
Class cls = target.getClass();
//如下第一个参数为代理类对象加载器,第二个为类的各个属性
/** * @param loader the class loader to define the proxy class
* @param interfaces the list of interfaces for the proxy class
* to implement
* @param h the invocation handler to dispatch method invocations to
* */
return Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),this);
}
//proxy在这个方法中很少被使用method就是目标对象的方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object argObject = args[0];
beforeMethod(argObject);
Object object = method.invoke(target,args);
afterMethod();
return object;
}
public void beforeMethod(Object object){
int userId =0;
System.out.println("动态代理 before code");
if (object instanceof Order) {
Order order = (Order) object;
userId = order.getUserId();
}
int dbRouter = userId % 2;
System.out.println("动态代理分配到[db}"+dbRouter+"处理");
}
private void afterMethod(){
System.out.println("动态代理 after code");
}
}
package pattern.structural.Proxy.dynamicproxy;
import pattern.structural.Proxy.IOrderService;
import pattern.structural.Proxy.Order;
import pattern.structural.Proxy.OrderServiceImpl;
import pattern.structural.Proxy.staticProxy.OrderServiceStaticProxy;
/**
* Created by Administrator on 2019/8/18.
*/
public class Test {
public static void main(String[] args) {
Order order = new Order();
order.setUserId(2);
IOrderService orderServiceDynamicProxy = (IOrderService) new OrderServiceDynamixProxy(new OrderServiceImpl()).bind();
orderServiceDynamicProxy.saveOrder(order);
}
}
动态代理 before code
动态代理分配到[db}0处理
Service层调用Dao层添加order方法
添加order成功
动态代理 after code
Process finished with exit code 0
十、代理模式源码解析(jdk+spring+mybatis):
1、搜索 jdk中java.lang.reflect
2、ProxyFactoryBean 核心方法getObject();
jdkDynamicAopProxy 类
CglibAopProxy 类
3、mybatis MapperProxyFactory newInstance() MapperRegist
MapperProxy类 invoke方法
Configuration getMapper();