代理模式
代理模式(Proxy Pattern)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象,这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。
代理模式又分为两大类:静态代理和动态代理。其中动态代理又分为JDK代理和CGLIB代理。
1. 静态代理
1.1实现方式
1.2 优点
1.3 缺点
代理类需要硬编码接口,在实际应用中可能会导致重复编码,浪费存储空间并且效率较低。
1.4 实现代码
package com.wnhz.smart.order.proxy.sta;
/**
* @author Hao
* @date 2023-11-28 20:10
*/
public class StaticProxyDemo {
public static void main(String[] args) {
// 被代理对象
RealObject realObject = new RealObject();
// 创建代理对象
StaticProxy proxy = new StaticProxy(realObject);
// 实现静态代理,调用代理对象的方法
proxy.doSomething();
}
}
interface MyInterface {
void doSomething();
}
class RealObject implements MyInterface {
@Override
public void doSomething() {
System.out.println("RealObject doSomething");
}
}
class StaticProxy implements MyInterface {
private RealObject realObject;
public StaticProxy(RealObject realObject) {
this.realObject = realObject;
}
@Override
public void doSomething() {
System.out.println("Before method invocation");
realObject.doSomething();
System.out.println("After method invocation");
}
}
2. JDK动态代理
2.1实现方式
代理类与委托类实现同一接口。代理类要实现 InvocationHandler 接口并重写 invoke 方法。invoke 方法中可以对委托方法进行增强处理。
2.2 优点
2.3 缺点
只能够代理实现了接口的委托类。
2.4 特点
2.5 实现代码
在下面的代码中,RealObject实现了MyInterface接口,它是我们要代理的实际对象。DynamicProxy类实现了InvocationHandler接口,并在invoke()方法中添加了额外的逻辑,用于在代理对象方法调用前后执行。
在main()方法中,我们使用Proxy.newProxyInstance()方法创建代理对象。我们指定了MyInterface接口作为代理对象类型,并将DynamicProxy对象作为代理对象的InvocationHandler。
最后,我们调用代理对象的doSomething()方法,并观察控制台输出的结果。
需要注意的是,代理对象的方法调用都会被转发到DynamicProxy类的invoke()方法中进行处理,因此在这个示例中,实际的RealObject对象的doSomething()方法的执行是在invoke()方法中通过反射进行的。
package com.proxy.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author Hao
* @date 2023-11-28 19:34
*/
public class JDKProxyDemo {
public static void main(String[] args) {
RealObject real = new RealObject();
InvocationHandler handler = new DynamicProxy(real);
// 创建代理对象
MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
MyInterface.class.getClassLoader(),
new Class<?>[]{MyInterface.class},
handler);
// 调用代理对象的方法
proxy.doSomething();
}
}
interface MyInterface {
void doSomething();
}
class RealObject implements MyInterface {
@Override
public void doSomething() {
System.out.println("RealObject doSomething");
}
}
class DynamicProxy implements InvocationHandler {
private Object target;
public DynamicProxy(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("Before method invocation");
Object result = method.invoke(target, args);
System.out.println("After method invocation");
return result;
}
}
结果:
Before method invocation
RealObject doSomething
After method invocation
2.6 总结
JDK动态代理只能代理接口实现类,原因是JDK动态代理是基于接口实现的,代理对象的类型由接口列表决定。如果你想代理一个类而不是一个接口,你需要使用其他的代理技术,比如CGLIB动态代理。
CGLIB 动态代理
3.1实现方式
代理类将委托类作为自己的父类并为其中的非 final 委托方法创建两个方法,一个是与委托方法签名相同的方法,它在方法中会通过 super 调用委托方法;另一个是代理类独有的方法。在代理方法中,它会判断是否存在实现了MethodInterceptor 接口的对象,若存在则将调用 intercept 方法对委托方法进行代理。
3.2 优点
可以在运行时对类或者是接口进行增强操作,且委托类无需实现接口。
3.3 缺点
3.4 特点
底层将方法全部存入一个数组中,通过数组索引直接进行方法调用。
3.5 代码实现
在下面的示例中,我们使用CGLIB的Enhancer类和MethodInterceptor接口来创建代理对象。RealObject类不再需要实现接口,而是直接作为代理对象的类型。在CGLIBProxy类中,我们实现了MethodInterceptor接口,并在intercept()方法中添加了额外的逻辑。
在main()方法中,我们使用Enhancer.create()方法创建代理对象。我们指定了RealObject类作为代理对象类型,并将CGLIBProxy对象作为代理对象的MethodInterceptor。最后,我们调用代理对象的doSomething()方法,并观察控制台输出的结果。
package com.proxy.cglib;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @author Hao
* @date 2023-11-28 19:58
*/
public class CGLIBProxyDemo {
public static void main(String[] args) {
RealObject real = new RealObject();
MethodInterceptor handler = new CGLIBProxy(real);
// 创建代理对象
RealObject proxy = (RealObject) Enhancer.create(
RealObject.class,
handler);
// 调用代理对象的方法
proxy.doSomething();
}
}
class RealObject {
public void doSomething() {
System.out.println("RealObject doSomething");
}
}
class CGLIBProxy implements MethodInterceptor {
private Object target;
public CGLIBProxy(Object target) {
this.target = target;
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before method invocation");
Object result = proxy.invoke(target, args);
System.out.println("After method invocation");
return result;
}
}
结果:
Before method invocation
RealObject doSomething
After method invocation
两者之间的优缺点
JDK动态代理的优点:
JDK动态代理的缺点:
CGLIB代理的优点:
CGLIB代理的缺点:
综上所述,JDK动态代理适用于代理接口实现类的场景,而CGLIB代理适用于代理没有实现接口的类的场景。如果你需要代理接口实现类,而且不想引入额外的依赖,那么JDK动态代理是一个不错的选择;如果你需要代理没有实现接口的类,那么CGLIB代理可能更适合你的需求。
原文地址:https://blog.csdn.net/treadsangerbraes/article/details/134676004
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_32012.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!