您的位置:首页 > 财经 > 产业 > 工程建设云_做软件页面设计的软件_站长工具 忘忧草_平台搭建

工程建设云_做软件页面设计的软件_站长工具 忘忧草_平台搭建

2024/10/5 19:21:12 来源:https://blog.csdn.net/weixin_44929475/article/details/142659277  浏览:    关键词:工程建设云_做软件页面设计的软件_站长工具 忘忧草_平台搭建
工程建设云_做软件页面设计的软件_站长工具 忘忧草_平台搭建

1. 简介

        代理模式(Proxy Pattern)是一种结构型设计模式,它能够为其他对象提供一个代理以控制对这个对象的访问。代理模式在不直接访问实际对象的情况下,提供了对目标对象的间接访问。通过引入一个代理对象来间接操作实际对象,可以在不改变实际对象代码的前提下,增加额外的功能操作,如访问控制、延迟初始化、日志记录、事务管理等。

代理模式通常分为几种类型:

  1. 静态代理:在代码编译时就已经确定代理类和目标类的关系。

  2. 动态代理:在代码运行时动态创建代理类。

    1. JDK动态代理:利用java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口在运行时创建代理对象。

    2. CGLIB动态代理:使用CGLIB库在运行时生成目标类的子类作为代理对象(实现MethodInterceptor接口)。

2. 静态代理

        静态代理是一种编译时就确定代理关系的方式。在静态代理中,代理类和目标类的关系是固定的,需要事先定义好。

实现步骤:

  1. 定义一个接口,目标对象和代理对象都实现这个接口。

  2. 创建目标对象的实现类。

  3. 创建代理类,实现相同的接口,并在内部持有目标对象的引用。

  4. 在代理类的方法中调用目标对象的方法,并在调用前后进行额外的操作。

示例代码:

package xiaokai.proxy.staticproxy;/*** Author:yang* Date:2024-09-30 13:58* Description:定义接口*/
public interface IStaticProxyService {String sayHello();
}package xiaokai.proxy.staticproxy;import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;/*** Author:yang* Date:2024-09-29 10:47* Description:基础方法实现类*/
@Service
@Slf4j
public class DefaultService implements IStaticProxyService{@Overridepublic String sayHello() {log.info("DefaultService sayHello");return "Hello ! ";}
}/*** Author:yang* Date:2024-09-29 11:00* Description:代理服务--->对实现功能进行增强*/
@Service
@Slf4j
public class ProxyService implements IStaticProxyService {@Autowiredprivate DefaultService defaultService;@Overridepublic String sayHello() {log.info("ProxyService sayHello");return defaultService.sayHello();}
}

测试:

@SpringBootTest(classes = ProxyApplication.class)
@RunWith(SpringRunner.class)
public class ProxyTest {@Autowiredprivate ProxyService proxyService;@Testpublic void testProxy() {proxyService.sayHello();}
}

结果:对基础方法进行了增强

 ProxyService sayHelloDefaultService sayHello

优点

  • 代理类和目标类的关系在编译时就已经确定,结构清晰。

缺点

  • 每一个目标类都需要一个代理类,如果有很多目标类,会导致代理类的数量大量增加,增加系统的复杂性。

3. 动态代理

        动态代理是在运行时创建代理对象的方式,不需要事先定义代理类。在Java中,动态代理通常是通过反射API实现的。

3.1 JDK

  1. 目标对象必须实现一个或多个接口。

  2. 创建一个实现了InvocationHandler接口的类。

  3. 使用Proxy.newProxyInstance方法在运行时动态创建代理对象。

示例代码:

package xiaokai.proxy.dynamicproxy.jdkservice;/*** Author:yang* Date:2024-09-29 11:16]* Description:问候服务接口*/
public interface IGreetingService {public String sayHello();
}package xiaokai.proxy.dynamicproxy.jdkservice;import lombok.extern.slf4j.Slf4j;/*** Author:yang* Date:2024-09-29 11:17* Description:*/
@Slf4j
public class GreetingService implements IGreetingService {@Overridepublic String sayHello() {log.info("sayHello");return "1";}
}package xiaokai.proxy.dynamicproxy.jdkservice;import lombok.extern.slf4j.Slf4j;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;/*** Author:yang* Date:2024-09-29 11:23*/
@Slf4j
public class JDKProxyService implements InvocationHandler {private Object target;public JDKProxyService(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {log.info("before invoke method: " + method.getName());Object result = method.invoke(target, args);log.info("after invoke method: " + method.getName());return result;}
}

测试:

package xiaokai.proxy.dynamicproxy;import xiaokai.proxy.dynamicproxy.jdkservice.GreetingService;
import xiaokai.proxy.dynamicproxy.jdkservice.IGreetingService;
import xiaokai.proxy.dynamicproxy.jdkservice.JDKProxyService;import java.lang.reflect.Proxy;/*** Author:yang* Date:2024-09-29 14:59*/
public class Main {public static void main(String[] args) {// 原始对象GreetingService original = new GreetingService();JDKProxyService proxyService = new JDKProxyService(original);// 创建代理对象IGreetingService instance = (IGreetingService) Proxy.newProxyInstance(original.getClass().getClassLoader(), original.getClass().getInterfaces(), proxyService);instance.sayHello();}
}

结果:

JDKProxyService - before invoke method: sayHello
GreetingService - sayHello
JDKProxyService - after invoke method: sayHello

优点

  • 可以在运行时动态创建代理对象,不需要为每个目标类编写代理类。

  • 目标类只需实现接口即可,代理类由JDK在运行时自动生成。

缺点

  • 只能代理实现了接口的类。

3.2 CGLIB

  1. 目标对象不需要实现接口,CGLIB通过生成目标对象的子类来实现代理。

  2. 创建一个实现了MethodInterceptor接口的类。

  3. 使用CGLIB的Enhancer类在运行时动态创建代理对象。

添加依赖:

<dependencies><dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.1</version></dependency>
</dependencies>

示例代码:

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/*** Author:yang* Date:2024-09-29 16:27*/
public class CglibHandler implements MethodInterceptor {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("before invoke");// 使用invokeSuper来调用父类方法Object result = methodProxy.invokeSuper(o, objects);System.out.println("after invoke");return result;}
}public class CglibService{public void sayHello() {System.out.println("hello, I am CglibService");}
}

测试:


public class Main {public static void main(String[] args) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(CglibService.class);enhancer.setCallback(new CglibHandler());CglibService instance = (CglibService) enhancer.create();instance.sayHello();}
}

结果:

before invoke
hello, I am CglibService
after invoke

优点

  • 可以代理没有实现接口的类。

  • 通过继承目标类实现代理,不需要目标类实现接口。

缺点

  • 代理对象的创建比JDK动态代理稍微复杂一些。

  • 需要引入第三方库CGLIB。

4. 应用场景

  1. 访问控制:在访问实际对象之前进行权限检查。

  2. 延迟初始化:在实际需要时才创建对象,提高系统性能。

  3. 日志记录:在调用目标对象方法前后记录日志信息。

  4. 事务管理:在方法调用前后添加事务处理逻辑。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com