java代理模式
代理模式
指的是使用一个代理对象将原对象包装起来,之后用这个代理来取代该对象,任何对原始对象的调用都需要通过代理。
1. 静态代理
程序运行之前就已经定好代理类和委托类的关系。
BasicSubject.java
/**
* 代理接口
*/
public interface BasicSubject {
public void doSomething();
}
BasicImpl.java
/**
* 委托类,真正执行任务的类,实现了代理接口
*/
public class BasicImpl implements BasicSubject{
@Override
public void doSomething() {
System.out.println("do something!");
}
}
BasicProxy.java
/**
* 代理类,实现了代理接口,同时里面有委托类的对象引用
*/
public class BasicProxy implements BasicSubject{
private BasicImpl basic = new BasicImpl();
@Override
public void doSomething() {
this.before();
basic.doSomething();
this.after();
}
public void before(){
System.out.println("before");
}
public void after(){
System.out.println("after");
}
}
testStaticProxy.java
public class testStaticProxy {
public static void main(String[] args) {
BasicSubject basicSubject = new BasicProxy();
basicSubject.doSomething();
}
}
可以看出,静态代理类由于一个类只能代理一种类型的对象,因此代码量比较多。同时当接口添加了一个方法时,除了实现类,所有的代理类也要添加改方法的实现,增加了代码维护工作量。
2. 动态代理
动态代理改进了静态代理的一些缺点,主要是编译后动态生成字节码并加载到JVM中进行实现。也被叫做JDK代理
BasicImpl01.java
public class BasicImpl01 implements BasicSubject{
@Override
public void doSomething() {
System.out.println("01 do something!");
}
}
BasicImpl02.java
public class BasicImpl02 implements BasicSubject{
@Override
public void doSomething() {
System.out.println("02 do something!");
}
}
DynamicSubjectProxy.java
public class DynamicSubjectProxy implements InvocationHandler {
private Object ProxyObject;
public Object newProxyInstance(Object ProxyObject){
this.ProxyObject = ProxyObject;
return Proxy.newProxyInstance(
ProxyObject.getClass().getClassLoader(),
ProxyObject.getClass().getInterfaces(),
this
);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before do something");
Object result = method.invoke(ProxyObject, args);
System.out.println("after do something");
return result;
}
}
TestDynamicProxy.java
public class TestDynamicProxy {
public static void main(String[] args) {
DynamicSubjectProxy dynamicProxy = new DynamicSubjectProxy();
BasicImpl01 basicImpl01 = new BasicImpl01();
BasicImpl02 basicImpl02 = new BasicImpl02();
BasicSubject basicSubject01 = (BasicSubject) dynamicProxy.newProxyInstance(basicImpl01);
basicSubject01.doSomething();
BasicSubject basicSubject02 = (BasicSubject) dynamicProxy.newProxyInstance(basicImpl02);
basicSubject02.doSomething();
}
}
动态代理对象不需要实现接口,但是要求目标对象必须实现接口,否则不能使用动态代理。
3. Cglib代理
cglib可以代理没有实现接口的类
使用时需要引入jar包
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.5</version>
</dependency>
AdminCglibService.java
public class AdminCglibService {
public void doSomething(){
System.out.println("do something!");
}
public Object returnSomething(){
System.out.println("return something!");
return new Object();
}
}
AdminServiceCglibProxy.java
public class AdminServiceCglibProxy implements MethodInterceptor {
private Object target;
public AdminServiceCglibProxy(Object target){
this.target = target;
}
public Object getProxyInstance(){
Enhancer en = new Enhancer();
en.setSuperclass(target.getClass());
en.setCallback(this);
return en.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("before");
Object obj = method.invoke(target);
System.out.println("after");
return obj;
}
}
CglibProxyTest.java
public class CglibProxyTest {
public static void main(String[] args) {
AdminCglibService target = new AdminCglibService();
AdminServiceCglibProxy proxyFactory = new AdminServiceCglibProxy(target);
AdminCglibService proxy = (AdminCglibService) proxyFactory.getProxyInstance();
Object obj = proxy.returnSomething();
proxy.doSomething();
}
}
对比
- 静态代理实现比较简单,只需要对对象进行封装,即可实现功能,但是静态代理只能代理一个目标对象,当目标对象过多时,需要重复编写许多代理类。
- 动态代理需要目标对象实现业务接口,代理类只需实现InvocationHandler接口。
- 静态代理在编译时就产生class字节码文件,效率较高
- 动态代理必须实现InvocationHandler接口,通过反射代理方法,比较消耗系统性能,但可以减少代理类的数量,使用更灵活
- cglib代理无需实现接口,通过生成类字节码实现代理,比反射稍快,不存在性能问题,但cglib会继承目标对象,需要重写方法,所以目标对象不能为final类
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)