代理设计模式主要对方法前后实现增强
应用场景
1 打印日志
2 AOP底层通过代理模式封装
3 事务@Transactional 底层AOP
4 Mybatis中的mapper接口
5 全局捕获异常
6 Lcn、Seata、分表分库框架sharding-jdbc 代理数据源
7 自定义注解生效
8 Rpc远程调用技术(通过dubbo调用接口只会引入接口)
代理模式优缺点
优点:实现扩展功能、对方法实现增强、安全性、解决代码冗余提高代码复用机制
缺点:生成非常多的class文件(代理类)
代理模式的分类
静态代理与动态代理
代理模式实现的原理
代理模式主要包含三个角色,即抽象主题角色(Subject)、委托类角色(被代理角色,Proxied)以及代理类角色(Proxy),如图所示:
- 抽象主题角色:可以是接口,也可以是抽象类;
- 委托类(被代理类)角色:真实主题角色,业务逻辑的具体执行者;
- 代理类角色:内部含有对真实对象的引用,负责对真实主题角色的调用,并在真实主题角色处理前后做预处理和后处理。
eg:买房 中介 卖房(被代理类)
1.静态代理的实现方式
基于接口实现(Jdk动态代理)和继承模式(Cglib字节码)
1.1 基于接口方式
接口
public interface OrderService {
String addOrder(String orderId, String orderName);
}
实现类
public class OrderServiceImpl implements OrderService {
@Override
public String addOrder(String orderId, String orderName) {
System.out.println("OrderServiceImpl真实方法执行...");
return orderId + "," + orderName;
}
}
代理类
public class OrderServiceProxy implements OrderService {
//被代理类
private OrderServiceImpl orderServiceImpl;
public OrderServiceProxy(OrderServiceImpl orderServiceImpl) {
this.orderServiceImpl = orderServiceImpl;
}
@Override
public String addOrder(String orderId, String orderName) {
System.out.println("采用代理模式统一打印日志 orderId:" + orderId + ",orderName:" + orderName);
return orderServiceImpl.addOrder(orderId, orderName);
}
}
测试
public class Test {
public static void main(String[] args) {
OrderService orderServiceProxy = new OrderServiceProxy(new OrderServiceImpl());
orderServiceProxy.addOrder("mayikt", "111");
}
}
1.2 基于继承方式
接口
public interface OrderService {
String addOrder(String orderId, String orderName);
}
实现类
public class OrderServiceImpl implements OrderService {
@Override
public String addOrder(String orderId, String orderName) {
System.out.println("OrderServiceImpl真实方法执行...");
return orderId + "," + orderName;
}
}
代理类
public class OrderServiceProxy extends OrderServiceImpl {
@Override
public String addOrder(String orderId, String orderName) {
System.out.println("采用代理模式统一打印日志 orderId:" + orderId + ",orderName:" + orderName);
return super.addOrder(orderId, orderName);
}
}
测试
public class Test {
public static void main(String[] args) {
OrderService orderServiceProxy = new OrderServiceProxy();
orderServiceProxy.addOrder("mayikt", "111");
}
}
2.动态代理的实现方式
jdk动态代理和cglib动态代理
2.1 JDK动态代理方式
接口
public interface OrderService {
String addOrder(String orderId, String orderName);
}
实现类
public class OrderServiceImpl implements OrderService {
@Override
public String addOrder(String orderId, String orderName) {
System.out.println("OrderServiceImpl真实方法执行...");
return orderId + "," + orderName;
}
}
事件处理器(用于动态生成代理类)
public class JdkInvocationHandler implements InvocationHandler {
//目标对象(被代理类)
private Object target;
public JdkInvocationHandler(Object object) {
this.target = object;
}
/**
* @param proxy jdk动态生成的代理类
* @param method 不是真正的目标方法,接口中的方法,底层通过反射执行真正目标方法
* @param args 代理类参数
* 使用生成的代理类去拦截回调
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("jdk动态代理执行开始>>>" + args[0]);
// 执行目标方法 java反射执行目标方法
Object result = method.invoke(target, args);
System.out.println("jdk动态代理执行结束>>>" + args[0]);
return result;
}
/**
* 使用jdk创建代理类对象
*
* @param <T>
* @return
*/
public <T> T getProxy() {
// ClassLoader 读取代理类class文件
// Class<?>[] interfaces 基于该接口拼接代理类的源代码
// InvocationHandler this
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
}
测试
public class Test {
public static void main(String[] args) {
JdkInvocationHandler jdkInvocationHandler = new JdkInvocationHandler(new OrderServiceImpl());
// 创建代理类
OrderService proxy = jdkInvocationHandler.getProxy();
proxy.addOrder("mayikt", "maplefire");
}
}
2.2 Cglib动态代理方式
接口
public interface OrderService {
String addOrder(String orderId, String orderName);
}
实现类
public class OrderServiceImpl implements OrderService {
@Override
public String addOrder(String orderId, String orderName) {
System.out.println("OrderServiceImpl真实方法执行...");
return orderId + "," + orderName;
}
}
方法拦截器(用于动态生成代理类)
public class CglibMethodInterceptor implements MethodInterceptor {
/**
* @param obj cglib生成好的代理类对象
* @param method 目标方法
* @param args 参数
* @param proxy 代理
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("cglib动态代理执行开始>>>");
Object result = proxy.invokeSuper(obj, args);
System.out.println("cglib动态代理执行结束>>>");
return result;
}
}
测试
public class Test {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
//设置即将生成的代理类的父类
enhancer.setSuperclass(OrderServiceImpl.class);
//设置回调方法
enhancer.setCallback(new CglibMethodInterceptor());
// 创建代理对象
OrderServiceImpl orderServiceImpl= (OrderServiceImpl) enhancer.create();
orderServiceImpl.addOrder("mayikt", "maplefire");
}
}
3.Jdk与Cglib动态代理的区别
Jdk动态代理:基于实现接口的形式生成代理类对象;使用java反射机制调用目标方法
- 需要拼接java源代码$proxy.java
- 需要将java源代码编译为class文件
- 采用类加载器读取class文件到程序中
- 采用java的反射机制执行目标方法
反射机制:method.invoke(target, args);
Cglib动态代理:基于继承目标对象生成代理类对象;(ASM)字节码技术
- 直接采用字节码技术生成class文件(无需编译过程)
- 采用类加载器读取class文件到程序中
- 采用FastClass机制调用到目标方法(比反射机制效率要高)
FastClass机制:memberService.add()
FastClass对目标对象中所有的方法生成一个索引的标记,直接根据索引调用到目标方法。