Java基础 代理模式:静态、动态、cglib;及 spring 中 动态、cglib 两种方式的示例
一、代理模式介绍
代理模式,也称委托模式,是结构型设计模式之一;
代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改代理目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。
1.1、静态代理与动态代理的区别主要在:
- 静态代理在编译时就已经实现,编译完成后代理类是一个实际的class文件
- 动态代理是在运行时动态生成的,即编译完成后没有实际的class文件,而是在运行时动态生成类字节码,并加载到JVM中
特点:动态代理中,代理对象不需要实现接口,但是要求被代理目标对象必须实现接口,否则不能使用动态代理。
二、Java 代理模式
java 中常用的代理模式有3种:静态代理、动态代理、cglib 动态代理
2.1、静态代理模式
使用静态代理的基本步骤:
- 定义公共接口;
- 被代理目标对象实现公共接口中的方法;
- 代理对象实现公共接口中的方法,通过方法调用被代理目标对象的实现方法。
缺点:
- 冗余。由于代理对象要实现与被代理目标对象一致的接口,会产生过多的代理类。
- 不易维护。一旦接口增加方法,被代理目标对象与代理对象都要进行修改。很难维护这么多代理类和被代理类之间的关系。
示例:
无,太简单,不想写;
2.2、动态代理模式
使用动态代理的基本步骤:
- 定义公共接口;
- 被代理目标对象实现公共接口中的方法;
- 定义一个实现 InvocationHandler 的代理工厂类。
- 通过代理工厂类的对象,创建代理对象;
- 代理对象调用被代理目标对象方法;
示例:
- 定义公共接口
package com.zk.demo.proxy;
/**
* @ClassName: ZKDoSomethingInterface
* @Description: TODO(simple description this class what to do. )
* @author Vinson
* @version 1.0
*/
public interface ZKDoSomethingInterface {
/**
* 做点啥
*
* @Title: doSomething
* @Description: TODO(simple description this method what to do.)
* @author Vinson
* @date Aug 3, 2024 8:36:04 AM
* @param param
* @return
* @return int
*/
int doSomething(int param);
}
- 被代理目标对象实现公共接口中的方法;
package com.zk.demo.proxy;
/**
* @ClassName: ZKDoSomethingImpl
* @Description: TODO(simple description this class what to do. )
* @author Vinson
* @version 1.0
*/
public class ZKDoSomethingImpl implements ZKDoSomethingInterface { // 有实现接口
private int mP;
public ZKDoSomethingImpl(int mP) {
this.mP = mP;
}
@Override
public int doSomething(int param) {
System.out
.println("[^_^:20240803-0838-001] ZKDoSomethingImpl.DoSomething 给参数 param:" + param + " 增加:" + this.mP);
param = this.mP + param;
return param;
}
}
- 定义一个实现 InvocationHandler 处理类及工厂类。
package com.zk.demo.proxy.dynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @ClassName: ZKInvocationHandler
* @Description: TODO(simple description this class what to do. )
* @author Vinson
* @version 1.0
*/
public class ZKInvocationHandler implements InvocationHandler {
/**
* 被代理的真实对象;
*
* 必须实现一个或多个接口
*/
private Object target;
public ZKInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("[^_^:20240803-0855-001] ZKInvocationHandler proxy:" + proxy.getClass());
System.out.println("[^_^:20240803-0855-001] ZKInvocationHandler method:" + method.getName());
Object rev = method.invoke(this.target, args);
System.out.println("[^_^:20240803-0855-001] ZKInvocationHandler 执行被代理目标对象的方法结束:" + rev);
return rev;
}
}
package com.zk.demo.proxy.dynamicProxy;
import java.lang.reflect.Proxy;
/**
* @ClassName: ZKDynamicProxyFactory
* @Description: TODO(simple description this class what to do. )
* @author Vinson
* @version 1.0
*/
public class ZKDynamicProxyFactory {
@SuppressWarnings("unchecked")
public <T> T getProxyInstance(Object target) {
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
new ZKInvocationHandler(target));
}
}
- 测试
package com.zk.demo.proxy.dynamicProxy;
import org.junit.Test;
import com.zk.demo.proxy.ZKDoSomethingImpl;
import com.zk.demo.proxy.ZKDoSomethingInterface;
import junit.framework.TestCase;
/**
* @ClassName: ZKDynamicProxyFactoryTest
* @Description: TODO(simple description this class what to do. )
* @author Vinson
* @version 1.0
*/
public class ZKDynamicProxyFactoryTest {
@Test
public void test() {
try {
ZKDoSomethingImpl dsImpl = new ZKDoSomethingImpl(3);
ZKDoSomethingInterface dsProxy = null;
int result = 0;
ZKDynamicProxyFactory dpf = new ZKDynamicProxyFactory();
dsProxy = dpf.getPr