苏州市网站建设培训网站seo应用
代理模式
代理模式使用代理对象来代替真实对象的访问,在不修改原有对象的前提下,提供额外的操作,扩展目标对象的功能。代理模式分为静态代理和动态代理。
静态代理
手动为目标对象中的方法进行增强,通过实现相同接口重写方法进行增强。非常不灵活,当对象中新增方法时,代理类同样需要增加代理方法。静态代理是在代码编译时生成的代理类
实现步骤
- 定义接口和实现类
- 定义代理类实现接口
- 将被代理类注入,重写方法,在方法中增强
代码展示
-
接口
public interface Image {void display(String name); }
-
实现类
public class RealImage implements Image {@Overridepublic void display(String name) {System.out.println(name + " display");} }
-
代理类
public class StaticProxy implements Image {private RealImage realImage;@Overridepublic void display(String name) {realImage = new RealImage();System.out.println("start");realImage.display(name);System.out.println("end");}public static void main(String[] args) {Image image = new StaticProxy();image.display("图片");} }
静态代理简单并且局限性太高,一般没有人使用
动态代理
相较于静态代理,动态代理更加灵活,可以被多个类创建统一代理类。针对实现类和接口分别有JDK动态代理
和CGLIB动态代理
。动态代理是在运行时动态生成代理类并加载到JVM中去的。
JDK动态代理
JDK动态代理是为已经实现接口的类创建代理类。核心是**InvocationHandler
接口和Proxy
类。Proxy
类用于生成代理对象,InvocationHandler
接口用于自定义处理逻辑。当我们用Proxy类中的newProxyInstance()
方法生成的动态代理对象调用方法时,这个方法的调用会转发到InvocationHandler
接口中的invoke
**方法中来调用。
Proxy
类中使用频率最高的方法是:newProxyInstance()
,这个方法主要用来生成一个代理对象。
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException{......}
这个方法一共有 3 个参数:
- loader :类加载器,用于加载代理对象。
- interfaces : 被代理类实现的一些接口;
- h : 实现了
InvocationHandler
接口的对象;
要实现动态代理的话,还必须需要实现InvocationHandler
来自定义处理逻辑。 当我们的动态代理对象调用一个方法时,这个方法的调用就会被转发到实现InvocationHandler
接口类的 invoke
方法来调用。
public interface InvocationHandler {/*** 当你使用代理对象调用方法的时候实际会调用到这个方法*/public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
}
invoke()
方法有下面三个参数:
- proxy :动态生成的代理类
- method : 与代理类对象调用的方法相对应
- args : 当前 method 方法的参数
实现步骤
- 定义接口和实现类
- 自定义**
InvocationHandler
并重写invoke
**方法,在方法中调用被代理的方法并实现自定义处理逻辑 - 通过
Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
方法创建代理对象 - 使用代理对象进行方法调用
代码展示
-
接口和实现类同上
-
InvocationHandler
/*** @author linmeng* @date 2023/2/22 00:42*/ public class JdkInvocationHandler implements InvocationHandler {/*** 被代理类**/private Object target;public JdkInvocationHandler(Object target) {this.target = target;}/*** @Author linmeng* @Description * @date 2023/2/24 15:57* @param proxy 动态生成的代理类* @param method 代理方法* @param args 方法参数* @return java.lang.Object**/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("调用方法前打印方法名称;" + method.getName());Object res = method.invoke(target, args);System.out.println("调用方法后打印方法名称;" + method.getName());return res;} }
-
代理对象生成
import java.lang.reflect.Proxy;/*** @author linmeng* @date 2023/2/22 00:44*/ public class JDKProxy {public static Object getProxy(Object target) {return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new JdkInvocationHandler(target));}}
-
测试
import org.junit.Test;/*** @author linmeng* @date 2023/2/22 00:50*/public class JdkTest {@Testpublic void jdkTest(){Image proxy = (Image) JDKProxy.getProxy(new RealImage());proxy.display("图片");}
CGLIB动态代理
当类没有实现接口时,是不能用JDK动态代理的。这个时候可以用CGLIB动态代理,他是通过继承的方式实现代理。
**在 CGLIB 动态代理机制中 MethodInterceptor
接口和 Enhancer
类是核心。**通过实现MethodInterceptor
接口中的intercept
方法自定义处理逻辑,Enhancer
类创建代理类。
你需要自定义 MethodInterceptor
并重写 intercept
方法,intercept
用于拦截增强被代理类的方法。
public interface MethodInterceptor
extends Callback{// 拦截被代理类中的方法public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,MethodProxy proxy) throws Throwable;
}
- obj : 被代理的对象(需要增强的对象)
- method : 被拦截的方法(需要增强的方法)
- args : 方法入参
- proxy : 用于调用原始方法
你可以通过 Enhancer
类来动态获取被代理类,当代理类调用方法的时候,实际调用的是 MethodInterceptor
中的 intercept
方法。
实现步骤
- 实现类
- 自定义
MethodInterceptor
并重写intercept
方法,自定义增强逻辑 - 通过
Enhancer
中的create()
方法创建代理对象 - 使用代理对象调用方法
代码展示
-
实现类
public class RealImage2 {public void display(String name) {System.out.println(name + " display");} }
-
自定义
MethodInterceptor
并重写intercept
方法/*** @author linmeng* @date 2023/2/24 14:10*/ public class CGLIBInterceptor implements MethodInterceptor {/*** @param o 被代理对象* @param method 被拦截的方法* @param objects 方法入参* @param methodProxy 用于调用元素方法* @return java.lang.Object* @Author linmeng* @Description* @date 2023/2/24 14:11**/@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("调用方法前打印方法名称;" + method.getName());Object res = methodProxy.invokeSuper(o, objects);System.out.println("调用方法后打印方法名称;" + method.getName());return res;} }
-
通过
Enhancer
中的create()
方法创建代理对象import net.sf.cglib.proxy.Enhancer;/*** @author linmeng* @date 2023/2/24 14:15*/ public class CGLIBProxy {public static Object getProxy(Class<?> clazz) {// 动态代理增强类Enhancer enhancer = new Enhancer();// 类加载器enhancer.setClassLoader(clazz.getClassLoader());// 被代理类enhancer.setSuperclass(clazz);// 增强类enhancer.setCallback(new CGLIBInterceptor());// 代理类创建return enhancer.create();} }
-
使用
import org.junit.Test;/*** @author linmeng* @date 2023/2/22 00:50*/ public class CGLIBTest {@Testpublic void cglibTest(){RealImage2 proxy = (RealImage2) CGLIBProxy.getProxy(RealImage2.class);proxy.display("图片");} }
参考链接
- Java设计模式:Proxy(代理)模式
- Java 代理模式详解
- Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass