简介
为其他对象提供一种代理,以控制对这个对象的访问,代理对象在客户端和目标对象之间起到中介的作用,使用代理可以简单的转发到实际对象,也可以提供额外的逻辑,这个完全取决于你的代理类是怎么实现的。代理类可以提供额外的功能,比如如果实际对象需要消耗很多资源那么代理类可以进行缓存,也可以在调用实际对象之前作参数验证等。
对于客户端,他们在使用代理类的时候,就感觉是在使用实际的对象,因为代理类和实际对象拥有相同的接口,该模式属于结构型。
适用场景
1、需要对对象的访问进行控制。
2、访问对象时应该提供额外的功能(增强目标对象)。
3、保护目标对象
优点
1、可以代替另一个对象
2、代理对象与真实被调用的对象进行分离
3、一定程度降低了系统的耦合度,扩展性好
4、保护目标对象
5、增强目标对象
缺点
1、系统中类的数目增加
2、造成请求速度变慢
3、增加系统的复杂度
扩展
1、静态代理
在代码中显式的定义了业务实现类的代理,在代理类中使用实际对象中相同的方法,让客户端可以使用代理类的方法来调用实际对象类。
2、动态代理
对接口的方法动态生成接口中的同名方法,来进行调用,注意:这里必须是接口。
3、CGLib代理
通过继承来实现的,生成的代理类就是业务类的子类,然后重写业务方法来进行代理。
使用注意点:
1、final方法不能被代理
2、代理对象的构造函数将被调用两次,CGLib会对每个代理对象生成一个子类
3、你需要CGBlib二进制文件在classpath下面,然而动态代理在jdk中依旧可用,Spring会发出警告,如果它没有发现GBLib的类在classpth里面。
spring扩展
1、当Bean有实现接口时,Spring就会用JDK的动态代理
2、当Bean没有实现接口时,Spring使用CGLib
可以强制使用CGLib
<aop:aspectj-autoproxy proxy-target-class="true" />
代码示例
静态代理
订单接口
public interface OrderService {
String saveOrder(Integer userId);
}
订单实现类
public class OrderServiceImpl implements OrderService{
public String saveOrder(Integer userId) {
System.out.println("创建订单,用户id为:"+userId);
return "sn123456";
}
}
静态代理类
public class OrderServiceStaticProxy {
private OrderService orderService;
public String saveOrder(Integer userId) {
methodBefore();
if(null == orderService){
orderService = new OrderServiceImpl();
}
String orderNo = orderService.saveOrder(userId);
methodAfter();
return orderNo;
}
private void methodBefore(){
System.out.println("订单前校验参数");
}
private void methodAfter(){
System.out.println("订单完成之后做点什么事情");
}
}
测试类
public class StaticProxyTest {
public static void main(String[] args) {
OrderServiceStaticProxy orderServiceStaticProxy = new OrderServiceStaticProxy();
orderServiceStaticProxy.saveOrder(1);
}
}
输出结果:
订单前校验参数
创建订单,用户id为:1
订单完成之后做点什么事情
动态代理
对相同功能的处理不需要创建多个类,只需要一个动态代理类就可以了,但是静态代理类需要创建多个类。
订单类
public class Order {
private Integer userId;
private String orderNo;
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getOrderNo() {
return orderNo;
}
public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
@Override
public String toString() {
return "Order{" +
"userId=" + userId +
", orderNo='" + orderNo + '\'' +
'}';
}
}
订单接口
public interface OrderService {
Order saveOrder(Order order);
}
订单实现类
public class OrderServiceImpl implements OrderService{
public Order saveOrder(Order order) {
order.setOrderNo("sn123");
System.out.println("保存订单数据");
return order;
}
}
动态代理类
public class OrderServiceDynamicProxy implements InvocationHandler {
private Object target;
public OrderServiceDynamicProxy(Object target) {
this.target = target;
}
public Object bind(){
Class cls = target.getClass();
return Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),this);
}
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;
}
private void beforeMethod(Object obj){
if(obj instanceof Order){
Order order = (Order)obj;
System.out.println("保存之前订单参数进行校验");
}
}
private void afterMethod(){
System.out.println("保存成功之后做点事情");
}
}
测试类
public class DynamicProxyTest {
public static void main(String[] args) {
Order order = new Order();
order.setUserId(1);
OrderService proxy = (OrderService) new OrderServiceDynamicProxy(new OrderServiceImpl()).bind();
order = proxy.saveOrder(order);
System.out.println("订单数据"+order);
}
}
输出结果
保存之前订单参数进行校验
保存订单数据
保存成功之后做点事情
订单数据Order{userId=1, orderNo='sn123'}
源码分析
jdk中应用
Proxy
类就是代理的实现。
spring中应用
mybatis中应用
注意:本文归作者所有,未经作者允许,不得转载