文章内容
一、什么是代理模式
代理模式,为目标对象提供一个替身,以控制对这个对象的访问,进行附加功能增强,从而达到扩展目标对象的功能。比如:添加日志、事务控制、程序耗时等等。
二、代理模式角色
- 抽象角色:定义代理角色和真实角色的公共对外方法。
- 真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理对象调用。
- 代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以增加前置和后置操作。
三、代理模式UML图
四、代理模式实现方式
- 静态代理:被代理对象(即目标对象)和代理对象需要实现共同的接口或继承共同的抽象类,同时代理对象需要关联目标对象。
- JDK动态代理:目标对象需要实现接口,代理对象不需要实现接口。利用JDK自带的Proxy类在运行时动态生成代理对象。
- Cglib动态代理:CGLIB代理也叫子类代理,在JVM运行时,在内存中动态的基于目标类创建一个子类对象,从而实现对目标对象的增强。CGLIB是通过使用字节码处理框架ASM来转换字节码并生成新的类。
五、静态代理优缺点
1、优点
- 避免了直接修改目标对象的功能,以代理模式对目标对象进行了功能扩展。
2、缺点
- 代理类需要与目标对象一一对应,可能会产生“类爆炸”,维护工作量巨大。
- 如果目标对象新增功能,代理类也要同步进行新增升级,可谓牵一发而动全身。
六、JDK动态代理Proxy类详解
JDK自带的代理类包路径java.lang.reflect.Proxy,调用静态方法newProxyInstance方法动态生成代理对象,该方法包括3个形参:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
- ClassLoader loader: 指定目标对象所使用的类加载器,用于加载代理类。
- Class<?>[] interfaces: 目标对象实现的接口类,通过泛型确定类型,也是代理类实现的接口类。
- InvocationHandler h: 代理对象的调用处理程序,执行目标对象的方法,会把当前执行的目标对象 的方法作为参数传入。调用invoke方法进行增强业务处理。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
- Object proxy:代理对象,在该方法中基本不用。
- Method method:目标对象的方法,对接口中的方法进行封装的method对象。
- Object[] args:调用目标对象方法的实际参数。
七、CGLIB动态代理
1、为啥要使用CGLIB
如果需要被代理的目标对象没有实现接口,这时就不能使用静态代理或JDK动态代理来实现了。这时,CGLIB就要登场了,它提供了一个功能强大、高性能的代码生成包,它可以为没有实现接口的普通类提供代理,弥补了JDK动态代理的不足。
2、使用CGLIB代理注意事项
- 被代理的目标对象不能为final
- 被代理的目标对象的方法不能被final、static修饰
3、引入CGLIB jar 包
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2</version>
</dependency>
4、CGLIB 2个核心类
- net.sf.cglib.proxy.Enhancer:用于动态生成代理对象,作用类似JDK代理中的Proxy类。
- net.sf.cglib.proxy.MethodInterceptor:目标对象的拦截器,用于实现对目标对象的功能增强。
八、代理模式demo示例
1、Demo需求
以用户管理为例,对用户功能进行增强,添加方法入口日志和结束日志。
2、静态代理模式代码实现
/**
* 用户管理接口
*/ public interface IUserService {
void insert();
void print();
}
/**
* 用户管理实现类
*/ public class UserServiceImpl implements IUserService {
@Override
public void insert() {
System.out.println("新增一个用户");
}
@Override
public void print() {
System.out.println("打印用户信息");
}
}
/**
* 用户管理静态代理类
*
*/ public class UserServiceProxy implements IUserService {
private IUserService userService;
public UserServiceProxy(IUserService userService) {
this.userService = userService;
}
/**
* 对原有insert功能进行增强,增加日志信息
*/ @Override
public void insert() {
System.out.println("新增用户开始");
userService.insert();
System.out.println("新增用户成功。");
}
/**
* 对原有print功能进行增强,增加日志信息
*/ @Override
public void print() {
System.out.println("输出用户信息开始");
userService.print();
System.out.println("输出用户信息完成。");
}
}
public class ClientTest {
public static void main(String[] args) {
//创建目标对象
IUserService userService = new UserServiceImpl();
//创建代理对象
IUserService userServiceProxy = new UserServiceProxy(userService);
//调用方法
userServiceProxy.print();
System.out.println("====================================");
userServiceProxy.insert();
}
}
控制台输入日志:
输出用户信息开始
打印用户信息
输出用户信息完成。
====================================
新增用户开始
新增一个用户
新增用户成功。
3、JDK动态代理模式代码实现
/**
* 用户管理接口
*/ public interface IUserService {
void insert();
void print();
}
/**
* 用户管理实现类
*/ public class UserServiceImpl implements IUserService {
@Override
public void insert() {
System.out.println("新增一个用户");
}
@Override
public void print() {
System.out.println("打印用户信息");
}
}
/**
* 代理对象的工厂类
*/ public class UserServiceProxyFactory {
private IUserService userService;
public UserServiceProxyFactory(IUserService userService) {
this.userService = userService;
}
public IUserService getProxyObject(){
return (IUserService) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
userService.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("进入方法,记录日志");
Object result = method.invoke(userService, args);
System.out.println("结束方法,记录日志");
return result;
}
});
}
}
public class Client {
public static void main(String[] args) {
//创建目标对象
IUserService userService = new UserServiceImpl();
// 创建代理对象
IUserService proxyObject = new UserServiceProxyFactory(userService).getProxyObject();
System.out.println(proxyObject.getClass());
System.out.println("========================");
//调用方法
proxyObject.insert();
System.out.println("========================");
proxyObject.print();
}
}
控制台输入日志:
class com.sun.proxy.$Proxy0
========================
进入方法,记录日志
新增一个用户
结束方法,记录日志
========================
进入方法,记录日志
打印用户信息
结束方法,记录日志
可以看到动态代理对象的class 带有 $Proxy 标识:class com.sun.proxy.$Proxy0
4、CGLIB动态代理模式代码实现
/**
* 用户管理类,被代理的目标类
*/ public class UserService {
public void add(String name) {
System.out.println("新增了一个用户: " + name);
}
public void print() {
System.out.println("打印用户信息...");
}
}
/**
* 用户代理对象工厂类,用来获取代理对象
*/ public class UserProxyFactory<T> {
//目标对象,使用泛型
private T target;
/**
* 初始化工厂类使,指定被代理的目标对象
* @param target
*/ public UserProxyFactory(T target) {
this.target = target;
}
/**
* 获取代理对象
*
* @return
*/ public T getProxyObj(){
// 创建enhancer对象,等价于JDK代理中的Proxy类
Enhancer enhancer = new Enhancer();
//设置父类的字节码对象
enhancer.setSuperclass(UserService.class);
//设置回调函数
enhancer.setCallback(new MethodInterceptor() {
/**
* 用于实现对目标对象的功能增强,类似于JDK代理中的InvocationHandler中的invoke方法
*
* @param o
* @param method
* @param objects
* @param methodProxy
* @return
* @throws Throwable
*/ @Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("调用方法前,写入日志");
Object result = method.invoke(target, objects);
System.out.println("调用方法结束,写入日志");
return result;
}
});
// 生成代理对象
return (T) enhancer.create();
}
}
/**
* CGLIB 客户端测试类
*
*/ public class CGLIBClient {
public static void main(String[] args) {
UserService userService = new UserProxyFactory<UserService>(new UserService()).getProxyObj();
System.out.println("代理对象class= " + userService.getClass());
System.out.println("=======================");
userService.add("lisi");
}
}
控制台输入日志:
代理对象class= class com.ford.proxy.dynamic.cglib.UserService$$EnhancerByCGLIB$$91d7e1dc
=======================
调用方法前,写入日志
新增了一个用户: lisi
调用方法结束,写入日志
可以看到,CGLIB代理对象带有:$$EnhancerByCGLIB$$,而JDK动态代理的代理对象代用:$Proxy,这一点可以判断代理对象到底使用了哪种代理实现方式。