文章目录
代理模式简介
- 代理模式(proxy pattern)就是为一个对象提供一个替身,以控制对这个对象的访问,更可以达到对该对象功能的增强。
- 在AOP编程中如何选择代理模式:目标对象实现了接口采用JDK代理,目标对象未实现接口采用cglib代理。
结构
- 1.抽象主题类(Subject):通过接口或者抽象类申明真实主题和代理对象实现的业务方法。
- 2.真实主题类(Real Subject):实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
- 3.代理类(Proxy):提供了和真实主题相同的接口,在内部含有对真实主题的引用,它可以访问、控制或者扩展真实主题的功能。
代理模式分类
- 代理常见的有3种类:静态代理、JDK动态代理、cglib代理
- 静态代理和JDK代理模式都要求目标对象实现了一个接口,而cglib不要求目标对象实现接口。
静态代理(static proxy)
什么是静态代理?
- 静态代理在使用时,需要定义接口或者父类,被代理对象(目标对象)与代理对象要实现相同的接口或者继承相同的父类。
静态代理优缺点
- 优点:在不修改目标对象的功能前提下,能通过代理对象对目标功能扩展。
- 缺点:因为代理对象和目标对象要实现一样的接口或者继承相同的父类,所以会有很多代理类,且一旦接口增加方法,目标对象和代理对象都要维护。
具体实现
例子:给WorkDao添加静态代理。
UML图
代码实现
- 抽象主题类
package com.xxliao.pattern.structure.proxy.static_proxy.demo;
/**
* @author xxliao
* @description: 工作接口-抽象主题类
* @date 2024/5/24 18:33
*/
public interface IWorkDao {
void work();
}
- 真实主题类
package com.xxliao.pattern.structure.proxy.static_proxy.demo;
/**
* @author xxliao
* @description: 工作类实现类-真实主题类
* @date 2024/5/24 18:34
*/
public class WorkDao implements IWorkDao{
@Override
public void work() {
System.out.println("Worker working....");
}
}
- 静态代理工厂类
package com.xxliao.pattern.structure.proxy.static_proxy.demo;
/**
* @author xxliao
* @description: 代理类
* @date 2024/5/24 18:35
*/
public class WorkDaoProxy implements IWorkDao {
// 目标对象,通过接口来聚合
private IWorkDao target;
// 通过构造器 填充目标对象
public WorkDaoProxy(IWorkDao target) {
this.target = target;
}
// 方法中对目标对象的目标方法进行 增强等功能。
@Override
public void work() {
System.out.println("before work method ... ");
target.work();
System.out.println("after work method ...");
}
}
- 测试客户端
package com.xxliao.pattern.structure.proxy.static_proxy.demo;
/**
* @author xxliao
* @description: static proxy demo test class
* @date 2024/5/24 18:38
*/
public class Client {
public static void main(String[] args) {
// 创建目标对象
WorkDao workDao = new WorkDao();
// 获取代理对象
WorkDaoProxy workDaoProxy = new WorkDaoProxy(workDao);
// 执行方法
workDaoProxy.work();
System.out.println(workDao.hashCode());
System.out.println(workDaoProxy.hashCode());
//System.out.println(workDao == workDaoProxy);
}
}
- 测试结果
JDK动态代理(jdk dynamic proxy)
什么是JDK代理?
- JDK代理是Java语言自带的代理,使用时候,要求被代理的对象需要有父类接口。
- 实现原理就是:在内存中创建一个新的class对象。
具体实现
例子:给WorkDao添加代理。
UML图
代码实现
- 抽象主题类
package com.xxliao.pattern.structure.proxy.jdk_dynamic_proxy.demo;
/**
* @author xxliao
* @description: 工作接口-抽象主题类
* @date 2024/5/24 18:33
*/
public interface IWorkDao {
void work();
}
- 真实主题类
package com.xxliao.pattern.structure.proxy.jdk_dynamic_proxy.demo;
/**
* @author xxliao
* @description: 工作类实现类-真实主题类
* @date 2024/5/24 18:34
*/
public class WorkDao implements IWorkDao {
@Override
public void work() {
System.out.println("Worker working....");
}
}
- 代理工厂类
package com.xxliao.pattern.structure.proxy.jdk_dynamic_proxy.demo;
import com.xxliao.pattern.structure.proxy.static_proxy.demo.IWorkDao;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author xxliao
* @description: 代理工厂类
* @date 2024/5/24 18:35
*/
public class ProxyFactory {
// 目标对象,通过接口来聚合
private IWorkDao target;
public ProxyFactory(IWorkDao target) {
this.target = target;
}
public IWorkDao getProxy() {
/**
* 使用Proxy获取代理对象,newProxyInstance方法参数说明:
* ClassLoader loader : 类加载器,用于加载代理类,使用真实对象的类加载器即可;
* Class<?>[] interfaces : 真实对象所实现的接口,代理模式真实对象和代理对象要实现相同的接口。
* InvocationHandler: 代理对象的调用处理程序。
*/
IWorkDao result = (IWorkDao) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
/**
* proxy: 代理对象;
* method: 对应在对象上调用的接口方法的method实例
* args:代理对象调用接口方法时传递的实际参数。
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理对象method执行之前...");
Object result = method.invoke(target, args);
System.out.println("代理对象method执行之后...");
return result;
}
}
);
return result;
}
}
- 测试客户端
package com.xxliao.pattern.structure.proxy.jdk_dynamic_proxy.demo;
import com.xxliao.pattern.structure.proxy.static_proxy.demo.IWorkDao;
import com.xxliao.pattern.structure.proxy.static_proxy.demo.WorkDao;
/**
* @author xxliao
* @description: static proxy demo test class
* @date 2024/5/24 18:38
*/
public class Client {
public static void main(String[] args) {
IWorkDao workDao = new WorkDao();
ProxyFactory proxyFactory = new ProxyFactory(workDao);
IWorkDao proxy = proxyFactory.getProxy();
proxy.work();
System.out.println(workDao.hashCode());
System.out.println(proxy.hashCode());
System.out.println(proxy == workDao);
}
}
- 测试结果
cglib动态代理(cglib dynamic proxy)
什么是cglib代理?
- cglib代理也叫子类代理,它是在内存中构建一个子类对象,从而实现对目标对象功能扩展,cglib包的底层是通过使用字节码框架ASM来转换字节码并生成新的类。
具体实现
例子:给TearchDao使用代理。TearchDao是个普通类。
UML图
- 目标测试类
package com.xxliao.pattern.structure.proxy.cglib_dynamic_proxy.demo;
/**
* @author xxliao
* @description: cglig 测试 目标对象类
* @date 2024/5/24 23:21
*/
public class TeacherDao {
public void teach() {
System.out.println("teacher is teaching...");
}
@Override
public int hashCode() {
return super.hashCode();
}
}
- 代理工厂类
package com.xxliao.pattern.structure.proxy.cglib_dynamic_proxy.demo;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @author xxliao
* @description: cglib代理工厂类
*
* MethodInterceptor接口 继承了 Callback 类,定义了intercept方法,该方法就是回调函数方法。
*
* @date 2024/5/24 23:09
*/
public class CglibProxyFactory implements MethodInterceptor {
// 维护一个目标对象
private Object target;
// 构造器,传入一个被代理对象
public CglibProxyFactory(Object target) {
this.target = target;
}
// 返回一个代理对象,是target对象的代理对象
public Object getProxyInstance() {
// 1.创建一个工具类
Enhancer enhancer = new Enhancer();
// 2.设置父类,也是是目标对象class
enhancer.setSuperclass(target.getClass());
// 3.设置回调函数
enhancer.setCallback(this);
// 4.创建子类对象,也就是代理对象
return enhancer.create();
}
/**
* @description 重写了intercept方法,会调用目标对象的方法。
*
* 参数含义:
* o: 代理对象;
* method: 真实对象中的方法的Method实例;
* objects: 实际参数;
* methodProxy : 代理对象中的方法Method实例
*
* @author xxliao
* @date 2024/5/24 23:17
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib 代理方法执行前...");
System.out.println("对象执行的方法是"+method.getName());
Object returnVal = method.invoke(target, objects);
System.out.println("cglib 代理方法执行后...");
return returnVal;
}
}
- 测试客户端
package com.xxliao.pattern.structure.proxy.cglib_dynamic_proxy.demo;
/**
* @author xxliao
* @description: cglib 测试客户端类
* @date 2024/5/24 23:22
*/
public class Client {
public static void main(String[] args) {
TeacherDao teacherDao = new TeacherDao();
CglibProxyFactory cglibProxyFactory = new CglibProxyFactory(teacherDao);
TeacherDao proxyInstance = (TeacherDao) cglibProxyFactory.getProxyInstance();
proxyInstance.teach();
System.out.println("teacherDao.hashCode="+teacherDao.hashCode());
System.out.println("===============================================");
System.out.println("proxyInstance.hashCode="+proxyInstance.hashCode());
System.out.println(teacherDao == proxyInstance);
}
}
- 测试结果