- 定义:为其他对象提供代理,以控制对这个对象的访问,代理对象在客户端和目标对象之间起到中介的作用。
- 使用场景:
- 保护目标对象,客户端并不知道具体调用了哪一个目标对象。
- 增强目标对象
- 优点
- 代理模式能够将代理对象与真实被调用的目标对象分离
- 一定程度上降低了系统的耦合度,扩展性好(待进一步分析)
- 缺点
- 使用代理模式需要添加代理类,会导致系统设计中类数目的增加
- 在客户端和目标对象之间增加了一个代理对象,会造成请求处理速度变慢
- 增加了系统的复杂度
代理模式分类: 静态代理、jdk动态代理、cglib代理类。
静态代理:在代码中显示定义一个业务实现类进行代理,对目标对象的方法进行进一步的封装,只能代理某一个固定的目标对象。
下面的uml类图中,代理类OrderServiceStaticService中包含被代理对象OrderService,在代理类中对被代理对象的被代理方法进行增强,客户端直接调用代理类的createOrder方法(被代理的方法)即可。
jdk动态代理:jdk动态代理无法代理类,只能代码接口(即目标对象必须实现接口),代理类时运行时由jvm根据业务实现类对象和方法名动态地创建一个代理类的class文件,此class文件被字节码引擎执行,通过代理类对象进行方法调用。
jdk动态代理的使用:
/**
代理得业务逻辑类,必须实现InvocationHandler接口并重写invoke()方法,
代理类方法的调用都会映射到此类的invoke()方法,所以这是一个实际调用的方法。
*/
public class OrderServiceDynamicProxy implements InvocationHandler {
private Object target;
public OrderServiceDynamicProxy(Object target) {
this.target = target;
}
/**
* 获取代理类
* @return
*/
public Object bind(){
Class cls = target.getClass();
Object obj = Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),this);
return obj;
}
/**
*
* @param proxy
* @param method 需要被增强的method方法
* @param args 被增强方法的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
beforeMethod(args[0]);
Object obj = method.invoke(target,args);
afterMethod();
return obj;
}
private void beforeMethod(Object obj){
System.out.println("动态代理 before code");
// 动态代理在一个业务逻辑类中处理不同的被代理对象
if (obj instanceof Order){
Order order = (Order)obj;
int userId = order.getUserId();
// 根据userId获取db路由
int dbRouter = userId % 2;
System.out.println("动态理分配到[db" + dbRouter + "]处理数据");
}else {
}
}
private void afterMethod(){
System.out.println("动态代理 after code");
}
}
/*
客户端类
*/
public class Test {
public static void main(String[] args){
// ============动态代理测试=================================
// OrderServiceImpl是需要被代理的类,实现了IOrderService接口,createOrder()是需要备注增强的方法。
IOrderService dynamicProxy = (IOrderService) new OrderServiceDynamicProxy(new OrderServiceImpl()).bind();
dynamicProxy.createOrder(order);
}
}
cglib代理类:可以代理类(没有实现接口),它针对类实现进行代理。cglib的实现原理很简单,它会生成一个被代理类的子类,覆盖其中的方法,也就是通过继承和重写。(注意被代理类和被代理方法都不能) cglib动态代理的使用
/*
cglib业务逻辑处理类,必须实现methodInterceptor接口,
并重写intercept()方法,在方法中对目标方法进行增强。
*/
public class OrderServiceCglibDynamicProxy implements MethodInterceptor {
/**
*创建CGLIB代理对象
* @return
*/
public Object createProxyObject(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OrderServiceImpl.class);
enhancer.setCallback(new OrderServiceCglibDynamicProxy());
return enhancer.create();
}
@Override
public Object intercept(Object target, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
beforeMethod(objects[0]);
Object result = methodProxy.invokeSuper(target,objects);
afterMethod();
return result;
}
/**
* 被代理方法执行前的处理
* @param obj
*/
private void beforeMethod(Object obj){
System.out.println("CGLIB动态代理 before method");
if (obj instanceof Order){
Order order = (Order) obj;
int userId = order.getUserId();
int dbRouter = userId%2;
System.out.println("动态代理分配到db" + dbRouter+"上");
}else {
// 参数不是Order对象,做其它处理
}
}
/**
*被代理方法执行后的处理
*/
private void afterMethod(){
System.out.println("CGLIB动态代理 after method");
}
}
客户端调用:
public class Test {
public static void main(String[] args){
Order order = new Order();
order.setUserId(1);
// ============CGLIB动态代理测试===========================
OrderServiceCglibDynamicProxy orderServiceCglibDynamicProxy = new OrderServiceCglibDynamicProxy();
OrderServiceImpl orderService = (OrderServiceImpl) orderServiceCglibDynamicProxy.createProxyObject();
orderService.createOrder(order);
}
控制台输出结果:
CGLIB动态代理 before method
动态代理分配到db1上
service层调用dao层
数据库订单创建成功
CGLIB动态代理 after method
- spring的默认代理选择
- bean没有实现接口->cglib
- bean实现接口->jdk动态代理
- 代理速度对比
- cglib动态代理底层是采用asm字节码0生成的,这种方要式比使用java反射效率要高,jdk动态代理的速度相对要比cglib的速度要快。
参考资料:geely老师的教学,本文仅做个人笔记使用。