jdk动态代理实现
前言
本人逻辑基于代码展开,阅读前还望view code
原理
jdk
代理基于接口实现,所以不可直接代理实现类,如果测试会发现形如..$proxy?...
报出classCastException
- 核心方法(
args
中的ClassLoader
类加载器,Class<?>[] interfaces
接口方法,InvocationHandler
实例),此方法应证jdk proxy
基于interface
实现(调用时不要将接口.class传入)
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
- 显然代理会针对一种行为,所以基于接口代理是存在其合理性,不过
cglib
的可操作性更强,无需接口 - 实际生成实现对应接口的新类,
jvm
层面的 - 演示代码的结构是工厂类
MyDynamicFactory
,接口MyInterface
,接口实现类MyProxy
思考
- 存在不少示例,是将工厂类内部设置了
target
,并且抽象了MyInvocationHandler
然后调用时重写属性,个人认为一般代理增强的代码业务通用,非entity
,所以想法是对要代理的类加入限制<T extends InvocationHandler>
这样减少类数量,减少耦合.,其次将增强逻辑至于同一类 - 如果将代理增强逻辑独立实现,显然工厂类中需要关于不同类型的
MyIncocationHandler
的集合,加上后续存类实例的hashMap
,安全性降低,并且复杂性提高,有可能需要concurrentHashMap
实现 - 工厂内部代理集合我采用
hashMap<K,V>
,其中K
类型String
,想必大家也能想到是全类名,V
采用实体类的对象,但是这样会引发调用时无关的创建对象问题,所以实现类采用单例 hashMap
线程不安全,主要是操作不原子,所以对工厂的put(String clzName
加锁,对外不暴露hashMap
的operation
- 单例里有个逻辑是防止反射破坏的(反射调用
constructor
,加个static boolean
标志查重)
代码
工厂类
@Slf4j
package com.pg.backend.designPattern.structuralPattern.proxyPattern.dynamicProxyPattern.main;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
/**
* JDK 代理基于接口,本实例
* @author paul 2024/3/6
*/
@Slf4j
public class MyDynamicProxyFactory {
//考虑到的想法是 ,基于 Enum ,但是考虑到类数量,基于hashMap<K,V> 全类名存储
private final HashMap<String,Object> proxiedObjs = new HashMap<>();
public Object getProxy( Object o) {
return Proxy.newProxyInstance(o.getClass().getClassLoader(), o.getClass().getInterfaces(), (InvocationHandler) o);
}
public Object getProxy(String clzName) {
if (clzName == null || clzName.isEmpty()) {
log.info("paramsError");
return null;
}
Object o = this.get(clzName);
return Proxy.newProxyInstance(o.getClass().getClassLoader(), o.getClass().getInterfaces(), (InvocationHandler) o);
}
@SneakyThrows
public synchronized <T extends InvocationHandler> void put(T o) {
proxiedObjs.put(o.getClass().getName(),o);
}
private synchronized Object get(String name) {
return proxiedObjs.get(name);
}
}
接口
package com.pg.backend.designPattern.structuralPattern.proxyPattern.dynamicProxyPattern.main;
/**
* @author paul 2024/3/6
*/
public interface MyInterface {
void test();
}
实现类
@Slf4j
package com.pg.backend.designPattern.structuralPattern.proxyPattern.dynamicProxyPattern.main;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @author paul 2024/3/6
*/
@Slf4j
public class MyProxy implements InvocationHandler,MyInterface {
private static volatile MyProxy myProxy;
private static boolean flag = false;
private MyProxy() {
if(flag) {
throw new RuntimeException("canNotCreateMoreInstance");
}
flag = true;
}
public static MyProxy getInstance() {
if(myProxy == null) {
synchronized (MyProxy.class) {
if(myProxy == null){
myProxy = new MyProxy();
}
}
}
return myProxy;
}
public void test(){
log.info("test...");
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log.info("beforeProxy");
return method.invoke(MyProxy.getInstance(),args);
}
}
框架
org.reflections 此框架处理非spring项目的aop或者动态增强很合适,比如类的收集,拥有注解的Field,在轮子项目里很合适
pom
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.10.2</version>
</dependency>
工具类
public class ReflectKit {
private Reflections reflections;
public ReflectKit(String packageAddress) {
// 配置类
ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
// 多组包扫描的分包
String[] addresses = packageAddress.split(",");
Stream.of(addresses).forEach(str -> configurationBuilder.addUrls(ClasspathHelper.forPackage(str.trim())));
// 加入Scanner扫描器,如果扫描注解字段,不加Scanners.FieldsAnnotated是不会扫描到的
configurationBuilder.setScanners(Scanners.FieldsAnnotated, Scanners.MethodsAnnotated,Scanners.TypesAnnotated);
reflections = new Reflections(configurationBuilder);
}
public <T extends Annotation> Set<Class<?>> getBeans(Class<T> anno) {
return reflections.getTypesAnnotatedWith(anno);
}
public <T extends Annotation> Set<Field> getFields(Class<T> anno) {
return reflections.getFieldsAnnotatedWith(anno);
}
}
总结
- 以上全部基于个人经验实现,若对您思维产生误导或者您认为错误,还请批评指正
- 若存在不错
java
后端项目实践,渴望得到青睐
联系方式
- Email: yydspg@outlook.com
- github: https://github.com/yydspg/