wordpress 手风琴插件,长沙网站优化联系方式,建设个人网站详细点,网站 模板下载代理模式
● 为对象提供一个代理类#xff0c;增强该对象的方法#xff0c;控制对这个对象的访问 ● 静态代理和动态代理#xff1a;静态代理就是编译的时候就已经确定#xff0c;而动态代理就是运行时才会生成
静态代理的使用场景
缓存代理
● 提供数据的缓存功能增强该对象的方法控制对这个对象的访问 ● 静态代理和动态代理静态代理就是编译的时候就已经确定而动态代理就是运行时才会生成
静态代理的使用场景
缓存代理
● 提供数据的缓存功能避免数据库重复查询
实践
定义数据查询的接口
public interface DataQuery {String query(String key);
}接口实现类实现接口
package com.hillky.desgin_learn.Proxy;public class DataBaseQuery implements DataQuery{Overridepublic String query(String key) {return DataBaseQuerykey;}
}创建缓存代理类实现接口内部使用缓存Map成员是被代理类
package com.hillky.desgin_learn.Proxy.cacheProxy;import lombok.NoArgsConstructor;import java.util.HashMap;public class CachingDataQueryProxy implements DataQuery{private DataQuery dataQuery;private static HashMapString,String cachenew HashMap();public CachingDataQueryProxy(DataBaseQuery dataBaseQuery) {this.dataQuery dataBaseQuery;}public CachingDataQueryProxy() {this.dataQuerynew DataBaseQuery();}Overridepublic String query(String key) {String result cache.get(key);if(result ! null){System.out.println(从缓存中取数据);return result;}result dataQuery.query(key);System.out.println(从数据库取数据);cache.put(key,result);return result;}
}建立测试类测试效果
安全代理
● 安全代理可以实现访问控制、权限验证等安全相关功能。
实践
定义一个数据查询接口
package com.hillky.desgin_learn.Proxy.safeProxy;public interface SensitiveDataQuery {String queryData(String userId);
}实现真实敏感数据查询实现
package com.hillky.desgin_learn.Proxy.safeProxy;public class SensitiveDataQueryImpl implements SensitiveDataQuery{Overridepublic String queryData(String userId) {return SensitiveDataQuery form user :userId;}
}安全代理类内部进行验证
package com.hillky.desgin_learn.Proxy.safeProxy;import lombok.Data;Data
public class SecurityProxy implements SensitiveDataQuery{private SensitiveDataQuery sensitiveDataQuery;private UserAuthenticator userAuthenticator;public SecurityProxy() {this.sensitiveDataQuerynew SensitiveDataQueryImpl();}Overridepublic String queryData(String userId) {if (userAuthenticator.hasPermission(userId)) {return sensitiveDataQuery.queryData(userId);} else {return Access Denied: Insufficient permission for user userId;}}
}UserAuthenticator 类来模拟用户权限验证
package com.hillky.desgin_learn.Proxy.safeProxy;import java.util.Arrays;
import java.util.List;public class UserAuthenticator {private final ListString authorizedUserIds;public UserAuthenticator() {// 模拟从数据库或配置文件中获取已授权的用户列表authorizedUserIds Arrays.asList(user1, user2, user3);}public boolean hasPermission(String userId) {return authorizedUserIds.contains(userId);}
}测试代码编写
虚拟代理
● 用于需要延迟创建耗时或资源密集型对象 ● 虚拟代理在初始时访问才创建实际对象之后将直接使用该对象
实践
定义一个图片接口
package com.hillky.desgin_learn.Proxy.vitruralProxy;public interface Image {void display();
}实现一个大型图片类
package com.hillky.desgin_learn.Proxy.vitruralProxy;public class LargeImage implements Image{private String imageUrl;public LargeImage(String imageUrl) {this.imageUrl imageUrl;}Overridepublic void display() {System.out.println(Displaying image: imageUrl);}
}虚拟代理类
package com.hillky.desgin_learn.Proxy.vitruralProxy;public class VirtualImageProxy implements Image{private String imageUrl;private LargeImage largeImage;public VirtualImageProxy(String imageUrl) {this.imageUrl imageUrl;}Overridepublic void display() {if(largeImagenull){largeImagenew LargeImage(imageUrl);}largeImage.display();}
}测试
可以看到虚拟代理如何实现懒加载以减少资源消耗和提高程序性能。
远程代理
● 为本地对象提供与远程对象相同的接口使得客户端可以透明地访问远程对象。需要做序列化反序列化网络通信不同语言的调用
实践
定义一个服务接口
package com.hillky.desgin_learn.Proxy.remoteProxy;public interface RemoteService {String fetchData(String dataId);
}实现一个远程服务类
package com.hillky.desgin_learn.Proxy.remoteProxy;public class RemoteServiceImpl implements RemoteService{Overridepublic String fetchData(String dataId) {return Data from remote service: dataId;}
}创建一个远程代理类它实现了 RemoteService 接口并在内部处理网络通信等细节
package com.hillky.desgin_learn.Proxy.remoteProxy;public class RemoteServiceProxy implements RemoteService{private String remoteServiceUrl;private RemoteService remoteService;public RemoteServiceProxy(String remoteServiceUrl) {this.remoteServiceUrl remoteServiceUrl;this.remoteServicenew RemoteServiceImpl();}Overridepublic String fetchData(String dataId) {// 网络通信、序列化和反序列化等逻辑System.out.println(Connecting to remote service at: remoteServiceUrl);// 假设我们已经获取到远程服务的数据String result remoteService.fetchData(dataId);System.out.println(Received data from remote service.);return result;}
}测试
请注意为了简化代码这里省略了实际的网 络通信、序列化和反序列化逻辑。
动态代理
● 静态代理需要手动编写代理类代理类与被代理类实现相同的接口对被代理对象进行包装。在程序运行前代理类的代码就已经生成并在程序运 行时调用。静态代理的优点是简单易懂缺点是需要手动编写代理类代码复杂度较 高且不易扩展。 ● 动态代理是在程序运行时动态生成代理类无需手动编写代理类大大降低了代码的 复杂度。通过反射实现
基于 JDK 的动态代理实现步骤
定义一个接口声明需要代理的方法
package com.hillky.desgin_learn.Proxy.remoteProxy;public interface RemoteService {String fetchData(String dataId);
}创建一个被代理类实现这个接口并在其中定义实现方法
package com.hillky.desgin_learn.Proxy.remoteProxy;public class RemoteServiceImpl implements RemoteService{Overridepublic String fetchData(String dataId) {return Data from remote service: dataId;}
}创建一个代理类实现 InvocationHandler 接口并在其中定义一个被代理类的对象作为属性。
package com.hillky.desgin_learn.Proxy.jdkProxy;import javafx.beans.InvalidationListener;
import javafx.beans.Observable;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.LinkedHashMap;public class CacheInvocationHandler implements InvocationHandler {private DataQuery dataQuery;private HashMapString,String cache new LinkedHashMap(256);public CacheInvocationHandler(DataQuery databaseDataQuery) {this.dataQuery databaseDataQuery;}public CacheInvocationHandler() {this.dataQuerynew DataBaseQuery();}Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {String resultnull;if(method.getName().equals(query)){result cache.get(args[0].toString());if(result!null){System.out.println(数据从缓存重获取。);return result;}result (String) method.invoke(dataQuery, args);cache.put(args[0].toString(),result);return result;}// 当其他的方法被调用不希望被干预直接调用原生的方法return method.invoke(dataQuery,args);}
}测试代码符合要求只有query方法加了缓存
package com.hillky.desgin_learn.Proxy.jdkProxy;import org.junit.jupiter.api.Test;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;import static org.junit.jupiter.api.Assertions.*;class CacheInvocationHandlerTest {Testvoid test() {// jdk提供的代理实现主要是使用Proxy类来完成// 1、classLoader被代理类的类加载器ClassLoader classLoader Thread.currentThread().getContextClassLoader();// 2、代理类需要实现的接口数组Class[] interfaces new Class[]{DataQuery.class};// 3、InvocationHandlerInvocationHandler invocationHandler new CacheInvocationHandler();DataQuery dataQuery (DataQuery) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);// 事实上调用query方法的使用他是调用了invokeString result dataQuery.query(key1);System.out.println(result);System.out.println(--------------------);result dataQuery.query(key1);System.out.println(result);System.out.println(--------------------);result dataQuery.query(key2);System.out.println(result);System.out.println();// 事实上调用queryAll方法的使用他是调用了invokeresult dataQuery.queryAll(key1);System.out.println(result);System.out.println(--------------------);result dataQuery.queryAll(key1);System.out.println(result);System.out.println(--------------------);result dataQuery.queryAll(key2);System.out.println(result);System.out.println(--------------------);}
}spring中aop的使用步骤
● 在 Spring 中AOP面向切面编程提供了一种有效的方式来对程序中的多个模块进行横切关注点的处理例如日志、事务、缓存、安全等。从而实现对目标对象的增强
引入 AOP 相关依赖
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-aop/artifactId
/dependency开启自动代理
EnableAspectJAutoProxy
SpringBootApplication
EnableAspectJAutoProxy
public class DesginLearnApplication {public static void main(String[] args) {SpringApplication.run(DesginLearnApplication.class, args);}}定义接口和实现类并将具体实现注入容器
package com.hillky.desgin_learn.Proxy.aop;public interface DataQuery {String query(String queryKey);
}
package com.hillky.desgin_learn.Proxy.aop;import org.springframework.stereotype.Component;Component
public class DataBaseQuery implements DataQuery{Overridepublic String query(String queryKey) {System.out.println(正在从数据库查询数据);return result;}
}
定义切面类对方法做增强
package com.hillky.desgin_learn.Proxy.aop;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;Component
Aspect
public class CacheAspectj {//定义切面Pointcut(execution(* com.hillky.desgin_learn.Proxy.aop.DataQuery.query(..)))public void pointcut(){}Around(pointcut())public String around(ProceedingJoinPoint joinPoint){Object[] args joinPoint.getArgs();String key args[0].toString();// 1、查询缓存命中则返回String result Cache.get(key);if(result ! null){System.out.println(数据从缓存中获取);return result;}// 未命中则去数据库查询实际上是调用被代理bean的方法try {result joinPoint.proceed().toString();// 如果查询有结果进行缓存Cache.put(key,result);} catch (Throwable e) {throw new RuntimeException(e);}return result;}}定义缓存
package com.hillky.desgin_learn.Proxy.aop;import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;public class Cache {private static MapString,String map new ConcurrentHashMap(256);public static String get(String key){return map.get(key);}public static void put(String key,String value){map.put(key, value);}
}测试
package com.hillky.desgin_learn.Proxy.aop;import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;import javax.annotation.Resource;import static org.junit.jupiter.api.Assertions.*;
SpringBootTest
class CacheAspectjTest {Resourceprivate DataQuery dataQuery;Testvoid test(){dataQuery.query(key1);dataQuery.query(key1);dataQuery.query(key2);}}代理和 AOP 是两个相关的概念代理是 AOP 的一种实现方式它们都可以 用于在程序中实现对目标对象的增强。区别在于代理主要是针对单个对象的方法调 用进行增强而 AOP 则是针对程序中多个模块的横切关注点进行增强。
动态代理的应用场景
动态代理是一种代理模式它在运行时动态生成代理对象而无需提前创建具体的代理类。 使用场景 ● 日志记录 ● 性能监控 ● 事务管理 ● 权限验证 ● 缓存 ● aop ● 速率限制
一般都可以用aop方便实现
日志记录
引入 AOP 相关依赖
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-aop/artifactId
/dependency开启自动代理
EnableAspectJAutoProxy
SpringBootApplication
EnableAspectJAutoProxy
public class DesginLearnApplication {public static void main(String[] args) {SpringApplication.run(DesginLearnApplication.class, args);}}创建一个切面类Aspect来实现日志记录的逻辑
package com.hillky.desgin_learn.Proxy.aop;public interface DataQuery {String query(String queryKey);
}定义切面类对方法做增强
package com.hillky.desgin_learn.Proxy.log;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;Aspect
Component
public class LoggingAspect {private final Logger logger LoggerFactory.getLogger(this.getClass());//定义切面Pointcut(within(org.springframework.web.bind.annotation.RestController *))public void restControllerMethods() {}Before(restControllerMethods())public void logMethodCall(JoinPoint joinPoint){String className joinPoint.getSignature().getDeclaringTypeName();String methodName joinPoint.getSignature().getName();logger.info(Entering method [{}.{}], className, methodName);}AfterReturning(pointcut restControllerMethods(), returning result)public void logMethodReturn(JoinPoint joinPoint, Object result) {String className joinPoint.getSignature().getDeclaringTypeName();String methodName joinPoint.getSignature().getName();logger.info(Exiting method [{}.{}], return value: {}, className,methodName, result);}
}
测试接口访问看控制台输出
package com.hillky.desgin_learn.Proxy.log;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;RestController
public class SampleController {GetMapping(/hello)public String hello() {return Hello, World!;}
}测试
package com.hillky.desgin_learn.Proxy.aop;import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;import javax.annotation.Resource;import static org.junit.jupiter.api.Assertions.*;
SpringBootTest
class CacheAspectjTest {Resourceprivate DataQuery dataQuery;Testvoid test(){dataQuery.query(key1);dataQuery.query(key1);dataQuery.query(key2);}}